【问题标题】:Understanding java.util.Calendar WEEK_OF_YEAR [duplicate]了解 java.util.Calendar WEEK_OF_YEAR [重复]
【发布时间】:2012-06-05 07:41:11
【问题描述】:

我试图了解java.util.Calendar.get(java.util.Calendar.WEEK_OF_YEAR) 的工作原理,但似乎我遗漏了一些要点。

String time = "1998-12-31"; // year month day
java.util.Calendar date = java.util.Calendar.getInstance();
date.setTime((new java.text.SimpleDateFormat("yyyy-MM-dd")).parse(time));
System.err.println("Week of year = " + date.get(java.util.Calendar.WEEK_OF_YEAR));
// Week of year = 1 Why ???

为什么date.get(java.util.Calendar.WEEK_OF_YEAR) 在一年的最后一周返回 1?

此外,WEEK_OF_YEAR 对于 "1998-01-01" 是 1,对于 "1998-12-23" 它是 52。
有人对此行为有解释吗?

【问题讨论】:

  • 它为我打印Week of year = 53。只需检查您发布的代码,并且您得到的输出来自同一个地方。
  • 这将是特定于语言环境的。您是否仔细阅读了关于 WEEK_OF_YEAR 的手册并查看了 getFirstDayOfWeek 和 getMinimalDaysInFirstWeek 的值?
  • @adashr,检查,它打印 1。
  • @Corbin,“一周的第一天 = 1”和“第一周的最少天数 = 1”。但我仍然不明白这会如何影响一年中的最后一周成为 1。
  • 在某些国家(例如美国,根据维基百科),第一周是 1. 一月。 31. Dez '98 是星期四,所以它是在 1999 年的第一周

标签: java datetime calendar


【解决方案1】:

来自java.util.Calendar javadoc

第一周

日历使用两个 参数:一周的第一天和 first 中的最少天数 周(从 1 到 7)。这些数字取自语言环境资源 构建日历时的数据。它们也可以被指定 明确地通过设置它们的值的方法。

在设置或获取 WEEK_OF_MONTH 或 WEEK_OF_YEAR 字段时, 日历必须将月份或年份的第一周确定为 参照点。一个月或一年的第一周被定义为 从 getFirstDayOfWeek() 和 至少包含该月的 getMinimalDaysInFirstWeek() 天或 年。周数 ..., -1, 0 在第一周之前;周数 2, 3,... 跟着它。请注意,归一化编号返回 get() 可能不同。例如,一个特定的 Calendar 子类可能 将一年中第 1 周的前一周指定为前一周的第 n 周 年。

所以它是特定于语言环境的。在您的情况下,如果该周包含新年后的几天,则将其计为新年的第 1 周。

您可以使用Calendar#setMinimalDaysInFirstWeek(int) 更改此行为。

