JAVA 获取指定月份的每周的开始日期和结束日期

本文介绍了两种在Java中获取指定月份每周开始日期和结束日期的方法。第一种情况是从月首日至月末日,第二种情况是按固定周期,每周从周一至周日。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.第一种情况,从1号开始到月份最后一天结束

在这里插入图片描述
代码如下:


	private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
	
	public List<Map> getScope() {
        String date = "2022-06-01";
        String timeStrs[] = date.split("-");
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, Integer.parseInt(timeStrs[0]));
        c.set(Calendar.MONTH, Integer.parseInt(timeStrs[1]) - 1);
        c.setFirstDayOfWeek(Calendar.MONDAY);
        int weeks = c.getActualMaximum(Calendar.WEEK_OF_MONTH);

        LocalDate localDateate = LocalDate.parse(date, dateTimeFormatter);
        //月份第一周的起始时间和结束时间
        LocalDate firstDay = localDateate.with(TemporalAdjusters.firstDayOfMonth());
        String firstDayStr = firstDay.format(dateTimeFormatter);
        String sunStr = getSunOfWeek(firstDayStr);

        List<Map> weekInfos = new ArrayList<>();
        for (int i = 1; i <= weeks; i++) {
            Map weekInfo = new HashMap();
            //第一周的起始时间就是当月的1号,结束时间就是周日
            if (i == 1) {
                weekInfo.put("start",firstDayStr);
                weekInfo.put("end",sunStr);
                weekInfo.put("order",i);
                //计算接下来每周的周一和周日
            } else if (i < weeks) {
                //由于sunStr是上一周的周日,所以取周一要取sunStr的下一周的周一
                String monDay = getLastMonOfWeek(sunStr);
                sunStr = getSunOfWeek(monDay);
                weekInfo.put("start",monDay);
                weekInfo.put("end",sunStr);
                weekInfo.put("order",i);
                //由于最后一周可能结束时间不是周日,所以要单独处理
            } else {
                String monDay = getLastMonOfWeek(sunStr);
                //结束时间肯定就是当前月的最后一天
                LocalDate lastDay = localDateate.with(TemporalAdjusters.lastDayOfMonth());
                String endDay = lastDay.format(dateTimeFormatter);
                weekInfo.put("start",monDay);
                weekInfo.put("end",endDay);
                weekInfo.put("order",i);
            }

            weekInfos.add(weekInfo);

        }
        return weekInfos;
    }


    //算出所在周的周日
    public String getSunOfWeek(String time) {
        LocalDate localDateate = LocalDate.parse(time, dateTimeFormatter);
        LocalDate endday = localDateate.with(TemporalAdjusters.next(java.time.DayOfWeek.MONDAY)).minusDays(1);
        String endDayStr = endday.format(dateTimeFormatter);
        return endDayStr;
    }

    //下一周的周一
    public String getLastMonOfWeek(String time) {
        LocalDate localDateate = LocalDate.parse(time, dateTimeFormatter);
        LocalDate endday = localDateate.with(TemporalAdjusters.next(java.time.DayOfWeek.MONDAY));
        String endDayStr = endday.format(dateTimeFormatter);
        return endDayStr;
    }
    

运行结果:
在这里插入图片描述

2.第二种情况,每周固定从周一开始到周天结束

在这里插入图片描述
代码如下:

	private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

	public List<Map> getScope() {
        String date = "2022-06-01";
        String timeStrs[] = date.split("-");
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, Integer.parseInt(timeStrs[0]));
        c.set(Calendar.MONTH, Integer.parseInt(timeStrs[1]) - 1);
        c.setFirstDayOfWeek(Calendar.MONDAY);
        int weeks = c.getActualMaximum(Calendar.WEEK_OF_MONTH);

        LocalDate localDateate = LocalDate.parse(date, dateTimeFormatter);
        //月份第一周的起始时间和结束时间
        LocalDate firstDay = localDateate.with(java.time.DayOfWeek.MONDAY);
        String firstDayStr = firstDay.format(dateTimeFormatter);
        String sunStr = getSunOfWeek(firstDayStr);

        List<Map> weekInfos = new ArrayList<>();
        for (int i = 1; i <= weeks; i++) {
            Map weekInfo = new HashMap();
            //第一周的起始时间就是当月的1号,结束时间就是周日
            if (i == 1) {
                weekInfo.put("start",firstDayStr);
                weekInfo.put("end",sunStr);
                weekInfo.put("order",i);
                //计算接下来每周的周一和周日
            } else {
                //由于sunStr是上一周的周日,所以取周一要取sunStr的下一周的周一
                String monDay = getLastMonOfWeek(sunStr);
                sunStr = getSunOfWeek(monDay);
                weekInfo.put("start",monDay);
                weekInfo.put("end",sunStr);
                weekInfo.put("order",i);
            }
            weekInfos.add(weekInfo);

        }
        return weekInfos;
    }


    //算出所在周的周日
    public String getSunOfWeek(String time) {
        LocalDate localDateate = LocalDate.parse(time, dateTimeFormatter);
        LocalDate endday = localDateate.with(TemporalAdjusters.next(java.time.DayOfWeek.MONDAY)).minusDays(1);
        String endDayStr = endday.format(dateTimeFormatter);
        return endDayStr;
    }

    //下一周的周一
    public String getLastMonOfWeek(String time) {
        LocalDate localDateate = LocalDate.parse(time, dateTimeFormatter);
        LocalDate endday = localDateate.with(TemporalAdjusters.next(java.time.DayOfWeek.MONDAY));
        String endDayStr = endday.format(dateTimeFormatter);
        return endDayStr;
    }

