从joda time到java.time的`w`符号格式不一致 [英] Inconsistent `w` symbol formatting from joda time to java.time

查看:97
本文介绍了从joda time到java.time的`w`符号格式不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的团队希望从Joda时间切换为 java.time ,但是在使用相同模式进行格式化时,我们看到了不同的行为。当我们使用星期几 w 符号时,就会出现问题:

My team is looking to switch from Joda time to java.time, but we're seeing different behavior in formatting using the same pattern. The issue arises when we're using the week-of-week-year w symbol:

final String dateString = "2016-01-04 00:00:00";
final String inputPattern = "yyyy-MM-dd HH:mm:ss";

// parse the input string using Joda
final org.joda.time.format.DateTimeFormatter jodaInputFormatter = org.joda.time.format.DateTimeFormat.forPattern(inputPattern);
final org.joda.time.DateTime jodaDateTime = jodaInputFormatter.parseDateTime(dateString);

// parse the input string using two different java.time classes
final java.time.format.DateTimeFormatter javaTimeInputFormatter = java.time.format.DateTimeFormatter.ofPattern(inputPattern).withZone(java.time.ZoneOffset.UTC);
final java.time.LocalDateTime localDateTime = java.time.LocalDateTime.parse(dateString, javaTimeInputFormatter);
final java.time.ZonedDateTime zonedDateTime = java.time.ZonedDateTime.parse(dateString, javaTimeInputFormatter);

final String outputPattern = "'week' w - dd/MM/yyyy HH:mm:ss";
final org.joda.time.format.DateTimeFormatter jodaOutputFormatter = org.joda.time.format.DateTimeFormat.forPattern(outputPattern);
final java.time.format.DateTimeFormatter javaTimeOutputFormatter = java.time.format.DateTimeFormatter.ofPattern(outputPattern);

// output: week 1 - 04/01/2016 00:00:00
System.out.println("With joda: " + jodaOutputFormatter.print(jodaDateTime));
// output: week 2 - 04/01/2016 00:00:00
System.out.println("With LocalDateTime: " + javaTimeOutputFormatter.format(localDateTime));
// output: week 2 - 04/01/2016 00:00:00
System.out.println("With ZonedDateTime: " + javaTimeOutputFormatter.format(zonedDateTime));

由于某些原因, w 符号在两个实现中是一对一的。

For some reason, the output from the w symbol is off-by-one across the two implementations.

是什么导致这种不一致? w 符号在Joda时间和 java.time 上是否不一致地实现?

What is causing this inconsistency? Is the w symbol inconsistently implemented across Joda time and java.time?

推荐答案

好吧,这有点投机,但是由于您告诉我您的系统时区是EST(-05:00),因此我假设您坐在美国(纽约?)。而且美国不适用ISO-8601周规定。星期几从星期日开始,一年的第一周不必包含至少4天(即使一天也可以算作一年的第一周)。

Well, it is a little bit speculative, but since you told me that your system timezone is EST (-05:00) I assume that you are sitting in US (New York?). And US does not apply ISO-8601-week rules. Weeks start on Sunday, and the first week of the year does not need to contain at least 4 days (even one day is enough to be counted as first week of year).

所以让我们看一下您的示例日期为1月4日。今天是星期一。美国的第一个星期是从2016年1月1日到2016年1月2日(2天-足够美国使用)。美国的第二个星期从1月3日星期日开始,所以1月的4月也在第二个星期。

So let's look at your example date of 4th of January. It is a Monday. The first US-week is from 2016-01-01 until 2016-01-02 (2 days - enough for US). And the second US-week starts on Sunday the 3rd of January, so the fourth of January is in the second week, too.

现在关键点是: java.time (JSR-310)对模式符号w使用本地化的基于周的年的星期,另请参见其应使用相同代码的反向移植。代码摘录:

And now the critical point: java.time (JSR-310) uses a localized week of week-based-year for the pattern symbol w, see also its backport which should have the same code. Code excerpt:

} else if (cur == 'w') {
    if (count > 2) {
        throw new IllegalArgumentException("Too many pattern letters: " + cur);
    }
    appendInternal(new WeekFieldsPrinterParser('w', count));

...

static final class WeekFieldsPrinterParser implements DateTimePrinterParser {
    private final char letter;
    private final int count;

    public WeekFieldsPrinterParser(char letter, int count) {
        this.letter = letter;
        this.count = count;
    }

    @Override
    public boolean print(DateTimePrintContext context, StringBuilder buf) {
        WeekFields weekFields = WeekFields.of(context.getLocale());
        DateTimePrinterParser pp = evaluate(weekFields);
        return pp.print(context, buf);
    }

使用 WeekFields.of(context.getLocale ())显然是模式符号 w。

The use of WeekFields.of(context.getLocale()) for the pattern symbol "w" is evident.

相反, Joda-Time仅使用ISO-8601-星期定义,它使星期从星期一开始,并将该星期算作一年的第一周,该年在当前日历年中至少包含四天。因此1月4日星期一是一年中第一个星期的开始,因为前三天不足以将ISO-8601算作一周。而是将前几天视为上一年的最后一周。

In contrast, Joda-Time only uses ISO-8601-week-definition which let weeks start on Monday and count that week as first week of year which contains at least four days in current calendar year. So the Monday 4th of January is the start of the first week-of-year because the three days before are not enough for ISO-8601 to be counted as week. Those preceding days are instead considered as last week of previous year.

因此,Joda-Time将1月4日显示为第1周,而 java.time 使用美国周2。

Consequently, Joda-Time displays week 1 for 4th of January while java.time uses the US-week 2.

问题的解决方案是指定区域设置,以便格式化程序将使用ISO周,因此您将获得与Joda-Time中相同的结果。例如,您可以选择 Locale.UK ,该语言也使用英语,但使用其他星期规则。 不要依赖您的默认语言环境。这可能会欺骗您。

Solution of your problem is to specify the locale such that the formatter will use ISO-weeks so you get the same result as in Joda-Time. For example, you could choose Locale.UK which also uses English but other week rules. Don't rely on your default locale. This can fool you.

这篇关于从joda time到java.time的`w`符号格式不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