java 使用带时区的 Joda 解析日期

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4624992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 07:16:30  来源:igfitidea点击:

Parsing date with Joda with time zone

javadatetimedatetimezonejodatime

提问by wilfried

I have two timestamps which describe the same instant of time in two different formats.

我有两个时间戳,它们以两种不同的格式描述同一时刻。

2010-10-03 18:58:07and 2010-10-03T16:58:07.000+02:00.

2010-10-03 18:58:072010-10-03T16:58:07.000+02:00

I parse the timestamps with two different date formatters with Joda-Time. In the end I want to have two DateTime objects that are equal in terms of being the same instant of time.

我用 Joda-Time 用两个不同的日期格式化程序解析时间戳。最后,我想要两个 DateTime 对象,它们在同一时刻是相等的。

The DateFormatter offers several methods to control time zones and locales but i couldn't get it to work.

DateFormatter 提供了多种方法来控制时区和语言环境,但我无法让它工作。

This is the code that i would like to work:

这是我想要工作的代码:

    final String date1 = "2010-10-03 18:58:07"; // Europe/Berlin local time
    final DateTimeFormatter formatter1 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    final DateTime dateTime1 = formatter1.parseDateTime(date1);

    final String date2 = "2010-10-03T16:58:07.000+02:00"; // Europe/Berlin local time with time zone
    final DateTimeFormatter formatter2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    final DateTime dateTime2 = formatter2.parseDateTime(date2);

    Assert.assertTrue(dateTime1.isEqual(dateTime2));

采纳答案by jarnbjo

If your default time zome is Europe/Berlin, 2010-10-03 18:58:07 corresponds to 2010-10-03T16:58:07.000+00:00.

如果您的默认时区是欧洲/柏林,则 2010-10-03 18:58:07 对应于 2010-10-03T16:58:07.000+00:00。

You probably misunderstand the time zone field in the string representation. Your time stamp 2010-10-03T16:58:07.000+02:00 means that "it is 16:58:07 in a time zone with a +2 hour offset from GMT), or in an other wording "it is now 16:58:07 in Berlin". I assume that you expected it to mean that it's 16:58:07 GMT?

您可能误解了字符串表示中的时区字段。您的时间戳 2010-10-03T16:58:07.000+02:00 意味着“它是 16:58:07 在与格林威治标准时间有 +2 小时偏移的时区中),或者换句话说“现在是 16 :58:07 在柏林”。我假设您认为它意味着格林威治标准时间 16:58:07?

回答by MicSim

Your two timestamps don't represent the same instant in time (as jambjo already remarked). See Time zone as offsets from UTCon wikipedia.

您的两个时间戳不代表同一时刻(正如 jambjo 已经指出的那样)。见时区从UTC偏移维基百科。

Also see the parseDateTimedocumentation on how it works. If you don't provide any time zone, then the default time zone will be applied (that is Berlin time zone UTC+2 if you are there). So:

另请参阅有关其工作原理的parseDateTime文档。如果您不提供任何时区,则将应用默认时区(如果您在那里,则为柏林时区 UTC+2)。所以:

  • 2010-10-03 18:58:07becomes 2010-10-03T18:58:07.000+02:00(18:58 in Berlin with offset of 2 hours to UTC, that means 16:58 in UTC) as expected.
  • 2010-10-03T16:58:07.000+02:00stays as it is, because there is a time zone provided (i.e. 16:58 in Berlin with offset of 2 hours to UTC, that means 14:58 in UTC)
  • 2010-10-03 18:58:07变为2010-10-03T18:58:07.000+02:00(柏林的 18:58,与 UTC 的偏移量为 2 小时,这意味着 UTC 的 16:58)正如预期的那样。
  • 2010-10-03T16:58:07.000+02:00保持原样,因为提供了一个时区(即柏林的 16:58 与 UTC 的偏移量为 2 小时,这意味着 UTC 的 14:58)

Hope you got the idea. You will need to adjust the times with the withZonemethod to get the desired results.

希望你有这个想法。您需要使用withZone方法调整时间以获得所需的结果。

回答by Basil Bourque

tl;dr

tl;博士

Use the modern java.timeclasses that supplanted Joda-Time.

使用取代Joda-Time的现代java.time类。

LocalDateTime                                   // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. *Not* a moment, *not* a point on the timeline.
.parse(                                         // Parse text into a date-time value.
    "2010-10-03 18:58:07".replace( " " , "T" )  // Replace SPACE in middle with a `T` to comply with ISO 8601 standard used by default in *java.time* when parsing/generating strings.
)                                               // Returns a `LocalDateTime` object.
.atZone(                                        // Assign the time zone we know for certain was intended for this input. 
    ZoneId.of( "Europe/Moscow" )                // Real time zones are named in `Continent/Region` format, never 2-4 letter codes such as CST, PST, IST, CEST, etc.
)                                               // Returns a `ZonedDateTime` object, a date with time-of-day and with a time zone assigned to determine a moment.
.toInstant()                                    // Adjust from time zone to UTC. 
.equals(
    OffsetDateTime                              // Represent a date and time-of-day with an offset-from-UTC but not a full time zone.
    .parse( "2010-10-03T16:58:07.000+02:00" )   // Parse a standard ISO 8601 string.
    .toInstant()                                // Adjust from offset to UTC (in other words, an offset of zero hours-minutes-seconds). 
)                                               // Returns `boolean`. 

