解析 DateFormat 时的 Java 时区

发布于 2024-10-09 01:24:26 字数 450 浏览 9 评论 0 原文

我的代码解析日期如下:

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 服务器上到底应该在哪里更改此类设置,以便我们在将来了解此类更改?

I had code that parses date as follows:

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);

And it was working fine, suddenly, this stopped working. It turns out an admin made some config changes on the server and the date is currently being returned as "2010-12-27T10:50:44.000-08:00" which is not parse-able by the above pattern. I have two questions:

The first would be what pattern would parse the date being returned by the JVM in the format above (specifically, just '-08:00' as the time zone)? And second, where exactly would one change such settings on a linux RHEL 5 server so that we are aware of such changes in the future?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

暖伴 2024-10-16 01:24:26

tl;dr

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) 等异常情况的规则。如果您考虑了时区,请应用 ZoneId 来获取 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, 日历,& SimpleDateFormat

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

要了解更多信息,请参阅 Oracle 教程 。并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310

您可以直接与数据库交换java.time对象。使用符合 JDBC 驱动程序 jeps/170" rel="noreferrer">JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如 Interval YearWeek YearQuarter ,以及更多

tl;dr

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

ISO 8601

The input string format is defined in the ISO 8601 standard, a family of date-time formats.

Avoid old date-time classes

The Question and other Answers use old outmoded date-time classes bundled with the earliest versions of Java. Avoid them. Now supplanted by the java.time classes.

Using java.time

Your input string ends with an offset-from-UTC. So we parse as a OffsetDateTime object.

The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.

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

If you want to view this date-time value as a moment on the timeline in UTC, extract an Instant.

Instant instant = odt.toInstant();

A time zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST). If you have a time zone in mind, apply a ZoneId to get a ZonedDateTime object. Same moment on the timeline, but viewed through a different wall-clock time.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );  // Same moment on the timeline, but viewed through a different wall-clock time.


About java.time

The 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.

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

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The 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.

傻比既视感 2024-10-16 01:24:26

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

The other application is using the ISO 8601 dateTime format. I am assuming the other application is sending you an XML response that is in compliance with XML Schema's dateTime type, which is ISO 8601. Now, it is a known thing that the DateFormat can't parse this format. You either have to use other libraries like joda-time (joda-time is the winner) or the FastDateFormat as specified in the other responses. Look at this post Converting ISO 8601-compliant String to java.util.Date

傲世九天 2024-10-16 01:24:26

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

我的输入:2020-12-08T10:36:53.939+05:30
我的输出:Tue Dec 08 10:36:53 IST 2020

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

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;
}

if still looking for answer, this worked for me

My Input : 2020-12-08T10:36:53.939+05:30
My Output : Tue Dec 08 10:36:53 IST 2020

You can convert this date to any format you need !

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;
}
王权女流氓 2024-10-16 01:24:26

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

If you want to parse it using straight JDK, i believe it should be parseable using the JAXB utils, see DatatypeFactory.newXMLGregorianCalendar or DatatypeConverter.parseDateTime.

何处潇湘 2024-10-16 01:24:26

使用 JodaTime

作为 @Pangea 建议使用 JodaTime 的更具体示例,这就是您可以使用的:

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

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

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

希望对其他人有帮助。

太平绅士

Use JodaTime

As a more concrete example to @Pangea's suggestion to use JodaTime, this is what you could use:

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

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

This correctly recognizes the UTC timezone. I haven't tried it with milliseconds in the string timestamp, but I'm confident it'll work just as well.

Hope that helps others.

JP

深海不蓝 2024-10-16 01:24:26

两种解决方案:

  • OffsetDateTime(Java 8 中内置)
  • joda (所有强大的日期 - 第三方库)

OffsetDateTime 显然是一个更好的选择,但是如果 joda 在相当长的一段时间内已被证明非常强大,并且如果有人更喜欢使用它,那么下面的代码有两者的示例

方法的示例,下面给出了两种方法的代码示例:

