【问题标题】:Why dec 31 2010 returns 1 as week of year?为什么 2010 年 12 月 31 日返回 1 作为一年中的一周?
【发布时间】:2011-01-05 19:43:19
【问题描述】:

例如:

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 时间也是如此。

:)

【问题讨论】:

  • 也许是因为它是在 2011 年的第一周...?
  • @Ralph,es_MX,墨西哥,我希望与 1 有所不同。
  • 我已经扩展了我的答案来解释为什么 31. Dec 属于美国一年中的第一周。 - 但我不知道墨西哥的情况如何

标签: java calendar jodatime week-number


【解决方案1】:

一年中的一周的定义是 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

添加 对于美国(我可以认为墨西哥也是如此),一年中的第 1 周是 1. 一月所属的那一周。 -- 所以如果 1. Januar 是星期六,那么之前的星期五(12 月 31 日)属于同一周,在这种情况下,这一天属于 2011 年的第 1 周。

【讨论】:

    【解决方案2】:

    为 WEEK_OF_YEAR 计算的值 字段范围从 1 到 53。第 1 周为 年份是最早的 7 天期间 从 getFirstDayOfWeek() 开始 至少包含 getMinimalDaysInFirstWeek() 天数 那年。因此它取决于 getMinimalDaysInFirstWeek() 的值, getFirstDayOfWeek() 和日期 1 月 1 日那一周。 一年的第 1 周和第 1 周 下一年编号 依次从 2 到 52 或 53(如 需要)。

    要确定该周是 2010 年的最后一周还是 2011 年的第一周,Java 使用 getMinimalDaysInFirstWeekjavadoc。如果该方法返回 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
    

    【讨论】:

      【解决方案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

      正如其他人所指出的,一周的定义因旧 java.util.Calendar 类中的 Locale 而异。

      这个麻烦的类及其伙伴 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 枚举对象用于周一至周日的星期几。

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

      localDate.toString(): 2010-12-27

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


      关于java.time

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

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

      要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

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

      从哪里获得 java.time 类?

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore


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

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

      【讨论】:

        【解决方案4】:

        IIRC,日期为 1 月 1 日的第一周是第 1 周。
        这就是为什么在 2010 年 12 月 31 日返回第 1 周的原因。
        在 2011 年 12 月 31 日试一试,你会得到 52 个。

        编辑:周因地区而异,有时定义为星期日 - 星期六,有时定义为星期一 - 星期日

        【讨论】:

        • 很可能是从财政年度的角度来看待它,即周一至周日的角度。
        • 应该添加“一周的第一天”是特定于语言环境的。美国以外的许多国家/地区将星期一定义为一周的第一天。
        • 一周的开始不仅取决于语言环境,还取决于如何确定一年的第一周。
        【解决方案5】:

        这是因为一周的开始时间取决于当地情况。

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

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

        【讨论】:

        • 是的。不过,如果一周从星期一开始,则适用相同的原则。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多