Java SimpleDateFormat 在不同的 OS 上对 'z' 的解释不同

Java SimpleDateFormat interprets 'z' differently on different OS

我有以下代码(已简化以关注问题)。使用 SimpleDateFormat 模式打印时区信息。

你知道为什么 z 在不同的机器上被区别对待吗?如果有办法告诉 Java 在所有机器上统一对待它?

此 class 正在 JavaMail and that is causing our email headers to include time which is not comply with RFC 2822 中使用。

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class DateFormatTest {
    String PATTERN = "z";
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.PATTERN);

    public static void main(final String[] args) {
        new DateFormatTest().printTimezone();
    }

    public void printTimezone() {
        System.out.println(this.simpleDateFormat.format(Calendar.getInstance().getTime()));
    }

}

输出:Windows / Mac

PDT

输出:Linux(CentOS Linux 版本 7.5.1804(核心))/Ubuntu 14 / 18

GMT-07:00

tl;博士

永远不要使用 Calendar。使用 java.time classes 代替。

对于 RFC 1123 / RFC 822 格式的字符串:

OffsetDateTime
.now( ZoneOffset.UTC )
.format( DateTimeFormatter.RFC_1123_DATE_TIME )

Mon, 24 Sep 2018 23:45:21 GMT

获取特定时区的当前偏移量:

ZoneId
.systemDefault()
.getRules()
.getOffset(
    Instant.now() 
)
.toString()

-07:00

避免Calendar

您正在使用可怕的旧日期时间 classes,这些日期时间在多年前被 java.time 取代。永远不要使用那些遗留的 classes;他们真是一团糟。

您关于 Calendar 行为的特定问题没有实际意义,因为没有必要再次使用 class。即使在与尚未更新到 java.time 的旧代码进行互操作时,您也可以通过添加到旧 [=] 的新方法在遗留和现代 classes 之间轻松转换169=]es.

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime() ;

……和……

GregorianCalendar gc = GregorianCalendar.from( zdt ) ; 

java.time

显然您需要当前默认时区的当前偏移量。

获取当前默认时区,一个ZoneId.

ZoneId z = ZoneId.systemDefault() ;  // Or specify ZoneId.of( "Pacific/Auckland" ) or so on.

请求那个时区的rules

ZoneRules rules = z.getRules() ;

获取特定时刻在该区域有效的UTC偏移量。我们将使用当前时刻,a Instant.

Instant now = Instant.now() ;
ZoneOffset offset = rules.getOffset( now ) ;

生成代表该 UTC 偏移量的文本。

String output = "At " + now + " in zone " + z + " the offset is " + offset;

At 2018-09-24T23:38:44.192642Z in zone America/Los_Angeles the offset is -07:00

RFC 1123/RFC 822

您提到了 RFC 但没有具体说明。也许 RFC 1123 / 822 ?

formatter for that 内置于 java.time.

OffsetDateTime nowInUtc = OffsetDateTime.now( ZoneOffset.UTC ) ;
String output = nowInUtc.format( DateTimeFormatter.RFC_1123_DATE_TIME ) ;

Mon, 24 Sep 2018 23:45:21 GMT

ISO 8601

仅供参考,RFC 1123 / RFC 822 格式是一种糟糕 格式。它假定英语。机器很难解析,人类也很难阅读。但我知道您可能需要它来处理过时的旧协议。

只知道现代协议使用 ISO 8601 标准格式。方便的是,这些格式在 java.time classes when parsing/generating strings.

中默认使用

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

在哪里获取 java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.