美文网首页
基于32位bit位操作,实现用户签到工具类

基于32位bit位操作,实现用户签到工具类

作者: 每天都是奥利给 | 来源:发表于2021-06-10 14:45 被阅读0次

    之前项目需要做用户签到,便查阅了相关资料,整理了一个工具类

    /**
     * 基于bit位运算 实现用户签到功能类
     */
    public class UserSginUtils {
    
        private static  final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        /**
         * 用户签到
         * @param sginTag 本月已签到标识 未签到则为0
         * @param monthOfDay 当前天 如 07-25 则传25
         * @return 返回新 签到标识 -> sginTag
         */
        public int doSgin(int sginTag, int monthOfDay){
            int offset = monthOfDay - 1; //偏移量从0开始 所以day-1
            int sgin_offset = 1 << offset; //日期从1号开始 所以从1开始左偏移offset位
            return sginTag + sgin_offset;
        }
    
        /**
         * 该月累计签到次数
         *  如 该月 1,2,3,6号用户签到了  则 sginTag = 39 则用户该月供签到4次
         * @param sginTag
         * @return
         */
        public int sginCount(int sginTag){
            return Integer.bitCount(sginTag);
        }
    
    
        /**
         * 该月首次签到日期
         * 向左取bit 第一位为1的偏移量
         * @param sginTag
         * @return
         */
        public int monthTopSginDate(int sginTag){
            int r = 1; //偏移量从0开始 所以+1
            if ((sginTag & 0xFFFF) == 0) {
                sginTag >>= 16;
                r += 16;
            }
            if ((sginTag & 0xFF) == 0) {
                sginTag >>= 8;
                r += 8;
            }
            if ((sginTag & 0x0F) == 0) {
                sginTag >>= 4;
                r += 4;
            }
            if ((sginTag & 0x03) == 0) {
                sginTag >>= 2;
                r += 2;
            }
            if ((sginTag & 0x01) == 0) {
                r += 1;
            }
            return r;
    
        }
    
        /**
         * 该月最后签到日期
         * 向右取第一个位1的偏移量
         * @param sginTag
         * @return
         */
        public int monthLastSginDate(int sginTag){
            int r = 0;
            if ((sginTag & 0xffff0000) != 0) {
                sginTag >>>= 16;
                r += 16;
            }
            if ((sginTag & 0xff00) != 0) {
                sginTag >>>= 8;
                r += 8;
            }
            if ((sginTag & 0xf0) != 0) {
                sginTag >>>= 4;
                r += 4;
            }
            if ((sginTag & 0x0c) != 0) {
                sginTag >>>= 2;
                r += 2;
            }
            if ((sginTag & 0x02) != 0) {
                sginTag >>>= 1;
                r += 1;
            }
            if ((sginTag & 0x01) != 0) {
                r += 1;
            }
            return r;
        }
    
        /**
         * 判断当天是否签到
         * @param sginTag 签到标识值
         * @param monthOfDay 天
         * @return
         */
        public boolean isSgin(int sginTag, int monthOfDay){
            int offset = monthOfDay - 1; //偏移量从0开始
            int daySgin = 1 << offset; //每月1号 bit偏移 offset 为monthday的bit位
            return (sginTag & daySgin) > 0;
        }
    
        /**
         * 当月连续签到的天数(按传入日期 往前推算)
         * @param sginTag       当月签到标识
         * @param checkDate     检查日期
         * @return
         */
        public int continuousNum(int sginTag, Date checkDate){
            int sginCount = 0; //签到次数
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(checkDate);
            int day = calendar.get(Calendar.DAY_OF_MONTH); //获取当前月份天数
    //        day = day - 1; //不考虑当天
            while (day > 0){
                if (isSgin(sginTag, day)){
                    sginCount++;
                }else { //只要有一次未签到 则退出循环
                    break;
                }
                day--;
            }
            return sginCount;
        }
    
        /**
         * 获取当月1号开始 连续签到次数
         * @param sginTag
         * @param year
         * @param month
         * @return
         */
        public int continuousFirstDay(int sginTag,int year, int month){
            int sginCount = 0;
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month-1);
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            //获取当月最大日期
            int maxDay = calendar.get(Calendar.DAY_OF_MONTH);
            for (int day = 1; day <= maxDay; day++){
                if (isSgin(sginTag, day)){
                    sginCount++;
                }else { //只要有一次未签到 则退出循环
                    break;
                }
            }
            return sginCount;
        }
    
        /**
         * 获取当月1号开始 连续签到次数
         * @param sginTag
         * @param year
         * @param month
         * @return
         */
        public List<String> continuousFirstDayOfDays(int sginTag,int year, int month){
            List<String> list = new ArrayList<>();
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month-1);
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            //获取当月最大日期
            int maxDay = calendar.get(Calendar.DAY_OF_MONTH);
            for (int day = 1; day <= maxDay; day++){
                if (isSgin(sginTag, day)){
                    calendar.set(Calendar.DAY_OF_MONTH, day);
                    list.add(format.format(calendar.getTime()));
                }else { //只要有一次未签到 则退出循环
                    break;
                }
            }
            return list;
        }
    
        /**
         * 获取当月(连续) 连续签到 指定次数的日期集合 如指定连续签到 contiousDay = 7 则 连续签到 7天或以后的所有日期会返回 否则返回空集合
         * @param sginTag
         * @param year
         * @param month
         * @return
         */
        public List<String> getContinousDays(int sginTag, int lastSginTag, int year, int month, int contiousDay){
            List<String> list = new ArrayList<>();
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month - 1);
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            //上月连续签到天数
            int lastSignCount = this.monthLastDateSginNum(lastSginTag, year, month);
            //获取当月最大日期
            int maxDay = calendar.get(Calendar.DAY_OF_MONTH);
            int sginCount = lastSignCount;
    
            for (int day = 1; day <= maxDay; day++){
                if (isSgin(sginTag, day)){
                    sginCount++;
                }else { //只要有一次未签到 则重置
                    sginCount = 0;
                }
                if (sginCount >= contiousDay){ //连续签到超过指定天数的 加入集合
                    calendar.set(Calendar.DAY_OF_MONTH, day);
                    list.add(format.format(calendar.getTime()));
                }
            }
            return list;
        }
    
        /**
         * 当月最后一天往前推 连续签到天数
         * @param sginTag
         * @param year
         * @param month
         * @return
         */
        public int monthLastDateSginNum(int sginTag, int year, int month){
            int sginCount = 0;
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month - 1);
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            while (day > 0){
                if (isSgin(sginTag, day)){
                    sginCount++;
                }else { //只要有一次未签到 则退出循环
                    break;
                }
                day--;
            }
            return sginCount;
        }
    
    
    
    
        /**
         * 获取用户签到视图数据
         * @param sginTag 签到标识
         * @param month   签到月份
         * @param year   签到年份
         * @return
         */
        public List<Map<String,Object>> sginMapDetails(int sginTag, int year, int month){
            List<Map<String,Object>> sginListMap = new ArrayList<>();
            //设置日期
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            month = month - 1; //日历类 月份从0开始
            calendar.set(Calendar.MONTH, month);
            //当月最大日期
            int maxMonthOfday = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
            int day = 1; //月份第一天
            String yearOfMonth = String.valueOf(year).concat("-".concat(month+1 < 10 ? "0".concat(String.valueOf(month+1)) : String.valueOf(month+1))); // yyyy-MM
            while (day <= maxMonthOfday){
                Map<String, Object> dateMap = new HashMap<>();
                dateMap.put("yearOfMonth", yearOfMonth);
                String monthOfDay = String.valueOf(day);
                if (day < 10){
                    monthOfDay = "0" + day;
                }
                String yearOfMonthDay = yearOfMonth
                        .concat("-")
                        .concat(monthOfDay);
                dateMap.put("yearOfMonthDay", yearOfMonthDay);
                dateMap.put("monthOfDay", monthOfDay);
                boolean isSgin = false;
                if (this.isSgin(sginTag, day)){
                    isSgin = true;
                }
                dateMap.put("isSgin", isSgin);
                sginListMap.add(dateMap);
                day ++;
            }
            return sginListMap;
        }
    
        /**
         * 测试
         * @param args
         */
    //    public static void main(String[] args) {
    //        UserSginUtils userSginUtils = new UserSginUtils();
    //        //签到
    //        //假设用户A 首次签到
    //        int sginTag = 0; //首次签到 签到标示值为0 该值存于数据库 或 redis缓存 key-val key:sgin:userId:yearMonthOfDay value:sginTag
    //        int monthOfDay = 1;// 签到日期
    //        int newSginTag = userSginUtils.doSgin(sginTag, monthOfDay);
    //        System.out.println("1. 用户1号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("2. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在2号签到
    //        monthOfDay = 2;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("3. 用户2号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("4. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在4号签到
    //        monthOfDay = 4;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("5. 用户4号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("6. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在4号签到
    //        monthOfDay = 5;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("5. 用户5号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("6. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在4号签到
    //        monthOfDay = 6;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("7. 用户6号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("8. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在4号签到
    //        monthOfDay = 7;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("9. 用户7号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("10. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //用户A 在4号签到
    //        monthOfDay = 8;
    //        newSginTag = userSginUtils.doSgin(newSginTag, monthOfDay);
    //        System.out.println("11. 用户8号签到,sginTag:"+newSginTag);
    //        //本月签到次数
    //        System.out.println("12. 用户本月签到:"+userSginUtils.sginCount(newSginTag)+"次");
    //        //判断用户是否在 5号签到
    //        System.out.println("13. 用户在5号签到了?结果:"+userSginUtils.isSgin(newSginTag, 5));
    //        //判断用户是否在 11号签到
    //        System.out.println("14. 用户在11号签到了?结果:"+userSginUtils.isSgin(newSginTag, 11));
    //        //检测连续签到
    //        //假设业务 连续签到7天有奖励
    //        // 用户A 准备在9号 准备签到 需要判断9号之前连续签到的情况 则:
    //        Calendar calendar = Calendar.getInstance();
    //        calendar.setTime(new Date());
    //        calendar.set(Calendar.DAY_OF_MONTH, 9);
    //        //4 5 6 7 8签到了 所以连续签到为 5
    //        System.out.println("15. 用户A在9号之前连续签到了:"+ userSginUtils.continuousNum(newSginTag, calendar.getTime())+"天");
    //        calendar.set(Calendar.DAY_OF_MONTH, 10);
    //        //9号未签到 所以10号之前连续签到为0
    //        System.out.println("16. 用户A在10号之前连续签到了:"+ userSginUtils.continuousNum(newSginTag, calendar.getTime())+"天");
    //        //本月签到视图
    //        System.out.println(userSginUtils.sginMapDetails(newSginTag, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH)+1));
    //    }
    
    }
    

    相关文章

      网友评论

          本文标题:基于32位bit位操作,实现用户签到工具类

          本文链接:https://www.haomeiwen.com/subject/tfnueltx.html