public class Demo {
public static void jodaTimeStuff(String dateString, DateTimeZone dtz) {
    System.out.println(StringUtils.leftPad(dateString, 29, " ") + "\t------->\t" + ISODateTimeFormat.dateTime().parseDateTime(dateString).toDateTime(dtz));
    System.out.println(StringUtils.leftPad(dateString, 29, " ") + "\t------->\t" + OffsetDateTime.parse(dateString).toZonedDateTime());
}
public static void main(String[] args) throws Exception {
    jodaTimeStuff("2010-03-01T08:00:00.000Z", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T08:00:00.000Z", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2010-03-01T00:00:00.000-08:00", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T00:00:00.000-08:00", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2010-03-01T00:00:00.000+05:30", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T00:00:00.000+05:30", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2021-11-15T02:27:24.540288Z", DateTimeZone.UTC);
    jodaTimeStuff("2021-11-15T02:27:24.540288Z", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
}

}

输出:

     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00:00.000Z
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00Z
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T13:30:00.000+05:30
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00Z
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T08:00:00.000Z
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T00:00-08:00
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T13:30:00.000+05:30
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T00:00-08:00
2010-03-01T00:00:00.000+05:30   ------->    2010-02-28T18:30:00.000Z
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00+05:30
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00:00.000+05:30
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00+05:30
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540Z
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540288Z
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T07:57:24.540+05:30
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540288Z

示例代码中使用的一些依赖项(一个仅用于格式化,另一个用于 joda:

    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.10.13</version>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.8</version>
    </dependency>

Dua me yaad rakhna(请在祈祷中记住我)

Two solutions:

  • OffsetDateTime (inbuilt in Java 8)
  • joda (the all mighty of dates - a 3rd party library)

OffsetDateTime is clearly a better option here, but if joda has been proven to be quite powerful from quite some time now and if someone prefers to use that then below code has sample of both

Code Sample of both approaches are given below:

public class Demo {
public static void jodaTimeStuff(String dateString, DateTimeZone dtz) {
    System.out.println(StringUtils.leftPad(dateString, 29, " ") + "\t------->\t" + ISODateTimeFormat.dateTime().parseDateTime(dateString).toDateTime(dtz));
    System.out.println(StringUtils.leftPad(dateString, 29, " ") + "\t------->\t" + OffsetDateTime.parse(dateString).toZonedDateTime());
}
public static void main(String[] args) throws Exception {
    jodaTimeStuff("2010-03-01T08:00:00.000Z", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T08:00:00.000Z", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2010-03-01T00:00:00.000-08:00", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T00:00:00.000-08:00", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2010-03-01T00:00:00.000+05:30", DateTimeZone.UTC);
    jodaTimeStuff("2010-03-01T00:00:00.000+05:30", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
    jodaTimeStuff("2021-11-15T02:27:24.540288Z", DateTimeZone.UTC);
    jodaTimeStuff("2021-11-15T02:27:24.540288Z", DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Kolkata")));
}

}

Output:

     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00:00.000Z
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00Z
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T13:30:00.000+05:30
     2010-03-01T08:00:00.000Z   ------->    2010-03-01T08:00Z
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T08:00:00.000Z
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T00:00-08:00
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T13:30:00.000+05:30
2010-03-01T00:00:00.000-08:00   ------->    2010-03-01T00:00-08:00
2010-03-01T00:00:00.000+05:30   ------->    2010-02-28T18:30:00.000Z
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00+05:30
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00:00.000+05:30
2010-03-01T00:00:00.000+05:30   ------->    2010-03-01T00:00+05:30
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540Z
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540288Z
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T07:57:24.540+05:30
  2021-11-15T02:27:24.540288Z   ------->    2021-11-15T02:27:24.540288Z

Some dependencies used in the sample code (one is just for formatting and another one is for joda:

    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.10.13</version>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.8</version>
    </dependency>

Dua me yaad rakhna (Please remember me in your prayers) ????????

眼睛会笑 2024-10-16 01:24:26

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

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

不确定哪些设置会影响此,但有一个 有关 Java 时区的 Oracle 常见问题解答
它可能是 RHEL 中的 user.timezone 系统属性或 /etc/localtime 符号链接。

The question should be where requiredTimeStamp is coming from and in which format. Is it entered by a user, or read from another program? Which component creates the date in the String representation?

The format "2010-12-27T10:50:44.000-08:00" looks like standardized format ISO-8601
It should be parseable with the pattern yyyy-MM-dd'T'HH:mm:ss.SSSZ

Not sure which settings affect this, but there is an Oracle FAQ about Java TimeZones.
It may be user.timezone system property or the /etc/localtime symlink in RHEL.

梦里°也失望 2024-10-16 01:24:26

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

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

SimpleDateFormat only accepts -0800 or GMT-08:00 as the timezone.

It seems the ISO 8601 format can not be parsed with SimpleDateFormat. Maybe you should have a look at Apache Commons Lang's FastDateFormat. It is compatible with SimpleDateFormat but accepts the ZZ pattern for the timezone that should parse the timezone format you need. DateFormatUtils contains some example constants that look like the pattern you need, just without the milliseconds (for example ISO_DATETIME_TIME_ZONE_FORMAT).

日记撕了你也走了 2024-10-16 01:24:26

尝试将其更改为小写 z。

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

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

Try to change it to lower case z.

z processes most of the common general timezone syntax, while Z uses stricter RFC 822 time zone with 4 digits.

Although its documented that both should parse 'General timezone settings', it might make the difference in your case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文