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

时间:2016-01-07 10:29:09

标签: java android calendar

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

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

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

  

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]

我做错了什么?

2 个答案:

答案 0 :(得分:8)

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

现在,查看你的日历设置,你得到firstDayOfWeek = 1(所以星期日到周六运行)和minimalDaysInFirstWeek = 1(所以一年的第一周是包含1月1日的那一周)。

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

从根本上说,日历算术与“一年中的一周”很棘手,因为:

  • 有很多不同的文化特定方式来看待它们
  • 通常,要求不会指定您真正感兴趣的那些

我强烈建议您使用Joda Time,以便尽可能让您的日期/时间处理代码更加清晰,但您仍然需要完全 你的意思是什么“将它设定为当年的某一年和一周”。请注意,Joda Time将“周 - 年”(用于周 - 周和星期几)的概念与“年”(用于月份和日期)分开,这有很大帮助。您需要注意,对于给定日期,周年和年份可能会有所不同。

答案 1 :(得分:0)

TL;博士

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

详细

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

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

正如Skeet所指出的,有不同的方式来定义一周的年份。

java.time类支持ISO 8601的标准week-of-year定义。这个定义是第1周是星期四的第一周,那个星期从星期一开始。因此,一周的开始可以包括前一年的一天或多天,并且最后一周可以包括来自下一年的一天或多天。这一年总是有52周或53周。

有关详细信息,请参阅my Answer类似问题。

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 ) ;

如果您想要该周的第一天,请使用TemporalAdjuster课程中的其他TemporalAdjusters

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

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

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?