运行结果:
在这里插入图片描述

<think>嗯,用户想根据日期范围、周几的重复频次开始时间生成Cron表达式。首先,我需要理解Cron表达式的结构。Cron有6或7个字段,分别是秒、分、时、日、月、周几,可能还有年。Java中的@Scheduled注解使用的是6位的格式,不包括年。 用户给出的参数是yyyy-MM-dd日期范围,也就是开始结束日期。但是Cron表达式通常处理周期性的任务,固定的日期范围可能需要更复杂的处理,比如在特定日期内重复。不过,标准的Cron可能不支持直接指定日期范围,可能需要结合多个条件。 然后是周几的重复频次,比如每周一、周三执行。这对应Cron中的星期字段,可以用数字1-7或者英文缩写,但Java的Cron通常用1-7,1是周日,2是周一,依此类推?或者可能不同,需要确认。比如用户想要每周周三执行,应该用“2,4”吗? HH:mm开始时间对应的是小时分钟字段,这部分比较直接,比如14:30就是3014。 接下来是日期范围的问题。假设用户希望任务在某个日期范围内执行,比如从2023-10-01到2023-12-31之间的每个周一周三的14:30执行。Cron表达式本身不支持年份,所以可能需要每年都执行,或者结合其他方法。但用户可能希望只在特定年份的日期范围内运行,这时候Cron可能不够,需要额外的逻辑判断。 或者,用户可能是指每个月的某几天,但日期范围可能跨越多个月。比如从10月到12月的每个周一周三。这时候月份字段设置为10-12,周几设置为2,4(如果周一是2的话),但需要注意日星期的冲突。Cron中的日星期字段是“或”的关系,即满足其中一个条件就会触发。所以如果同时指定了日星期,可能会触发多次,这可能不是用户想要的。 比如,用户可能希望从10月到12月的每个周一周三执行,那么月份设置为10-12,周几设置为2,4(假设),而日字段设为“?”表示不指定具体日期,由周几触发。这样组合起来可能正确。 所以,生成Cron的步骤可能是: 1. 解析开始时间的HH:mm,得到小时分钟。 2. 处理日期范围的月份部分,将开始结束日期月份提取出来,生成月份范围,如10-12。 3. 处理周几的频次,将周几转换为Cron的格式,例如周一周三转换为2,4(需要确认Java Cron的星期表示,因为有的系统可能周日是1,周一到周六是2-7)。 4. 日期范围中的日部分可能无法直接设置,因为Cron不支持日期区间内的每周几,所以可能需要忽略日字段,用周几来触发,同时月份设置为对应的范围。 例如,日期范围是2023-10-01到2023-12-31,每周周三的14:30,对应的Cron可能是: 0 30 14 ? 10-12 2,4 这里,秒是0,分是30,小时是14,日忽略(用?),月份是10-12,周几是周一周三。但需要确认Java中Cron的星期格式是否正确。在Spring的@Scheduled中,周几的1代表周日,2代表周一,依此类推,所以周一周三对应的是24。同时,当使用周几时,日字段应该设为?,以避免冲突。 如果日期范围跨年,比如从2023-11-15到2024-02-10,这时候月份字段可能需要分成两部分,比如11-121-2,但Cron不支持这样的分段,只能写成11,12,1,2,或者用不同的表达式。但Cron的月份字段不支持跨年的范围,所以可能需要多个触发器,或者用更复杂的逻辑,但用户可能希望在一个表达式中处理,这可能无法实现,需要分开处理。 不过用户的需求是生成基于给定参数的Cron表达式,可能只能处理单年份内的日期范围,或者忽略年份,因为Cron本身不处理年份。因此,在生成时,月份字段设为开始结束月份之间的范围,如果跨年的话,可能需要分多个表达式或者无法处理。 总结步骤: - 时间部分:直接转换HH:mm到小时分钟。 - 周几:转换为对应的数字,用逗号分隔。 - 日期范围中的月份:合并开始结束日期月份,生成月份范围,如10-12。 - 日期范围中的日:由于Cron无法处理动态日期范围,可能无法直接表达,只能忽略,依赖周几触发,所以日字段设为?,月份设为对应的范围。 例如,用户给出日期范围2023-10-05到2023-12-20,每周一、三、五,时间09:00: Cron表达式应为: 0 0 9 ? 10-12 2,4,6 这里假设周一到周五对应2,4,6,月份是10-12,日忽略。 但需要验证是否正确。另外,如果日期范围包括不同的年份,比如2023-11-01到2024-01-31,月份需要写成11,12,1,但由于Cron无法跨年处理,可能无法正确触发,需要用户自行处理年份部分,或者分多个表达式。 另外,日期范围的开始结束日期中的日可能不在同一个月,但Cron的月份字段是按月处理的,无法指定具体的日期区间,如10月5日到12月20日,只能设置月份为10-12,而无法限制到具体的日。这时候,如果用户需要精确到日期范围,比如10月5日到12月20日之间的每个周一,那么Cron无法单独处理,需要结合其他条件,比如在任务执行时检查日期是否在范围内,或者使用更复杂的调度框架。 因此,在生成Cron表达式时,可能只能处理月份范围,而无法处理具体的日范围。如果用户确实需要精确的日期范围,可能需要额外的逻辑在任务执行时判断当前日期是否在范围内,如果不在则跳过执行。 所以,最终的Cron表达式生成逻辑为: 1. 解析开始时间HH:mm -> 分钟小时。 2. 解析日期范围,获取开始结束月份,生成月份字段,如开始月份为10,结束为12,则月份为10-12。 3. 解析周几的重复频次,转换为对应的Cron星期表达式,如周一、周三、周五转换为2,4,6。 4. 日字段设为?,因为由周几触发。 5. 秒设为0,如果需要的话。 因此,生成的Cron表达式结构为:秒 分 时 ? 月份范围 周几 同时,需要提醒用户,这种方法无法处理跨年的月份范围,且无法限制到具体的开始结束日期(如10月5日到12月20日中的日期),只能处理整个月份范围。如果用户需要更精确的控制,需要在任务执行时添加日期判断逻辑。 例如,代码示例中,可以在任务执行时检查当前日期是否在用户指定日期范围内,如果不在,则跳过执行。例如: @Scheduled(cron = "0 30 14 ? 10-12 2,4") public void scheduledTask() { LocalDate currentDate = LocalDate.now(); LocalDate startDate = LocalDate.of(2023, 10, 1); LocalDate endDate = LocalDate.of(2023, 12, 31); if (currentDate.isBefore(startDate) || currentDate.isAfter(endDate)) { return; } // 执行任务逻辑 } 这样,Cron表达式负责处理月份周几,而具体的日期范围在任务内部判断。 因此,生成Cron的步骤需要结合月份范围周几,并在代码中添加日期范围的判断。</think>### 分步生成Cron表达式的方法 #### 一、Cron表达式结构 Java中的Cron表达式格式为:`秒 分 时 日 月 周几`(6个字段)。需特别注意: 1. **周几字段**:1表示周日,2表示周一,7表示周六(与常规习惯不同) 2. **日/周互斥**:若指定了`周几`,则`日`字段需设为`?`,否则可能触发意外行为[^1] #### 二、参数转换规则 1. **时间部分**(HH:mm) - 示例:`14:30` → `分=30`,`时=14` 2. **周几重复频次** - 示例:`周一,周三` → `周几=2,4` 3. **日期范围**(yyyy-MM-dd) - 月份范围:提取开始/结束日期月份,合并为连续区间 - 示例:`2023-10-05`至`2023-12-20` → `月=10-12` #### 三、生成公式 $$ \text{Cron} = 0 \quad [分] \quad [时] \quad ? \quad [月] \quad [周几] $$ #### 四、示例场景 **需求**:2023-10-01至2023-12-31期间,每周周三的14:30执行 **生成步骤**: 1. 时间部分:`分=30`,`时=14` 2. 月份范围:`10-12` 3. 周几转换:`周一=2`,`周三=4` 4. 最终表达式: ```java 0 30 14 ? 10-12 2,4 ``` #### 五、边界处理建议 1. **跨年日期范围**(如2023-11-15至2024-02-10) - 拆分表达式:`0 30 14 ? 11-12 2,4` `0 30 14 ? 1-2 2,4` 2. **精确日期控制**(如限定10月5日至12月20日) - 需在任务代码中添加日期判断: ```java @Scheduled(cron = "0 30 14 ? 10-12 2,4") public void task() { LocalDate now = LocalDate.now(); if (now.isBefore(LocalDate.of(2023,10,5)) || now.isAfter(LocalDate.of(2023,12,20))) { return; } // 业务逻辑 } ``` #### 六、工具方法示例 ```java public static String generateCron(LocalDate startDate, LocalDate endDate, List<DayOfWeek> days, LocalTime startTime) { // 1. 解析时间 int minute = startTime.getMinute(); int hour = startTime.getHour(); // 2. 计算月份范围 int startMonth = startDate.getMonthValue(); int endMonth = endDate.getMonthValue(); String monthRange = (startMonth == endMonth) ? String.valueOf(startMonth) : startMonth + "-" + endMonth; // 3. 转换周几(Java的DayOfWeek:1=周一,7=周日) String weekDays = days.stream() .map(d -> String.valueOf(d.getValue() + 1)) // 转换为Cron格式 .collect(Collectors.joining(",")); return String.format("0 %d %d ? %s %s", minute, hour, monthRange, weekDays); } ``` #### 七、验证工具 建议通过在线工具验证表达式: - [Cron Maker](https://www.freeformatter.com/cron-expression-generator-quartz.html) - [Spring Task Execution Check](https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值