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 definition:ISO 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.Date、Calendar 和 SimpleDateFormat。
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 的试验场。您可能会在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。
乔达时间
更新: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