日历获得年份返回错误的结果

我想创建一个日历对象,并将其设置为当年的某一年和一周。

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.WEEK_OF_YEAR, weekOfYear);  // 1
calendar.set(Calendar.YEAR, year); // 2016
setWeekChecked(calendar);

这是日历对象的toString,因为我将它传递给setWeekChecked方法:

java.util.GregorianCalendar中[时间= ?, areFieldsSet =假,宽大=真,区=美国/纽约,Firstdayofweek可= 1,minimalDaysInFirstWeek = 1,ERA = 1,YEAR = 2016,MONTH = 0,WEEK_OF_YEAR = 1,WEEK_OF_MONTH = 2,DAY_OF_MONTH = 7,DAY_OF_YEAR = 7,DAY_OF_WEEK = 5,DAY_OF_WEEK_IN_MONTH = 1,AM_PM = 0,HOUR = 5,HOUR_OF_DAY = 5,MINUTE = 25,SECOND = 43,微差= 219,ZONE_OFFSET = -18000000,DST_OFFSET = 0 ]

在setWeekChecked方法中:

public void setWeekChecked(final Calendar cal) {
    final int targetWeek = cal.get(Calendar.WEEK_OF_YEAR); // Returns 1
    final int targetYear = cal.get(Calendar.YEAR); // Returns 2015??
}

这是日历对象的toString现在:

java.util.GregorianCalendar中[时间= 1451557543219,areFieldsSet =真,宽大=真,区=美国/纽约,Firstdayofweek可= 1,minimalDaysInFirstWeek = 1,ERA = 1,YEAR = 2015,月= 11,WEEK_OF_YEAR = 1,WEEK_OF_MONTH = 5,DAY_OF_MONTH = 31,DAY_OF_YEAR = 365,DAY_OF_WEEK = 5,DAY_OF_WEEK_IN_MONTH = 5,AM_PM = 0,HOUR = 5,HOUR_OF_DAY = 5,MINUTE = 25,SECOND = 43,微差= 219,ZONE_OFFSET = -18000000,DST_OFFSET = 0 ]

我究竟做错了什么?


我怀疑日历在2016年第一周试图使用当前的星期几(今天是星期四)。

现在,查看日历设置,您将获得firstDayOfWeek = 1(周日到周六的运行周数)和minimalDaysInFirstWeek = 1(因此,今年的第一周是包含1月1日的第一周)。

这意味着2016年第一周的日历从2015年12月27日到2016年1月2日。因此,第一周的星期四是12月31日 - 这正是您向我们表示的日历。

基本上,“年份周”的日历算术很棘手,因为:

  • 有很多不同的文化特定的方式来看待它们
  • 通常,需求不会指定您实际感兴趣的人中的哪一个
  • 我强烈建议使用Joda时间,尽可能使日期/时间处理代码更加清晰,但是您仍然需要明确指出“将其设置为某年和一周的含义在那年”。 请注意,乔达时间将“周年”(用于星期几和星期几)的概念与“年份”(月份和月份中使用)的概念区分开来,这非常有帮助。 您需要注意的是,对于给定的日期,周年和年份可能会有所不同。


    TL;博士

    LocalDate.of( 2016 , Month.JULY , 1 ) 
             .with( IsoFields.WEEK_OF_WEEK_BASED_YEAR , 1 ) 
    

    细节

    Jon Skeet的答案是正确的。 更新:我们有更好的方法。

    内置于Java 8及更高版本中的java.time类取代了与最早版本的Java捆绑在一起的麻烦的旧式旧式日期 - 时间类。 并且java.time正式取代了Joda-Time,因为该项目现在处于维护模式。

    正如Skeet指出的那样,有不同的方法来定义每周的年份。

    java.time类为每年一次的标准ISO 8601定义提供支持。 这个定义是,第一周是周四的第一周,而那周是周一开始。 因此,本周的开始可能包括前一年的一天或更多天,最后一周可能包括来年的一天或更多天。 这一年总是有52周或53周。

    有关更多详细信息,请参阅我对类似问题的回答。

    LocalDate类表示没有时间和不带时区的仅限日期的值。

    获得所需年份中间附近的日期。 所需的年份是以周为单位的年份而不是历年,因此必须避免日历年的开始或结束。 就你而言,你希望以2016年为基础的周年。

    LocalDate ld = LocalDate.of( 2016 , Month.JULY , 1 ) ;
    

    接下来,我们使用IsoFields.WEEK_OF_WEEK_BASED_YEAR将该日期调整到所需的一周。

    LocalDate dayIn2016W01 = ld.with( IsoFields.WEEK_OF_WEEK_BASED_YEAR , 1 ) ;
    

    如果您想要那一周的第一天,请使用TemporalAdjusters类中的另一个TemporalAdjuster

    LocalDate firstDayOf2016W01 = dayIn2016W01.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) );
    

    提示:当Android变得更强大时,请使用ThreeTen-Extra项目中的YearWeek类。


    关于java.time

    java.time框架内置于Java 8及更高版本中。 这些类取代了诸如java.util.DateCalendarSimpleDateFormat等麻烦的旧式遗留日期时间类。

    现在处于维护模式的Joda-Time项目建议迁移到java.time类。

    要了解更多信息,请参阅Oracle教程。 并搜索堆栈溢出了很多例子和解释。 规范是JSR 310。

    何处获取java.time类?

  • Java SE 8Java SE 9和更高版本
  • 内置。
  • 带有捆绑实现的标准Java API的一部分。
  • Java 9增加了一些次要功能和修复。
  • Java SE 6Java SE 7
  • 大部分java.time功能都在ThreeTen-Backport中移植到Java 6和7。
  • Android的
  • ThreeTenABP项目专门针对Android采用了ThreeTen-Backport(上文提到)。
  • 请参阅如何使用ThreeTenABP ...。
  • 链接地址: http://www.djcxy.com/p/3093.html

    上一篇: Calendar get year returns wrong result

    下一篇: Make WCF DateTime Compatible for Java client