了解java.util.Calendar WEEK_OF_YEAR

时间:2012-06-05 07:41:12

标签: java datetime calendar

我试图理解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的{​​{1}}为1,"1998-01-01"的{​​{1}}为52 有没有人对这种行为有解释?

2 个答案:

答案 0 :(得分:11)

来自java.util.Calendar javadoc

  

第一周

     

日历使用两个来定义特定于语言环境的七天工作周   参数:一周的第一天和第一天的最小天数   一周(从1到7)。这些数字取自语言环境资源   构建日历时的数据。它们也可能被指定   明确地通过设置其值的方法。

     

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

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

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

答案 1 :(得分:5)

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 enum对象,用于周一至周日的星期几。

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

localDate.toString():1998-12-28

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


关于 java.time

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

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore


约达时间

更新 Joda-Time项目现在位于maintenance mode,团队建议迁移到java.time课程。这部分原封不动。

优秀的Joda-Time框架使用ISO 8601作为默认值。它的课程包括这周的信息。 Joda-Time是臭名昭着的java.util.Date& amp;与Java捆绑在一起的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