这个问题已经在这里有一个答案:
- 为什么2010年12月31日收益为1年的周? 6个回答
我想了解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。
没有任何人有这种行为的解释?
从java.util.Calendar中的Javadoc :
第一周
一周的第一天,在第一周的最少天数(从1到7):日历使用两个参数定义了一个特定于区域的7天周。 这些数字是从语言环境资源数据采取当日历构造。 他们还可以通过设置自己的值的方法明确指定。
当设置或获取WEEK_OF_MONTH或WEEK_OF_YEAR字段日历必须确定一个月或一年的第一周作为参考点。 一个月或一年的第一周被定义为最早的七天内开始对getFirstDayOfWeek()和含有一个月或一年至少getMinimalDaysInFirstWeek()天。 周编号...,-1,0前面的第一周; 2号,3周...遵循它。 请注意,由get返回的标准化编号()可能会有所不同。 例如,一个特定的日历子类可以一周一年度为前一年的第n个星期的前1周指定。
因此,它是特定于语言环境。 在你的情况下,如果一周包含新一年的天,它是由新的一年算作1周。
您可以通过使用更改此行为日历#setMinimalDaysInFirstWeek(INT) 。
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)工程
别! 那类是一个血腥的混乱,并且最好留给遗忘。
在由NPE的答案是正确的。 在Calendar
,一周的定义中,语言环境而异。 一位好心的功能,但令人困惑。
标准定义一周
有很多方法来定义“一周”和“今年的第一周”。
然而,有一个主要的标准定义 :在ISO 8601标准 。 该标准定义了今年周 ,其中包括一年的第一周 。
与今年前周四的一周
一个标准的一周开始星期一和星期日结束。
一个基于标准的为期一周的年周#1具有日历年的第一个星期四。
java.time
该java.time类取代了旧的麻烦日期时间类。 这些现代化的类支持ISO 8601周至第的IsoFields
类,认为实施三个常量TemporalField
:
-
WEEK_OF_WEEK_BASED_YEAR
-
WEEK_BASED_YEAR
-
WEEK_BASED_YEARS
呼叫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
用于day-of-周周一至周日枚举对象。
LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ;
localDate.toString():1998年12月28日
我强烈建议加入这个库到您的项目。 然后,你可以绕过智能对象,而不是愚蠢的整数。 这样做可以使代码更自我记录,提供了类型安全 ,并确保有效的值。
关于java.time
该java.time框架是建立在Java 8和更高版本。 这些类取代麻烦的老传统日期时间类,如java.util.Date
, Calendar
,和SimpleDateFormat
。
该乔达-时间的项目,现在在维护模式 ,建议迁移到java.time类。
要了解更多信息,请参阅甲骨文教程 。 和搜索堆栈溢出了很多例子和解释。 规范是JSR 310 。
使用JDBC驱动程序与兼容JDBC 4.2或更高版本,您可以直接与数据库交换java.time对象。 无需字符串,也不是的java.sql。*类。
从哪里获取java.time类?
- 的Java SE 8 , Java SE的9 ,后来
- 内置。
- 具有捆绑实现标准Java API的一部分。
- Java的9增加了一些小的功能和修复。
- Java SE 6中和Java SE 7中
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植 。
- Android的
- 后来版本的java.time类的Android束实现的。
- 对于早期的Android,在ThreeTenABP项目适应ThreeTen -反向移植 (如上所述)。 请参阅如何使用ThreeTenABP ... 。
该ThreeTen-额外项目与其他类扩展java.time。 该项目是为将来可能增加的java.time试验场。 您可以在这里找到一些有用的类,比如Interval
, YearWeek
, YearQuarter
,和更多 。
乔达时间
工程进展: 乔达时间的项目现在处于维护模式 ,与团队的建议迁移java.time类。 原封不动作为历史这部分。
优秀的乔达时间框架使用ISO 8601的预设值。 其课程包括为期一周的年这一信息。 乔达时间是与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