Java 日期时间格式中的小写z返回偏移量,而不是缩写

Java 日期时间格式中的小写z返回偏移量,而不是缩写,java,datetime,timezone,jodatime,datetime-format,Java,Datetime,Timezone,Jodatime,Datetime Format,我被难住了。我必须承认,我可能没有在正确的地方寻找这个错误。也就是说 我们使用dd-MMM-YYY-HH:mm:ss z作为日期格式字符串。小写的z应该返回区域的三个字母缩写,如PST或CET。确实如此。除了生产之外,到处都是。在生产中,我们得到偏移量,如-08:00。我们通过战争证实,我们在任何地方都在使用joda 2.9.2 我们使用dateTime.withZone(DateTimeZone.forID(timezone)).toString(dateFormat,locale)其中dat

我被难住了。我必须承认,我可能没有在正确的地方寻找这个错误。也就是说

我们使用
dd-MMM-YYY-HH:mm:ss z
作为日期格式字符串。小写的
z
应该返回区域的三个字母缩写,如
PST
CET
。确实如此。除了生产之外,到处都是。在生产中,我们得到偏移量,如
-08:00
。我们通过战争证实,我们在任何地方都在使用joda 2.9.2

我们使用
dateTime.withZone(DateTimeZone.forID(timezone)).toString(dateFormat,locale)
其中
dateTime
是一个
dateTime
timezone
是一个
字符串(
美国/洛杉矶
)<代码>日期格式
如上所述,
dd-MMM-YYY-HH:mm:ss z
locale
跨实例验证为
en

我注意到了这一点,这就产生了这样的想法,即区域设置信息正在丢失,只留下偏移量。尽管如此,无论我对
timezone
locale
使用什么,我都无法重现这种情况。当然,我们也不使用
来表示越界行为

编辑:就其价值而言,我认为这不是语言环境,因为我可以在
.toString(dateFormat,locale)
中使用合成的语言环境值,如
新语言环境(“hasdf”)
和预期的日期格式。我能得到完全出乎意料的格式的唯一方法是使用大写的
Z
代替小写的
Z


第二次编辑:噢,JVM在任何地方都是一样的。

我不能重现这个问题,但我认为Joda从JVM本身获得了这个信息

您可以通过以下代码检查Joda使用的数据:

String[][] zoneStringsEn = DateTimeUtils.getDateFormatSymbols(Locale.ENGLISH).getZoneStrings();
for (String[] strings : zoneStringsEn) {
    if (strings != null && strings.length >= 5 && "America/Los_Angeles".equals(strings[0])) {
        System.out.println(strings[2]); // "PST" in my JVM
    }
}

可能不工作的环境有不同的JVM版本。

可能这与JVM中的区域设置数据有关(检查您的版本,确保它们在所有环境中都相同)

无论如何,有一种变通方法可以覆盖Joda用于时区名称的文本。您需要扩展
org.joda.time.tz.DefaultNameProvider

public class MyNameProvider extends DefaultNameProvider {

    @Override
    public String getShortName(Locale locale, String id, String nameKey, boolean standardTime) {
        if (Locale.ENGLISH.equals(locale) && "America/Los_Angeles".equals(id)) {
            // return the correct name for Daylight Saving Time
            return standardTime ? "PST" : "PDT";
        }

        return super.getShortName(locale, id, nameKey, standardTime);
    }
}
然后你会:

DateTimeZone.setNameProvider(new MyNameProvider());

DateTime d = new DateTime().withZone(DateTimeZone.forID("America/Los_Angeles"));
System.out.println(d.toString("dd MMM YYY HH:mm:ss z", Locale.ENGLISH));
这将覆盖JVM正在使用的任何数据,并始终在英语区域设置中使用“PST”和“PDT”表示美国/洛杉矶

我能得到完全出乎意料的格式的唯一方法是用大写的Z代替小写的Z

这是因为一个大写的Z表示偏移量,如javadoc中所述:

区域:'Z'输出不带冒号的偏移量,'ZZ'输出带冒号的偏移量,'ZZZ'或更多输出区域id

小写的z表示区域名称:

符号含义表示示例
------  -------               ------------   -------
z时区文本太平洋标准时间;PST
Z时区偏移/id区域-0800-08:00; 美国/洛杉矶

很有可能是某个类路径问题

在我们的项目中,我们能够在类路径上重现这个问题,包括JodaTime2.9.2和2.4

我们不知道我们包含了旧的2.4版本。它没有显示在依赖关系树中。最终,我们在一些旧的胖罐子依赖中发现了joda类,实际上我们不再需要它了


请记住,不同环境之间的类路径问题可能是不确定的。

哪个特定时区会返回偏移量?你知道TZDB很久以前就开始删除许多时区的“发明”缩写吗?所有时区都给出偏移量,而不是缩写。双重检查-相同的JVM EEEEE verywhere-uu-是的,双重检查-相同的JVM EEEEE verywhere O.O