解析DateFormat时的Java时区

IT小君   2021-12-09T03:39:23

我有如下解析日期的代码:

String ALT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat sdf = new SimpleDateFormat(
                    ALT_DATE_TIME_FORMAT);
Date date = sdf.parse(requiredTimeStamp);

它工作正常,突然间,这停止了工作。事实证明,管理员对服务器进行了一些配置更改,当前返回的日期为“2010-12-27T10:50:44.000-08:00”,无法通过上述模式进行解析。我有两个问题:

第一个是什么模式会解析 JVM 以上述格式返回的日期(具体来说,只是“-08:00”作为时区)?其次,在 linux RHEL 5 服务器上究竟会在哪里更改此类设置,以便我们将来知道此类更改?

点击广告,支持我们为你提供更好的服务
评论(8)
IT小君

tl;博士

OffsetDateTime.parse( "2010-12-27T10:50:44.000-08:00" )

ISO 8601

输入字符串格式在ISO 8601标准中定义,这是一个日期时间格式系列。

避免旧的日期时间课程

问题和其他答案使用与最早版本的 Java 捆绑在一起的旧的过时日期时间类。避开它们。现在被 java.time 类取代。

使用 java.time

您的输入字符串以offset-from-UTC结尾所以我们解析为一个OffsetDateTime对象。

java.time 类在解析/生成字符串时默认使用 ISO 8601 格式。所以不需要指定格式模式。

OffsetDateTime odt = OffsetDateTime.parse( "2010-12-27T10:50:44.000-08:00" );

如果您想将此日期时间值视为 UTC 时间线上的某个时刻,请提取一个Instant.

Instant instant = odt.toInstant();

时区是偏移量加上一组用于处理夏令时 (DST) 等异常情况的规则。如果您考虑了时区,请应用 aZoneId来获取ZonedDateTime对象。时间线上的同一时刻,但通过不同的挂钟时间查看

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );  // Same moment on the timeline, but viewed through a different wall-clock 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 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

2021-12-09T03:39:23   回复
IT小君

另一个应用程序使用 ISO 8601 日期时间格式。我假设另一个应用程序正在向您发送一个 XML 响应,该响应符合 XML Schema 的 dateTime 类型,即 ISO 8601。现在,DateFormat 无法解析这种格式是众所周知的事情。您要么必须使用其他库,如 joda-time(joda-time 是赢家)或其他响应中指定的 FastDateFormat。看看这篇文章Converting ISO 8601-compatible String to java.util.Date

2021-12-09T03:39:23   回复
IT小君

如果仍在寻找答案,这对我有用

我的输入:2020-12-08T10:36:53.939+05:30
我的输出:2020 年 12 月 8 日星期二 10:36:53

您可以将此日期转换为您需要的任何格式!

private static Date convertDate(String input) {
    Date newDate = null;
    try {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        newDate=dateFormat.parse(input);  
    } catch (Exception e) {
        e.printStackTrace();
    }
    return newDate;
}
2021-12-09T03:39:24   回复
IT小君

如果您想使用直接 JDK 解析它,我相信它应该可以使用 JAXB 工具进行解析,请参阅DatatypeFactory.newXMLGregorianCalendarDatatypeConverter.parseDateTime

2021-12-09T03:39:24   回复
IT小君

使用JodaTime

作为@Pangea 建议使用 JodaTime 的更具体示例,您可以使用以下方法:

String timestamp = "2012-09-17T04:11:46Z";

DateTime date = ISODateTimeFormat.dateTimeParser().parseDateTime(timestamp);

这可以正确识别 UTC 时区。我还没有在字符串时间戳中尝试过毫秒,但我相信它也能正常工作。

希望能帮助别人。

J.P

2021-12-09T03:39:24   回复
IT小君

问题应该requiredTimeStamp是来自哪里以及以哪种格式。它是由用户输入还是从其他程序读取?哪个组件在字符串表示中创建日期?

格式 "2010-12-27T10:50:44.000-08:00" 看起来像标准化格式ISO-8601 它应该可以用模式解析yyyy-MM-dd'T'HH:mm:ss.SSSZ

不确定哪些设置会影响这一点,但有一个关于 Java TimeZonesOracle FAQ它可能是user.timezone系统属性或/etc/localtimeRHEL 中符号链接。

2021-12-09T03:39:24   回复
IT小君

SimpleDateFormat 只接受-0800GMT-08:00作为时区。

似乎无法解析 ISO 8601 格式SimpleDateFormat也许您应该看看Apache Commons LangFastDateFormat它兼容SimpleDateFormat但接受ZZ应解析您需要的时区格式的时区模式。DateFormatUtils包含一些看起来像您需要的模式的示例常量,只是没有毫秒(例如ISO_DATETIME_TIME_ZONE_FORMAT)。

2021-12-09T03:39:24   回复
IT小君

尝试将其更改为小写 z。

z 处理大多数常见的通用时区语法,而 Z 使用更严格的 RFC 822 时区,有 4 位数字。

尽管它记录了两者都应该解析“常规时区设置”,但它可能会对您的情况产生影响。

2021-12-09T03:39:25   回复