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

时间:2018-09-24 22:24:43

标签: java date datetime javamail 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()));
    }

}

输出:Windows / Mac

PDT

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

GMT-07:00

1 个答案:

答案 0 :(得分:10)

tl; dr

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

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

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

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

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

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

-07:00

避免使用Calendar

您使用的是可怕的旧日期时间类,而该类早已被 java.time 取代。永远不要使用那些遗留类;他们是一个可怕的烂摊子。

您关于 Calendar行为的特定问题尚无定论,因为无需再次使用该类。即使与尚未更新为 java.time 的旧代码进行互操作,您也可以通过添加到旧类中的新方法轻松地在旧类与现代类之间进行转换。

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime() ;

…和…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ; 

java.time

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

获取当前的默认时区ZoneId

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

询问该时区的rules

ZoneRules rules = z.getRules() ;

在某个时刻获取该区域中生效的自UTC的偏移量。我们将使用当前时刻Instant

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

生成一个文本,该文本表示与UTC的偏移量。

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

在2018-09-24T23:38:44.192642Z中America / Los_Angeles区域中,偏移量是-07:00

RFC 1123 / RFC 822

您提到了RFC,但未指定。也许是RFC 1123/822?

java.time 中内置了formatter for that

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

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

ISO 8601

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

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


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore