Java 8的DateTimeFormatter
类有一个方法ofPattern(String pattern)
,它允许您从A-z
,a-z
个字母的字符串中定义格式。这些示例没有说明y
,年代和Y
,基于周的年份之间的区别。它是什么?
Symbol Meaning Presentation Examples
------ ------- ------------ -------
y year-of-era year 2004; 04
Y week-based-year year 1996; 96
答案 0 :(得分:29)
" year-week"的年度值样式日期,如2006W52。 如果所涉及的一周跨越年份界限,它可能会超出年代的价值+1或-1。
答案 1 :(得分:8)
其他一些答案很有趣,但是很复杂。这是一个希望更简单的答案,可以使您适应方向。
y
和u
(小写)基于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年的一周的第一周。
YYYY
表示2019-12-30的日期。yyyy
。 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库为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)
每个字段都记录在"字段"类,例如ChronoField
,WeekFields
或IsoFields
。
"年代"字段记录在ChronoField
。
"以周为基础的年份"字段记录在WeekFields
。
答案 3 :(得分:1)
Y
的建议是,我们要根据ISO 8601周编号年份格式化给定日期。根据{{3}},第01周的定义是
其中有一年的第一个星期四的星期(正式的ISO定义)
因此
一年中的第一个ISO周可能有最多三天,实际上是在公历结束的那一天
让我们考虑“ 2019-12-30”日期,即星期一。
如果我们看一下该周,则我们将2019年12月30日和31日分别为星期一和星期二; 2020年1月1-4日为星期三,星期四,星期五和星期六。如您所见,本周跨越(我们使用的日历系统)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天:
我的代码:
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月1日的一周。换句话说,一周只需要在新的一年中至少有一天,就可以成为该年的第1周。在ISO中不是这样。您会看到法国的1月1日属于旧年的第52周。在这里,一周属于大部分日子所在的年份(因为一周中有7天,所以这是奇数,所以永远不会有平局)。换句话说,一周必须在新的一年中至少有四(四)天才能成为第1周。