Java SimpleDateFormat在不同的操作系统上以不同的方式解释'z'

Abh*_*nde 7 java datetime date jakarta-mail simpledateformat

我遵循了代码(简化为专注于问题).使用SimpleDateFormat模式打印时区信息.

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

此类正在JavaMail中使用,这导致我们的电子邮件标头包含不符合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()));
    }

}
Run Code Online (Sandbox Code Playgroud)

输出:Windows/Mac

PDT
Run Code Online (Sandbox Code Playgroud)

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

GMT-07:00
Run Code Online (Sandbox Code Playgroud)

Bas*_*que 10

TL;博士

切勿使用Calendar.请改用java.time类.

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

OffsetDateTime
.now( ZoneOffset.UTC )
.format( DateTimeFormatter.RFC_1123_DATE_TIME )
Run Code Online (Sandbox Code Playgroud)

星期一,2019年9月24日23:45:21 GMT

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

ZoneId
.systemDefault()
.getRules()
.getOffset(
    Instant.now() 
)
.toString()
Run Code Online (Sandbox Code Playgroud)

-07:00

避免 Calendar

您使用的是java.time多年前取代的糟糕的旧日期时间类.永远不要使用那些遗留类; 他们是一个可怕的可怜的混乱.

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

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime() ;
Run Code Online (Sandbox Code Playgroud)

…和…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ; 
Run Code Online (Sandbox Code Playgroud)

java.time

显然,您希望当前默认时区的当前偏移量来自UTC.

获取当前的默认时区,a ZoneId.

ZoneId z = ZoneId.systemDefault() ;  // Or specify ZoneId.of( "Pacific/Auckland" ) or so on.
Run Code Online (Sandbox Code Playgroud)

询问该时区的规则.

ZoneRules rules = z.getRules() ;
Run Code Online (Sandbox Code Playgroud)

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

Instant now = Instant.now() ;
ZoneOffset offset = rules.getOffset( now ) ;
Run Code Online (Sandbox Code Playgroud)

生成表示从UTC偏移的文本.

String output = "At " + now + " in zone " + z + " the offset is " + offset;
Run Code Online (Sandbox Code Playgroud)

2018-09-24T23:38:44.192642Z在美国/洛杉矶地区偏移量为-07:00

RFC 1123/RFC 822

您提到了RFC但没有指定.也许RFC 1123/822?

它的格式化程序内置于java.time中.

OffsetDateTime nowInUtc = OffsetDateTime.now( ZoneOffset.UTC ) ;
String output = nowInUtc.format( DateTimeFormatter.RFC_1123_DATE_TIME ) ;
Run Code Online (Sandbox Code Playgroud)

星期一,2019年9月24日23:45:21 GMT

ISO 8601

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

只知道现代协议使用ISO 8601标准格式.方便的是,在解析/生成字符串时,默认情况下会在java.time类中使用这些格式.


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

您可以直接与数据库交换java.time对象.使用符合JDBC 4.2或更高版本的JDBC驱动程序.不需要字符串,不需要课程.java.sql.*

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.