【讨论】:

  • 谢谢。不幸的是,使用setMinimalDaysInFirstWeek 在这里没有帮助(或者我不明白如何使用它)。如果我将它设置为`,那么我会得到上述行为。如果我将其设置为 7,则“1999-01-01”为 52。
  • 好吧,这周不能同时是 - 旧年的最后一周和新年的第一周。要么是一个,要么是另一个。
【解决方案2】:

tl;博士

java.time.LocalDate.parse( "1998-12-31" )
    .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )

53

或者,添加一个库,然后……

org.threeten.extra.YearWeek.from(     // Convert from a `LocalDate` object to a `YearWeek` object representing the entire week of that date’s week-based year.
    LocalDate.parse( "1998-12-31" )   // Parse string into a `LocalDate` objects. 
).getWeek()                           // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year.

53

详情

我正在尝试了解 java.util.Calendar.get(java.util.Calendar.WEEK_OF_YEAR) 的工作原理

不要!那门课一团糟,最好忘掉。

answer by npe 是正确的。在Calendar 中,一周的定义因地区而异。一个善意的功能,但令人困惑。

标准周定义

有很多方法可以定义“一周”和“一年中的第一周”。

但是,有one major standard definitionISO 8601 standard。该标准定义了weeks of the year,包括first week of the year

一年中第一个星期四的那一周

标准的一周从星期一开始,到星期日结束。

标准周年的第 1 周是日历年的第一个星期四。

java.time

java.time 类取代了麻烦的遗留日期时间类。这些现代类通过 IsoFields 类支持 ISO 8601 周,包含三个实现 TemporalField 的常量:

致电LocalDate::get 访问TemporalField

LocalDate ld = LocalDate.parse( "1998-12-31" ) ;
int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ;

ld.toString(): 1998-12-31

weekOfWeekBasedYear:53

yearOfWeekBasedYear: 1998

注意之后的第二天,即 1999 年新日历年的第一天,也是在同一周,即 1998 年的第 53 周。

LocalDate firstOf1999 = ld.plusDays( 1 );
int weekOfWeekBasedYear_FirstOf1999 = firstOf1999.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int yearOfWeekBasedYear_FirstOf1999 = firstOf1999.get( IsoFields.WEEK_BASED_YEAR ) ;

firstOf1999.toString(): 1999-01-01

weekOfWeekBasedYear_FirstOf1999: 53

yearOfWeekBasedYear_FirstOf1999: 1998

ISO 8601 字符串格式

ISO 8601 标准定义了文本格式以及基于周的年份值的含义:yyyy-Www。对于特定日期,为星期一至星期日添加编号为 1-7 的星期几:yyyy-Www-d

构造这样一个字符串。

String outputWeek = ld.format( DateTimeFormatter.ISO_WEEK_DATE ) ;  // yyyy-Www 

1998-W53

String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ;  // yyyy-Www-d

1998-W53-4

YearWeek

如果您将ThreeTen-Extra 库添加到您的项目中,这项工作会容易得多。然后使用YearWeek 类。

YearWeek yw = YearWeek.from( ld ) ;  // Determine ISO 8601 week of a `LocalDate`. 

生成标准字符串。

String output = yw.toString() ;

1998-W53

然后解析。

YearWeek yearWeek = YearWeek.parse( "1998-W53" ) ;  

yearWeek.toString(): 1998-W53

确定日期。传递 java.time.DayOfWeek 枚举对象用于周一至周日的星期几。

LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ;

localDate.toString(): 1998-12-28

我强烈建议将此库添加到您的项目中。然后你可以传递智能对象而不是愚蠢的整数。这样做可以使您的代码更具自我记录性,提供type-safety,并确保有效值。


关于java.time

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

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

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

使用符合JDBC 4.2 或更高版本的JDBC driver,您可以直接与您的数据库交换java.time 对象。不需要字符串也不需要 java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore


乔达时间

更新:Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。本节原封不动地保留为历史。

优秀的 Joda-Time 框架默认使用 ISO 8601。它的课程包括一年中这一周的信息。 Joda-Time 是与 Java 捆绑在一起的臭名昭著的麻烦 java.util.Date 和 java.util.Calendar 类的流行替代品。

示例代码

这里是一些示例代码,用于获取当前日期时间一年中第一周的第一天的第一时刻。

请注意拨打withTimeAtStartOfDay 以获得当天的第一时间。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );

DateTime now = new DateTime( timeZone );
DateTime firstWeekStart = now.withWeekOfWeekyear(1).withDayOfWeek(1).withTimeAtStartOfDay();
DateTime firstWeekStop = firstWeekStart.plusWeeks( 1 );
Interval firstWeek = new Interval( firstWeekStart, firstWeekStop );

转储到控制台...

System.out.println( "now: " + now );
System.out.println( "firstWeekStart: " + firstWeekStart );
System.out.println( "firstWeekStop: " + firstWeekStop );
System.out.println( "firstWeek: " + firstWeek );

运行时……

now: 2014-02-07T12:49:33.623+01:00
firstWeekStart: 2013-12-30T00:00:00.000+01:00
firstWeekStop: 2014-01-06T00:00:00.000+01:00
firstWeek: 2013-12-30T00:00:00.000+01:00/2014-01-06T00:00:00.000+01:00

【讨论】:

  • 也许用java.time更新这个?
  • @cricket_007 问,你就会收到。
猜你喜欢
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
  • 2018-08-19
  • 2017-11-19
相关资源
最近更新 更多