为什么2010年12月31日将作为一年中的一周返回1?

时间:2011-01-05 19:43:20

标签: java calendar jodatime week-number

例如:

Calendar c = Calendar.getInstance();
DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
c.setTime( sdf.parse("31/12/2010"));
out.println( c.get( Calendar.WEEK_OF_YEAR ) );  

打印1

Joda时间也是如此。

:)

6 个答案:

答案 0 :(得分:52)

每周的定义为Locale依赖。

其他帖子中讨论了如何在美国定义它。例如在德国(DIN 1355-1 / ISO 8601):第一周*是新的一年中有4天或更多天的第一周。

*周的第一天是星期一,星期的最后一天是星期日

Java的Calendar关注区域设置。例如:

public static void main(String[] args) throws ParseException {

    DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    Date lastDec2010 = sdf.parse("31/12/2010");

    Calendar calUs = Calendar.getInstance(Locale.US);       
    calUs.setTime(lastDec2010);

    Calendar calDe = Calendar.getInstance(Locale.GERMAN);       
    calDe.setTime(lastDec2010);

    System.out.println( "us: " + calUs.get( Calendar.WEEK_OF_YEAR ) ); 
    System.out.println( "de: " + calDe.get( Calendar.WEEK_OF_YEAR ) );
}

打印:

us: 1
de: 52

<强> ADDED 对于美国(我可以想到墨西哥也是如此)1。一周是1月1日所属的那一周。 - 因此,如果1. Januar是星期六,那么星期五(星期三)是同一周,在这种情况下,这一天属于2011年的一周。

答案 1 :(得分:9)

  

为WEEK_OF_YEAR计算的值   字段范围从1到53.第1周为a   年是最早的七天   从getFirstDayOfWeek()开始   至少包含   getMinimalDaysInFirstWeek()天   那年。因此它取决于   getMinimalDaysInFirstWeek()的值,   getFirstDayOfWeek()和当天   1月1周。周之间   一年的第1周和第1周的第1周   下一年是有编号的   顺序从2到52或53(如   需要)。

确定该周是2010年的最后一周还是2011年的第一周,Java使用getMinimalDaysInFirstWeek javadoc。如果该方法返回7,则该周的所有日期都是同一年的第一周是第一周,如果它返回1,那么第一周与下一年的任何日期是下一年的第一周。

在这种情况下,2011年1月1日是星期六所以它被认为是2011年的第一周,只要你希望一周有一天被认为已经是明年的第一周,如果你不要这样做:

Calendar c = Calendar.getInstance();
c.setMinimalDaysInFirstWeek(7);//anything more than 1 will work in this year
DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
c.setTime( sdf.parse("31/12/2010"));
System.out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

返回:

52

答案 2 :(得分:3)

IIRC,第1周的日期为1月1日是第1周 这就是为什么第1周将于12/31/2010返回。
试试12/31/2011,你会得到52。

编辑:周特定于区域设置,有时定义为星期日 - 星期六,有时定义为星期一 - 星期日

答案 3 :(得分:3)

TL;博士

java.time.LocalDate.parse( 
    "31/12/2010" , 
    DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )  
)      
.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )
  

52

或者,添加一个库,然后......

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.
    java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK )  
).getWeek()                           // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year.
  

52

java.time

正如其他人所说,一周的定义在旧Locale课程中的java.util.Calendar不等。

这个麻烦的类及其合作伙伴java.util.Date已被Java 8及更高版本中内置的java.time框架所取代。

IsoFields课程使用ISO 8601标准定义一周:周总是在星期一开始,第1周持有日历年的第一个星期四。

获取当前时刻。

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );

询问标准的基于工作日的年份。

int week = now.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int weekYear = now.get ( IsoFields.WEEK_BASED_YEAR );

标准周定义

有很多方法可以定义“一周”和“一年中的第一周”。

但是,有one major standard definitionISO 8601 standard。该标准定义了一年中的几周,包括一年中的第一周。

  

这一年的第一个星期四

标准周从星期一开始,到星期日结束。

以工作周为基础的第一周第1周有该日历年的第一个星期四。

java.time 类通过IsoFields类支持ISO 8601周,包含三个实现TemporalField的常量:

致电LocalDate::get以访问TemporalField

LocalDate ld = LocalDate.parse( "2010-12-31" ) ;
int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ;
  

ld.toString():2010-12-31

     

weekOfWeekBasedYear:52

     

yearOfWeekBasedYear:2010

ISO 8601字符串格式

ISO 8601标准定义了文本格式以及基于周的年度值的含义:yyyy-Www。对于特定日期,请在周一至周日添加编号为1-7的星期几:yyyy-Www-d

构造这样的字符串。

String outputWeek = String.format( "%04d" , yearOfWeekBasedYear ) + "-W" + String.format( "%02d" , weekOfWeekBasedYear ) ;
String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ;
  

2010-W52-5

YearWeek

如果将ThreeTen-Extra库添加到项目中,这项工作会容易得多。然后使用YearWeek类。

YearWeek yw = YearWeek.from( ld ) ;  // Determine ISO 8601 week of a `LocalDate`. 

生成标准字符串。

String output = yw.toString() ;
  

2010-W52

并解析。

YearWeek yearWeek = YearWeek.parse( "2010-W52" ) ;  
  

yearWeek.toString():2010-W52

确定日期。传递一个java.time.DayOfWeek enum对象,用于周一至周日的星期几。

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

localDate.toString():2010-12-27

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

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; 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

有关详细信息,请参阅类似问题的my Answer

...并在类似问题上查看my Answer

答案 4 :(得分:2)

这是因为本周的开始是当地的。

在美国,第1周从1月1日之前的星期日开始。2010年是12月26日。这就是12月31日仍然是第1周的原因。

在欧洲,第1周从1月1日之前的星期一开始。2010年是12月27日。这也是为什么欧洲12月31日仍然是第1周。

答案 5 :(得分:0)

我觉得这是一种更好的方法。

Calendar c = Calendar.getInstance();
DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
c.setTime( sdf.parse("31/12/2010"));

int thisWeek = c.get(Calendar.WEEK_OF_YEAR);
if (c.get(Calendar.MONTH) == Calendar.DECEMBER && thisWeek == 1)
    thisWeek = 53;

System.out.println(thisWeek);

这里的主要假设是,对于12月份,本周不能为1,因此只返回53.

如果我错了,请提出建议,以及为什么在Java日历中没有实现这一点。