年代和周年之间的差异?

时间:2014-10-17 19:13:34

标签: java date datetime java-8 java-time

Java 8的DateTimeFormatter类有一个方法ofPattern(String pattern),它允许您从A-za-z个字母的字符串中定义格式。这些示例没有说明y年代Y基于周的年份之间的区别。它是什么?

Symbol  Meaning                     Presentation      Examples
------  -------                     ------------      -------
 y       year-of-era                 year              2004; 04
 Y       week-based-year             year              1996; 96

6 个答案:

答案 0 :(得分:29)

" year-week"的年度值样式日期,如2006W52。 如果所涉及的一周跨越年份界限,它可能会超出年代的价值+1或-1。

请参阅http://en.wikipedia.org/wiki/ISO_8601#Week_dates

答案 1 :(得分:8)

tl; dr

table showing the calendar year of 2019-12-30 is 2019 while the week-based year is 2020

Table showing the length in days and weeks for a calendar year and a week-based year, 365 or 366 days versus 364 or 371, and 52 partial weeks versus 52 or 53 whole weeks.

详细信息

其他一些答案很有趣,但是很复杂。这是一个希望更简单的答案,可以使您适应方向。

yu(小写)

基于Gregorian calendar,年份的y字符就是日历年,即整个西方国家和世界大部分地区使用的常规年份。

DateTimeFormatter类还将u用于几乎相同的事物。对于当代日期,没有区别。有关具体细节,请参见uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java?

对于我们在quotidian生活中使用的常规日期,您可以使用以下格式设置格式解析或生成表示日期值的文本:

DateTimeFormatter.ofPattern( "dd/MM/yyyy" ) ;

…或…

DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;

无论哪种情况,都将像这样解析2019年12月30日,星期一:

LocalDate localDate = LocalDate.parse( "30/12/2019" ) ;

localDate.toString():2019-12-30

Y(大写)

各行各业的许多人发现按星期跟踪时间,为一年中的每个星期分配一个数字很有用。

有多种定义星期的方法,例如从星期日或星期一开始。因此,有多种方法可以定义一年中的一周。 #1周是否有1月1日?还是第一周有一年的第一个星期日?

ISO 8601标准defines a week从星期一开始。第1周是新日历年的第一个星期四。

此定义表示以周为基础的年份有52个或53个整周,始终为7天(周一至周日),一年的长度为364天或371天。相比之下,一个日历年有365天或366天跨越52个局部星期。

因此日期2019-12-30(2019年12月30日,星期一)实际上是基于2020年的一周的第一周。

calendar showing week # 1 of 2020, starting with December 30, 2019.

  • 如果您需要生成或解析 2020 的基于周的年份值,请在格式格式中使用大写YYYY表示2019-12-30的日期。
  • 如果您希望日历年为2019-12-30,即 2019 ,请使用小写的yyyy

ISO 8601格式

ISO 8601标准定义了一种特定格式,用于表示基于一周的年份的一周内的日期:YYYY-Www-d,其中YYYY是基于一周的年份,-W是固定的,ww代表第1到52或1-53周,而d代表从周一到周日的1-7。

因此,2019年12月30日,星期一为:2020-W01-1表示以周为基础的2020年,一年中的第一周和一周中的第一天(星期一)。

要使用星期几编号来解析ISO 8601星期,我们可以使用DateTimeFormatter。无需使用YYYY定义格式设置模式,因为这项工作已经为您完成。使用内置的DateTimeFormatter.ISO_WEEK_DATE

String output = localDate.format( DateTimeFormatter.ISO_WEEK_DATE ) ;

2020-W01-1

同样,解析。

LocalDate localDate = 
    LocalDate.parse( 
        "2020-W01-1" , 
        DateTimeFormatter.ISO_WEEK_DATE
    )
;

localDate.toString():2019-12-30

ThreeTen-Extra

ThreeTen-Extra库为Java内置的 java.time 类添加了功能。

org.threeten.extra.YearWeek

该库提供了YearWeek类。根据{{​​3}},这正是您每周工作几周所需要的。

此类可以在常规日期格式和面向星期的格式之间来回转换。

LocalDate localDate = LocalDate.of( 2019 , Month.DECEMBER , 30 ) ;  // Monday 2019-12-30. Its week-based year is 2020. 
YearWeek yearWeek = YearWeek.from( localDate ) ;
String wFormatted = yearWeek.toString() ;

2020-W01

从中获取日期。

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

localDate.toString():2019-12-30

答案 2 :(得分:4)

每个字段都记录在"字段"类,例如ChronoFieldWeekFieldsIsoFields

"年代"字段记录在ChronoField

"以周为基础的年份"字段记录在WeekFields

答案 3 :(得分:1)

Y的建议是,我们要根据ISO 8601周编号年份格式化给定日期。根据{{​​3}},第01周的定义是

其中有一年的第一个星期四的星期(正式的ISO定义)

因此

一年中的第一个ISO周可能有最多三天,实际上是在公历结束的那一天

让我们考虑“ 2019-12-30”日期,即星期一。

wikipedia

如果我们看一下该周,则我们将2019年12月30日和31日分别为星期一和星期二; 2020年1月1-4日为星期三,星期四,星期五和星期六。如您所见,本周跨越calendar showing ISO 8601 weeks 1 & 2 of year-based year 2020(我们使用的日历系统)2019年和公历2020年。如果我们应用上述基于周的年份的week01的定义,我们可以看到12/30之间的一周/ 2019和01/05/2020是基于周的2020年的week01(ISO标准指定Gregorian calendar year为星期一)。因此,如果我们想用dateTimeFormatter 'YYYY-MM-dd'解析“ 2019-12-30”,则正确的结果是'2020-12-30'。但是,对于'yyyy-MM-dd',最终结果将是'2019-12-30'