true

真的

Details

细节

The Answer by jarnbjois correct in that you misunderstood the meanings of the offset-from-UTCand time zonevalues.

jarnbjo答案是正确的,因为您误解了offset-from-UTC时区值的含义。

Now in 2018, the Joda-Timeproject is in maintenance-mode. That project's principal author, Stephen Colebourne, went on to found JSR 310and author its implementation, the java.timeclasses found in OpenJDK.

现在在 2018 年,Joda-Time项目处于维护模式。该项目的主要作者 Stephen Colebourne 继续创建了JSR 310并编写了它的实现,即OpenJDK 中java.time类。

First input

第一次输入

Your input string 2010-10-03 18:58:07is nearly in standard ISO 8601format. To comply, replace the SPACE in the middle with a T.

您的输入字符串2010-10-03 18:58:07几乎采用标准ISO 8601格式。为了遵守,请将中间的 SPACE 替换为T.

String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;

That string lacks any indicator of time zone or offset-from-UTC. So parse as a LocalDateTime.

该字符串缺少时区或UTC 偏移量的任何指示符。所以解析为LocalDateTime.

LocalDateTime ldt = LocalDateTime.parse( input1 ) ;

This value does notrepresent a moment, is nota point on the timeline. Without the context of a zone or offset, it could be any of many moments within a range of about 26-27 hours, the range of time zones around the globe.

此值也不会代表了一下,是不是在时间轴上的一个点。如果没有区域或偏移的上下文,它可以是大约 26-27 小时范围内的许多时刻中的任何一个,即全球时区的范围。

In your comments you revealed that apparently that input string was meant to represent a date and time-of-day in the Europe/Moscowtime zone. So we can assign that zone to determine a moment, a point on the timeline.

在您的评论中,您透露显然该输入字符串旨在表示时区中的日期和时间Europe/Moscow。所以我们可以分配那个区域来确定一个时刻,时间线上的一个点。

ZoneId zMoscow = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdtMoscow = ldt.atZone( zMoscow ) ;  // Determine a moment by assigning a time zone.

zdtMoscow.toString(): 2010-10-03T18:58:07+04:00[Europe/Moscow]

zdtMoscow.toString(): 2010-10-03T18:58:07+04:00[欧洲/莫斯科]

Second input

第二个输入

Your second input 2010-10-03T16:58:07.000+02:00complies with standard ISO 8601format.

您的第二个输入2010-10-03T16:58:07.000+02:00符合标准ISO 8601格式。

This input carries an offset-from-UTC of two hours ahead of UTC. So this string represents the time-of-day of 14:58:07 in UTC.

此输入比 UTC 提前两小时从 UTC 偏移。因此,此字符串表示 UTC 中 14:58:07 的时间。

We can parse as a OffsetDateTimeto respect the given offset.

我们可以解析为 aOffsetDateTime以尊重给定的偏移量。

OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;

odt2.toString(): 2010-10-03T16:58:07+02:00

odt2.toString(): 2010-10-03T16:58:07+02:00

Compare

比较

Do these two inputs represent the same moment, the same point on the timeline?

这两个输入是否代表同一时刻,时间线上的同一点?

One way to compare is by adjusting both to UTC. An Instantis always in UTC, by definition.

一种比较方法是将两者都调整为 UTC。根据Instant定义,An始终采用 UTC。

Tip: Get in the habit of thinking, working, storing, exchanging, and logging in UTC. Think of UTC as The One True Time.

提示:养成在UTC中思考、工作、存储、交流和登录的习惯。将 UTC 视为唯一的真实时间

Instant instant1 = zdtMoscow.toInstant() ;  // Adjust from time zone to UTC.
Instant instant2 = odt2.toInstant() ;       // Adjust from offset to UTC.

boolean equality = instant1.equals( instant2 );

When run, we see results with a Zon the end. That means UTC, and is pronounced Zulu. And, indeed, we see these two values represent the same moment, almost 3 PM in UTC.

运行时,我们会看到Z结尾带有 a的结果。这意味着UTC,并发音为Zulu。事实上,我们看到这两个值代表同一时刻,UTC 时间几乎是下午 3 点。

instant1.toString(): 2010-10-03T14:58:07Z

instant2.toString(): 2010-10-03T14:58:07Z

equality: true

Instant1.toString(): 2010-10-03T14:58:07Z

Instant2.toString(): 2010-10-03T14:58:07Z

平等:真的



About java.time

关于java.time

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

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

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

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

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

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

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

Where to obtain the java.time classes?

从哪里获得 java.time 类?

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

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Mathieu Laporte

I had the same issue as you and the best way I found is to parse the data. I originally had this format: 2018-01-22 09:25:14.000 +0000

我和你有同样的问题,我发现最好的方法是解析数据。我原来有这种格式:2018-01-22 09:25:14.000 +0000

Simply select the column and click on "Text to Columns" in Data's tab.

只需选择该列,然后单击“数据”选项卡中的“文本到列”。

I used Delimited with space to parse this format in 3 different columns. So at the end, I have;

我使用带空格的分隔来解析 3 个不同列中的这种格式。所以最后,我有;

Col A 2018-01-22 Col B 09:25:14.000 Col C +0000

Col A 2018-01-22 Col B 09:25:14.000 Col C +0000