简而言之
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)的工作原理
不要这样做!那个类很混乱,最好忘记它。
npe的答案是正确的。在Calendar
中,一周的定义因语言环境而异。这是一个良好的意图,但令人困惑。
标准周定义
有许多方法来定义“一周”和“一年的第一周”。
然而,有一个主要的标准定义:ISO 8601标准。该标准定义了一年中的周数,包括一年的第一周。
一年中第一个星期四所在的那个星期
标准周从星期一开始,到星期日结束。
标准周年的第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() ;
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 及更高版本中。这些类取代了旧的遗留日期时间类,例如 java.util.Date
, Calendar
, 和 SimpleDateFormat
。
Joda-Time项目现在处于维护模式,建议迁移到java.time类。
欲了解更多信息,请参阅Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范为JSR 310。
使用符合JDBC 4.2或更高版本的JDBC驱动程序,您可以直接与数据库交换java.time对象。无需字符串或java.sql.*类。
如何获取java.time类?
ThreeTen-Extra项目通过增加类扩展了java.time。该项目是java.time可能未来添加的内容的试验场。您可能会在这里找到一些有用的类,例如Interval
, YearWeek
, YearQuarter
和更多。
Joda-Time
更新:Joda-Time 项目现已进入维护模式,团队建议迁移到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