日历获得年份返回错误的结果
我想创建一个日历对象,并将其设置为当年的某一年和一周。
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.Date
, Calendar
和SimpleDateFormat
等麻烦的旧式遗留日期时间类。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程。 并搜索堆栈溢出了很多例子和解释。 规范是JSR 310。
何处获取java.time类?