`

你可能不知道的 Calendar 之 DAY_OF_WEEK

阅读更多

 

1.背景:

百度知道上有人咨询了 Calendar 设置 Calendar.DAY_OF_WEEK不正确的问题 参见 http://zhidao.baidu.com/question/748936560786113052

他的入职时间是 "2006-02-14",要计算 20年后的所在周的周六

理论上, 2026-02-14所在周的周六,正好就是 2026-02-14

他写的代码是

public class Test {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date date=sdf.parse("2006-02-14");
        System.out.println(sdf.format(date));

        //********************************************************************
        Calendar c=Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, 20);
        c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        //********************************************************************

        System.out.println("入职20周年纪念日派对日期:"+sdf.format(c.getTime()));
    }
}

看上去没毛病,但是结果死活就是 2026-02-21

但是,在中间插入一行代码 System.out.println(c.get(Calendar.DAY_OF_WEEK));

public class Test {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date date=sdf.parse("2006-02-14");
        System.out.println(sdf.format(date));


        //********************************************************************
        Calendar c=Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, 20);
        System.out.println(c.get(Calendar.DAY_OF_WEEK));//有就正确,没有就错误:输出2026-02-21

        c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);  //正确日期2026-02-14
        //********************************************************************

        System.out.println("入职20周年纪念日派对日期:"+sdf.format(c.getTime()));
    }
}

结果就是正确的 2026-02-14

是不是很神奇?颠覆世界观,觉得不可思议?

2.原因

原因在于,当你设置 DAY_OF_WEEK 的时候, 你需要设置 WEEK_OF_MONTH 或者 DAY_OF_WEEK_IN_MONTH 或者 WEEK_OF_YEAR, 否则会使用老的WEEK_OF_MONTH 字段

When computing time (milliseconds), GregorianCalendar leaves some fields inconsistent. 
Then, after the last set(DAY_OF_WEEK), an invalid (older) WEEK_OF_MONTH value is used in the last getTime() call.

When you set DAY_OF_WEEK, the calendar expects a week field (WEEK_OF_MONTHDAY_OF_WEEK_IN_MONTH or WEEK_OF_YEAR) has also been set. 
So, avoid setting DAY_OF_WEEK without setting one of the week fields.

原先的这段代码

public class Test {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date date=sdf.parse("2006-02-14");
        System.out.println(sdf.format(date));

        //********************************************************************
        Calendar c=Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, 20);
        c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        //********************************************************************

        System.out.println("入职20周年纪念日派对日期:"+sdf.format(c.getTime()));
    }
}

由于只设置了 Calendar.DAY_OF_WEEK ,那么计算的时间结果是 20年后的第3周的周六 (因为没有设置WEEK_OF_MONTH,那么取的是老的"2006-02-14" 的WEEK_OF_MONTH )
而 "2006-02-14" 是所在月的第3周, 那么 20年后的第3周的周六 结果就是 2026-02-21 了

3. 为毛中间插入了一段 System.out.println(c.get(Calendar.DAY_OF_WEEK)); 结果就正确了呢?

我在问题里面也回答了,

  • 换成 System.out.println(c.get(Calendar.ERA)); 结果也会对
  • 换成 System.out.println("啦啦啦啦:" + sdf.format(c.getTime())); 结果也对 

原因在于,
调用这些方法的时候 ,Calendar 会调用 java.util.Calendar.complete() 方法, 
这个方法会依照已经设置的参数,把 Calendar 的 17 个字段(包括 WEEK_OF_MONTH ) 都重新计算一下 ,

此时, "2006-02-14" 20年后的日期是 2026-02-14 , 他的 WEEK_OF_MONTH 是当月的第二周, 都算完成了

4.最佳实践 (推荐指南)

真心不建议自己来写 Calendar SimpleDateFormat 来操作 ,坑比较多.

建议使用 apache commons-lang3 jar 或者 joda-time

示例: 对我来说就三步

public static void main(String[] args) throws ParseException{
    //1.转成date
    Date date = DateUtils.parseDate("2006-02-14", "yyyy-MM-dd");

    //2.20年后的日期
    Date d20 = DateUtils.addYears(date, 20);

    //3.20年后的日期所在周的 周六 ,
    Calendar calendar = DateUtils.toCalendar(d20);
    calendar.set(DAY_OF_WEEK, SATURDAY);
    System.out.println("入职20周年纪念日派对日期:" + DateFormatUtils.format(calendar.getTime(), "yyyy-MM-dd"));
}

你也可以使用 feilong-core jar

示例: 对我来说就三步

    public static void main(String[] args){
        //1.转成date
        Date date2 = DateUtil.toDate("2006-02-14", DatePattern.COMMON_DATE);

        //2.20年后的日期
        Date d20 = DateUtil.addYear(date2, 20);

        //3.20年后的日期所在周的 周六
        System.out.println("入职20周年纪念日派对日期:" + DateUtil.toString(getLastDateOfThisWeek(d20), DatePattern.COMMON_DATE));
    }

5.参考

分享到:
评论

相关推荐

    Calendar使用示例文件

    System.out.println("WEEK_OF_YEAR:" + calendar.get(Calendar.WEEK_OF_YEAR)); System.out.println("WEEK_OF_MONTH:" + calendar.get(Calendar.WEEK_OF_MONTH)); System.out.println("DATE:" + calendar.get...

    java技术点,常用的方法处理

    这里,`set(Calendar.DAY_OF_WEEK, ...)`将日期设置为本周的第一天,而`set(Calendar.WEEK_OF_YEAR, ...)`确保我们处在一年中的第一周。然后,`getTime()`返回的是一个`Date`对象,代表了这一周的开始日期。 此外,...

    java对日期的控制

    cal.add(Calendar.WEEK_OF_YEAR, -1); cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); cal.add(Calendar.DATE, weeks); return getNowTime("yyyy-MM-dd"); } ``` 这里先回溯一周,然后调整到星期一,再根据`...

    史上最全java时间类date的处理

    cal.add(Calendar.WEEK_OF_YEAR, -1); cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()); } public String getPreviousWeekSunday() { ...

    SYS_CALENDAR_DATE.sql

    `WEEK_OF_YEAR` int(10) NOT NULL COMMENT '获得指定日期是所在年份的第几周', `WEEK_OF_MONTH` int(10) NOT NULL COMMENT '获得指定日期是所在月份的第几周', `DAY_OF_MONTH` int(10) NOT NULL COMMENT '获得...

    java 获取时间 本周本年本月第一天最后一天

    c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek()); // 将当前日期设为星期一 System.out.println("本周第一天:" + c.getTime()); c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6); // 将当前日期设为...

    java时间处理工具类--CalendarUtil(java源码)

    int first_day_of_week = now.get(Calendar.DATE) + 2 - today; // 星期一 now.set(Calendar.DATE, first_day_of_week); return now.getTime(); } /** * 获得所在星期的最后一天 */ public static ...

    java API 在包java.util中有一个GregorianCalendar类,使用它可以得到一年内某个月的日历.zip

    ", 星期: " + calendar.get(Calendar.DAY_OF_WEEK)); } ``` 上述代码将打印出5月的每一天以及对应的星期。`Calendar.DAY_OF_WEEK`返回的是1到7的值,其中1代表周日,7代表周六。你可能需要将其转换为常见的星期...

    周日历选择插件jcalendar_week

    $(obj).addClass("calendar_day_act").siblings().removeClass("calendar_day_act"); } }); 点击上方显示当前年份和周的DOM部分可选择并跳转到指定年份和周。 插件提供的方法: //获取周第一天方法weekfirstdate...

    获取下周本周下周日期,获取今天所属第几周

    int startOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY; calendar.add(Calendar.DAY_OF_MONTH, -startOfWeek); Date startOfWeekDate = calendar.getTime(); calendar.add(Calendar.DAY_OF_...

    万年历的完整算法.doc

    该函数的输入变量为 gc_solar_calendar_year 和 gc_solar_calendar_month,输出变量为 start_day_of_week 和 temp_total_day。 在该函数中,首先对输入变量进行初始化,然后使用循环计算当前月份和年份的总天数 ...

    实现日历(控制台版)

    要得到某月的第一天是星期几,我们可以创建一个`Calendar`实例,设置到指定的月份和年份,然后调用`get(Calendar.DAY_OF_WEEK)`方法,其中返回值范围是1(表示星期日)到7(表示星期六)。 ```java Calendar ...

    android日历 calendar的使用

    `calendar.get(Calendar.MONTH)` 获取月份(注意,月份是从0开始的,1代表二月),`calendar.get(Calendar.DAY_OF_MONTH)` 获取月份中的第几天,`calendar.get(Calendar.DAY_OF_WEEK)` 获取一周中的第几天。...

    java日历各种写法

    calendar.add(Calendar.WEEK_OF_YEAR, -1); // 减1周 ``` 六、日期格式化 将`Calendar`对象转换为字符串通常需要`SimpleDateFormat`类: ```java SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:...

    Java-Date 类的学习总结.docx

    int weekno = cal.get(Calendar.WEEK_OF_YEAR); ``` 也可以计算一年中的第几星期是几号,例如: ```java SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); cal...

    calendar 日期推算

    calendar.add(Calendar.WEEK_OF_MONTH, 1); ``` 9. **实例分析**: 在`Calendar.txt`文件中,可能包含了一些实际的例子,展示了如何使用`Calendar`进行日期推算。例如,你可能会看到如何从当前日期开始,增加或...

    获取当前日期下周的日期

    例如,`cal.add(Calendar.DAY_OF_WEEK, (9-cal.get(Calendar.DAY_OF_WEEK))%7)`语句将当前日期增加到下周一周的第一天。 获取上一周一周的日期 要获取上一周一周的日期,需要使用`Calendar`类的`add`方法减少当前...

    java中Calendar类用法实例详解

    首先,Calendar 类提供了许多常量字段,例如 DATE、DAY_OF_MONTH、DAY_OF_WEEK、DAY_OF_YEAR、HOUR、HOUR_OF_DAY、MILLISECOND、MINUTE、SECOND、WEEK_OF_MONTH、WEEK_OF_YEAR、MONTH 等。这些常量字段可以用来获取...

    java时间操作函数汇总.pdf

    - 获取某一天是一年中的第几星期,可以使用 `Calendar.WEEK_OF_YEAR`: ```java Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 2006); cal.set(Calendar.MONTH, 9); // 9代表10月,因为月份...

    java时间处理工具类--DateUtils

    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); cal.add(Calendar.DAY_OF_MONTH, 6); return cal.getTime(); } /** * 获取指定时间范围的第一天 * * @param dateRangeType * 时间范围类型 * ...

Global site tag (gtag.js) - Google Analytics