时间(5)
入门。
接着上一篇的话说,每个语言格式化时间的方法都是不一样的,但week-based-year
的概念是不变的,并不是个 bug,而是个 feature,使用时一定要仔细看文档。比如 bash 中,看看date
的文档($ man date
),你会发现类似的两个选项:
%G year of ISO week number
...
%Y year
打印出来 2018 年 12 月 31 日的“年”看看:
$ date -u "+%G" --date="2018-12-31"
2019
$ date -u "+%Y" --date="2018-12-31"
2018
%G
跟 Java 的Y
类似,而%Y
跟 Java 的y
类似。记不住是吧?养成看文档的好习惯吧。
放弃?
等等,上一篇的例子是 2018 年 12 月 30 日,这里用的 31 日,为什么不用一样的?因为是个坑嘛!
$ date -u "+%G" --date="2018-12-30"
2018
$ date -u "+%G" --date="2018-12-31"
2019
回顾一下 Java:
jshell> DateTimeFormatter.ofPattern("YYYY-MM-dd").format(LocalDate.of(2018, 12, 30))
$1 ==> "2019-12-30"
之前明明说 2018 年 12 月 30 日是周日,是 2019 第一周的第一天,为什么 bash 里 30 日还是 2018,而 31 日才是 2019 呢?
进阶!
好吧,是week-based-year
的原理我们还没解释清楚。这个“年”取决于两个因素:
- 一周是从周几开始的?周日还是周一?
- 第一周至少包含几天在新的一年?只要 1 月 1 号在这周里就算新的一年还是要超过这周半数才算?
Bash 采用的是 ISO 标准:一周从周一开始;至少有 4 天在新的一年才叫做第一周:
jshell> java.time.temporal.WeekFields.ISO.getFirstDayOfWeek()
$1 ==> MONDAY
jshell> java.time.temporal.WeekFields.ISO.getMinimalDaysInFirstWeek()
$2 ==> 4
而 Java 则是取决于地点。以美国为例,一周是从周日开始的,只要有一天在新的一年这周就叫做第一周:
jshell> java.time.temporal.WeekFields.of(Locale.US).getFirstDayOfWeek()
$3 ==> SUNDAY
jshell> java.time.temporal.WeekFields.of(Locale.US).getMinimalDaysInFirstWeek()
$4 ==> 1
比较有趣的是,Locale 中既有CHINA
也有CHINESE
,但看起来好像差不多。
jshell> java.time.temporal.WeekFields.of(Locale.CHINA).getFirstDayOfWeek()
$5 ==> SUNDAY
jshell> java.time.temporal.WeekFields.of(Locale.CHINESE).getFirstDayOfWeek()
$6 ==> SUNDAY
但不要想当然的认为全世界都是这样的,比如法国FRANCE
和法语FRENCH
就不同,前者的周从周一开始,而后者从周日开始:
jshell> java.time.temporal.WeekFields.of(Locale.FRANCE).getFirstDayOfWeek()
$7 ==> MONDAY
jshell> java.time.temporal.WeekFields.of(Locale.FRENCH).getFirstDayOfWeek()
$8 ==> SUNDAY