System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("YYYY-MM-dd"))); // output "2020-12-30"
System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // output "2019-12-30"

我认为Java实现可能存在潜在问题。如果我们考虑上述Sam Berry给出的the beginning of a week,则“ 2019-12-29”的输出与基于周的年份的定义方式不一致。原因是“ 2019-12-29”是星期日。如果我们从上面的维基百科应用定义,则即使给出'YYYY-MM-dd',“ 2019-12-29”也应解析为“ 2019-12-29”。这是因为按照ISO标准,week01的开始是星期一而不是星期日。如果我们查看example,则可以看到2020年的第01周从“ 2019-12-30”开始。我怀疑这可能是由于API的实现者认为一周的开始是星期日,根据ISO标准,这是不正确的。

更新

可疑的Java实现错误。这不是实现错误。感谢您在下面的week numbers for 2020评论。在格式化期间,对如何定义week01的开始有微妙的依赖性,这受Locale的影响。例如,如果语言环境是欧洲,则一周的开始是星期一,这与ISO标准一致。因此

System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.FRANCE)));

具有输出2019-12-29。但是,在美国,一周的开始被视为星期日。因此

System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.US)));

具有输出2020-12-29

答案 4 :(得分:0)

基于周的年份

一个星期只属于一年的概念。例如:

tzutil /g

时代

年份的常用用法,1/1始终是一年的第一天。例如:

LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/Y")) 
---> "12/29/2020"`

答案 5 :(得分:0)

我没有从其他答案中得出完全清楚的答案,所以请允许我出手。

基于周的年份或有时简称为 week year ,是相关星期编号所属的年份。因此,举例来说,第1周的所有天都具有相同的基于周的年份,即使某周中的某天位于上一个日历年。或反过来说,假设一年中的第52周延伸到下一年(这可能适用于某些(并非全部)周编号方案),那么该周的每一天都将旧的日历年作为基于周的年份。我住的地方,2020年的第1周是从12月30日星期一至1月5日星期日(含)。因此,对于截至12月29日的日期,日历年和基于周的年份同意为2019年。12月30日和31日具有基于周的年份2020,但是当然仍然是日历年2019。从1月1日开始,日历年和基于周的年份。再次同意,现在是2020年。

因此,以周为基础的年份除具有周数外几乎没有任何有意义的用途。

变得有点复杂的地方(我认为其他答案不太清楚的地方)是,周编号取决于语言环境,因此基于周的年份也是如此。 DateTimeFormatter有一个语言环境,并在确定给定日期的基于周的年份时使用此语言环境选择要使用的星期编号方案。

为了说明这一点,我将在2022年新年前后在三种不同的语言环境中格式化10天:

  1. 我想展示ISO 8601周,并选择了法国作为遵循ISO的国家/地区
  2. 美国的周从星期日开始
  3. 在许多阿拉伯国家/地区,新的一周从星期六开始;我以摩洛哥为例

我的代码:

    DateTimeFormatter iso
            = DateTimeFormatter.ofPattern("Y w E", Locale.FRANCE);
    DateTimeFormatter us
            = DateTimeFormatter.ofPattern("Y w E", Locale.US);
    DateTimeFormatter arabic = DateTimeFormatter
            .ofPattern("Y w E", Locale.forLanguageTag("ar-MA"));
    
    System.out.println("                ISO           US          Morocco");
    LocalDate d = LocalDate.of(2021, Month.DECEMBER, 25);
    for (int i = 0; i < 10; i++) {
        System.out.format("%-10s  %-12s  %-11s  %s%n",
                d, d.format(iso), d.format(us), d.format(arabic));
        d = d.plusDays(1);
    }

输出:

                ISO           US          Morocco
2021-12-25  2021 51 sam.  2021 52 Sat  2021 53 السبت
2021-12-26  2021 51 dim.  2022 1 Sun   2021 53 الأحد
2021-12-27  2021 52 lun.  2022 1 Mon   2021 53 الاثنين
2021-12-28  2021 52 mar.  2022 1 Tue   2021 53 الثلاثاء
2021-12-29  2021 52 mer.  2022 1 Wed   2021 53 الأربعاء
2021-12-30  2021 52 jeu.  2022 1 Thu   2021 53 الخميس
2021-12-31  2021 52 ven.  2022 1 Fri   2021 53 الجمعة
2022-01-01  2021 52 sam.  2022 1 Sat   2022 1 السبت
2022-01-02  2021 52 dim.  2022 2 Sun   2022 1 الأحد
2022-01-03  2022 1 lun.   2022 2 Mon   2022 1 الاثنين

观察;

  • 在所有三列中,星期年份在第1周开始的同一天发生变化。
  • 更改发生在三个区域的不同日期:
    1. 在美国以周为基础的2022年始于2021年圣史蒂芬纪念日。
    2. 在摩洛哥,以周为基础的2022年恰好是2022日历年的第一天,但​​这仅仅是因为2022年的这一天是星期六,因此是一周的第一天。
    3. 在ISO 8601中,基于周的2022年要到1月3日才开始。

出于完整性考虑:定义星期编号分为两个部分:

  1. 新一周从一周的哪一天开始
  2. 一周必须包含新的一年的多少天才能成为第1周。这被称为第一周的最少天数。

在美国和摩洛哥,第1周被定义为包含1月1日的一周。换句话说,一周只需要在新的一年中至少有一天,就可以成为该年的第1周。在ISO中不是这样。您会看到法国的1月1日属于旧年的第52周。在这里,一周属于大部分日子所在的年份(因为一周中有7天,所以这是奇数,所以永远不会有平局)。换句话说,一周必须在新的一年中至少有四(四)天才能成为第1周。