SimpleDateFormat Week Calculations

只愿长相守 提交于 2019-12-18 05:55:10

问题


I'm getting some puzzling results with SimpleDateFormat and am hoping that someone can shed some light on the issue. The output:

Time          = Mon Dec 27 00:00:00 PST 2010
2010-01 <--- THIS IS WHAT I DON'T UNDERSTAND
Start of week = Sun Dec 26 00:00:00 PST 2010
2010-01
End of Week   = Sat Jan 01 23:59:59 PST 2011
2011-01

Should I be treating the last "week" of the year that extends to the next year as a special case? Or is this the correct way to interpret this? Obviously when attempting to organize week sequentially, the order is incorrect. Adjusting the initial values, Dec 25, 2005 is considered the 53rd week. I haven't looked at Joda yet to see if Joda produces similar results.

The relevant code:

private static Date getStartOfWeek( Date d ) {
  Calendar calendar = Calendar.getInstance();
  calendar.clear();
  calendar.setTime( d );

  calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );

  return calendar.getTime();  
}

private static Date getEndOfWeek( Date d ) {
  Calendar calendar = Calendar.getInstance();
  calendar.clear();

  calendar.setTime( d );
  calendar.add( Calendar.WEEK_OF_YEAR, 1 );
  calendar.set( Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() );
  calendar.add( Calendar.MILLISECOND, -1 );

  return calendar.getTime();
}


Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set( 2010, Calendar.DECEMBER, 27 );
Date d = calendar.getTime();
Date start = getStartOfWeek( d );
Date end = getEndOfWeek( d );
SimpleDateFormat fmt = new SimpleDateFormat( "yyyy-ww" );

System.out.println( "Time          = " + d );
System.out.println( fmt.format( d ) );
System.out.println( "Start of week = " + start );
System.out.println( fmt.format( start ) );
System.out.println( "End of Week   = " + end );
System.out.println( fmt.format( end ) );

Background: I found this when using the crosstab (date grouped into week) in JasperReports.

EDIT: I am using JDK 1.6.0_25

EDIT: It seems that I will have to use Joda to get the correct result. TO get the week start/end, I ended up using: LocalDate.withDayOfWeek. To retrieve the year and week number, I used DateTime.getWeekyear and DateTime.getWeekOfWeekyear.


回答1:


The bug is in your formatting code, not Java.

The surprising behavior is due to an esoteric rule in date notation. Note that ISO 8601 (rather confusingly) specifies different rules for year boundaries when using week numbers. In particular, 2010-12-27 is considered part of 2011 when using week numbers.

As a result, you should be using the "week year" YYYY rather than the usual year yyyy. (See http://download.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html#week_year and the last example in http://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.)

Also, the standard notation for dates uses an explicit 'W', so you should use new SimpleDateFormat( "YYYY-'W'ww" ) instead.

Edit: There's another problem. Java seems to default to the non-standard calendar.getMinimalDaysInFirstWeek() == 1, so you have to set

calendar.setMinimalDaysInFirstWeek( 4 );

in order to get the correct year.

Edit: From reading the Calendar javadocs, you might also need to set the starting day to Monday. Further, the YYYY format specifier seems to be new in Java 1.7. In light of this, unless you're willing to upgrade to a pre-release Java version, I recommend just using Joda Time.




回答2:


From ISO Week

The first week of a year is the week that contains the first Thursday of the year.

So the behavior has nothing to do with Java or Joda. This is how the "week of the year" is implemented worldwide (if they follow the ISO standard)




回答3:


the standadr java Date & Time classes are not well designed and sometimes don't work as expected. use instead Joda Time




回答4:


Yes, this looks to be a bug in Java, and not in the formatting code. If you print:

System.out.println("Week = " + calendar.get(Calendar.WEEK_OF_YEAR));

It also shows 1.

If you change your date to something not so close to the end of the year, eg:

calendar.set(2010, Calendar.NOVEMBER, 27);

Then the output looks right. BTW, I tested using Sun 1.6.0_25 64bit VM.



来源:https://stackoverflow.com/questions/6754024/simpledateformat-week-calculations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!