Java 日期 不同月按周分组

日期按月、按周次分组

今天接到需求,要求按月份分开周次

12月31号和新一年的1月1号拆开两个组:[{‘2020-12 第五周 ’:['2020-12-28','2020-12-31']},{‘2021-01 第一周 ’:['2021-01-01','2021-01-03']}]

咋一看,这不搞事情嘛。。。

先把最基本的工具类的函数熟悉一下:

calendar.get(Calendar.WEEK_OF_MONTH) // 这个月在第几周
calendar.getActualMaximum(Calendar.DAY_OF_MONTH) //当月最大天数
calendar.get(Calendar.DAY_OF_WEEK) //周几 
calendar.setFirstDayOfWeek(Calendar.MONDAY); //设置周一为一周的开始

好像该有的函数都有了,那就开始撸了

噼里啪啦整了一顿之后,终于整出了一个初版,测试多次,暂无发现有逻辑BUG,如有望及时提出

测试按月分组一年的数据,耗时约16ms

暂时收工,源码奉上:

/**
     * 根据时间刻度 转化成对应的周
     * eg: 2021-01-01 - 2020-03-05
     *
     * @return {
     * "2021-01 第一周":['2021-01-01','2021-01-03']
     * "2021-01 第二周":['2021-01-04','2021-01-10']
     * ....
     * "2021-03 第一周":['2021-03-01','2021-03-05']
     * }
     */
    public static Map<String, Date[]> getWeekOfMonthStartAndEnd(String startDate, String endDate) throws ParseException {
        final int dayTimeOffset = 24 * 60 * 60 * 1000;
        final String formatKey = "%s 第%d周";
        checkNotEmpty(startDate, endDate);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat keyFormat = new SimpleDateFormat("yyyy-MM");
        Date _start = format.parse(startDate);
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(_start);
        if (startDate.equals(endDate)) {
            //同一天
            int idx = calendar.get(Calendar.WEEK_OF_MONTH);
            return Collections.singletonMap(String.format(formatKey, startDate.substring(0, 7), idx), new Date[]{_start, _start});
        }
        Date _end = format.parse(endDate);
        //日期偏移量 (日)
        long dayOffset = (_end.getTime() - _start.getTime()) / dayTimeOffset + 1;
        if (dayOffset < 0) {
            throw new IllegalArgumentException("结束时间必须大于开始时间");
        }
        // --------------------------------处理数据-------------------------------//
        long spanDay = 0; // 累加日期
        int last;
        Map<String, Date[]> result = new LinkedHashMap<>((int) (spanDay / 7) + 1);
        do {
            //result Key 值
            int idx = calendar.get(Calendar.WEEK_OF_MONTH); //当前在这个月的第几周
            String key = String.format(formatKey, keyFormat.format(calendar.getTime()), idx);
            // 0 星期天 1 周一 2 周二 3 周三 4 周四 5 周五 6 周六
            int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;// 周几
            int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); // 当前月最大的天数
            int days = calendar.get(Calendar.DAY_OF_MONTH);
            last = maxDays - days;
            //选择开头的一天
            Date date1 = calendar.getTime(); // value[0]
            if (week > 0) {
                //这周剩下的几天
                int i = 7 - week;
                //添加剩余的几天  30 31 / 01 ==> add 2 days
                if (i > last) {
                    calendar.add(Calendar.DAY_OF_MONTH, last);
                    result.put(key, new Date[]{date1, calendar.getTime()});
                    calendar.add(Calendar.DAY_OF_MONTH, 1); // 到达下一个月
                    spanDay = spanDay + last + 1;
                } else if (i + spanDay >= dayOffset) {
                    //最后一轮
                    result.put(key, new Date[]{date1, _end});
                    spanDay = dayOffset;
                } else {
                    //添加剩余一整周
                    calendar.add(Calendar.DAY_OF_MONTH, i);
                    result.put(key, new Date[]{date1, calendar.getTime()});
                    spanDay = spanDay + i + 1;
                    calendar.add(Calendar.DAY_OF_MONTH, 1); // 到达下一周周一
                }
            } else {
                result.put(key, new Date[]{date1, date1});
                calendar.add(Calendar.DAY_OF_MONTH, 1); // 到达下一周周一
                spanDay++;
            }
        } while (spanDay < dayOffset);
        return result;
    }

    private static void checkNotEmpty(String... args) {
        for (String arg : args) {
            if (StringUtils.isEmpty(arg)) {
                throw new IllegalArgumentException("argument is empty!");
            }
        }
    }

注意:SimpleDateFormat会涉及线程安全的问题,如果需要频繁调用的情景下,建议使用ThreadLocal对象

Java中计算给定日期是一年中的第几天,你可以按照以下步骤解题: 1. **获取当前年份和份数**: - 使用`java.time.LocalDate`类获取当前日期,然后提取出年份(`getYear()`)和份(`getMonthValue()`),因为份是从0开始计数的,所以需要加1。 2. **计算该有多少天**: - 获取当前年份的所有份(`ChronoField.MONTH_OF_YEAR`),遍历这个范围并累计每个的天数,直到达到给定的份。可以使用`java.time.MonthDay`类辅助计算。 3. **计算给定日期在当前内的位置**: - 如果输入的日期早于当前日期,说明在同一年的不同份,减去前几个的总天数即可。如果相等或晚于,直接算作当前份的天数。 4. **计算剩余的天数**: - 如果给定的日期是在下个,那么加上下个的第一天,再减去当天(`getOfMonth()`)。注意闰年的处理,2的天数可能会是28或29天。 5. **返回结果**: - 将所有部分相加得到最终结果。 ```java import java.time.LocalDate; import java.time.temporal.ChronoField; public int calculateDay(LocalDate date) { LocalDate currentDate = LocalDate.now(); int year = currentDate.getYear(); int month = currentDate.getMonthValue() + 1; // 加一,因为份从1开始 // 计算到给定份之前的所有的天数 int daysBeforeGivenMonth = 0; for (int i = 1; i < month; i++) { daysBeforeGivenMonth += LocalDate.of(year, i, 1).until(currentDate, ChronoUnit.MONTHS); } // 确定给定日期在当前的位置 if (date.isBefore(currentDate)) { // 同年不同的情况 return daysBeforeGivenMonth + date.getDayOfMonth(); } else { // 当或以后 LocalDate nextMonthFirstDay = date.with(TemporalAdjusters.nextMonth第一天()); return daysBeforeGivenMonth + date.getDayOfMonth() - nextMonthFirstDay.getDayOfMonth() + 1; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值