说明

签到功能根据业务情况的不同大致分为两种,一种是只要进入系统就会默认签到,另外一种是进入系统之后需要用户手动点击签到按钮进行签到。两种情况最大的区别就是,自动签到连续签到天数肯定至少为1天。而手动签到的情况则需要考虑断签的情况。

自动签到下统计连续签到天数

public static void main(String[] args) {
        try {
            /**
             * 造一些测试数据,这里就不去数据库里查了,一般正常是数据库有个表记录签到记录
             */
            List<String> signInDateStrs = new ArrayList<>();
            signInDateStrs.add("2019-12-31");
            signInDateStrs.add("2020-01-01");
            signInDateStrs.add("2020-01-02");
            List<Date> signInDates = new ArrayList<>();
            for (String dateStr : signInDateStrs) {
                Calendar calendarTo = Calendar.getInstance();
                calendarTo.setTime(new SimpleDateFormat("yyyy-MM-dd").parse(dateStr));
                Calendar c = Calendar.getInstance();
                c.setTimeInMillis(0);
                c.set(calendarTo.get(Calendar.YEAR), calendarTo.get(Calendar.MONTH),
                        calendarTo.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
                signInDates.add(c.getTime());
            }

            int count = persistentDay(signInDates);
            System.out.println("连续签到了" + count + "天");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * 自动签到的情况,只要一进入系统就会签到,所以连续签到肯定至少为1天
     * @param signInDates
     * @return
     */
    private static int persistentDay(List<Date> signInDates){
        //定义一个变量表示连续签到天数,从1开始
        int continuousDays = 1;

        //1. 注意先对时间进行从小到大排序(可以在数据库里查的时候就根据时间排序,也可以查询出来之后再排序)

        /**
         * 2. 从最大的时间开始往前比较,因为我们是要拿连续签到的时间,这样才有意义,减少无谓的比较
         */
        Calendar later = Calendar.getInstance();
        Calendar before = Calendar.getInstance();
        for (int i = signInDates.size() - 1; i > 0; i--){
            later.setTime(signInDates.get(i));
            before.setTime(signInDates.get(i - 1));
            //前一天 + 1天 = 后一天,则视为连续签到
            before.add(Calendar.DAY_OF_MONTH,1);
            if (later.get(Calendar.YEAR) == before.get(Calendar.YEAR)
                    && later.get(Calendar.MONTH) == before.get(Calendar.MONTH)
                    && later.get(Calendar.DAY_OF_YEAR) == before.get(Calendar.DAY_OF_YEAR)){
                continuousDays++;
            }else {
                //只要遇到不连续的就不用再往前比较了
                break;
            }
        }
        return continuousDays;
    }

手动签到下统计连续签到天数

public static void main(String[] args) {
        /**
         * 造一些测试数据,为了简单演示就不去数据库查寻签到记录了
         * 注意时间要从小到大排序,如果从数据库里查询的时候,可以根据这个时间进行order by
         * 也可以查询出来再程序排序
         */
        List<String> signInDateStrs = new ArrayList<>();
        signInDateStrs.add("2019-12-31");
        signInDateStrs.add("2020-03-02");
        signInDateStrs.add("2020-03-03");
        List<Date> signInDates = new ArrayList<>();
        try {
            for (String dateStr : signInDateStrs) {
                Calendar calendarTo = Calendar.getInstance();
                calendarTo.setTime(new SimpleDateFormat("yyyy-MM-dd").parse(dateStr));
                Calendar c = Calendar.getInstance();
                c.setTimeInMillis(0);
                c.set(calendarTo.get(Calendar.YEAR), calendarTo.get(Calendar.MONTH),
                        calendarTo.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
                signInDates.add(c.getTime());
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }


        int count = persistentDay(signInDates);
        System.out.println("已连续签到 " + count + "天");
    }

    /**
     * 需要手动点击签到的情况
     * @param signInDates
     * @return
     */
    private static int persistentDay(List<Date> signInDates) {
        //定义一个变量表示连续签到天数,从1开始
        int continuousDays = 1;

        /**
         * 如果手动签到的话需要考虑
         * 把排序之后的签到记录时间中最大的那个时间拿出来与 昨天 进行比较,如果相等证明还是连续签到的,如果不等则连续签到变成0
         */
        Calendar yesterday = Calendar.getInstance();
        yesterday.setTime(new Date());
        yesterday.add(Calendar.DAY_OF_MONTH, -1);

        Calendar lastDay = Calendar.getInstance();
        lastDay.setTime(signInDates.get(signInDates.size() - 1));
        if (yesterday.get(Calendar.YEAR) != lastDay.get(Calendar.YEAR)
                || yesterday.get(Calendar.MONTH) != lastDay.get(Calendar.MONTH)
                || yesterday.get(Calendar.DAY_OF_YEAR) != lastDay.get(Calendar.DAY_OF_YEAR)) {
            //昨天没有签到
            continuousDays = 0;
            return continuousDays;
        }

        /**
         * 2. 从最大的时间开始往前比较,因为我们是要拿连续签到的时间,这样才有意义,减少无谓的比较
         */
        Calendar later = Calendar.getInstance();
        Calendar before = Calendar.getInstance();
        for (int i = signInDates.size() - 1; i > 0; i--) {
            later.setTime(signInDates.get(i));
            before.setTime(signInDates.get(i - 1));
            //前一天 + 1天 = 后一天,则视为连续签到
            before.add(Calendar.DAY_OF_MONTH, 1);
            if (later.get(Calendar.YEAR) == before.get(Calendar.YEAR)
                    && later.get(Calendar.MONTH) == before.get(Calendar.MONTH)
                    && later.get(Calendar.DAY_OF_YEAR) == before.get(Calendar.DAY_OF_YEAR)) {
                continuousDays++;
            } else {
                //只要遇到不连续的就不用再往前比较了
                break;
            }
        }
        return continuousDays;
    }