使用TimeZone信息的Joda DateTime

时间:2015-10-02 08:46:35

标签: datetime timezone jodatime

我有以下内容:

val startWithTZ = new DateTime("2016-10-01T00:00:00", DateTimeZone.UTC)
val endWithTZ = new DateTime("2016-10-01T11:00:00", DateTimeZone.UTC)
val intervalWithTZ = new Interval(startWithTZ, endWithTZ)

val startWithoutTZ = new DateTime("2016-10-01T00:00:00")
val endWithoutTZ = new DateTime("2016-10-01T11:00:00")
val intervalWithoutTZ = new Interval(startWithoutTZ, endWithoutTZ)

有了这个,我现在做以下事情:

val utcInterval = new Interval(intervalWithoutTZ.getStart.toDateTime(DateTimeZone.UTC),
intervalWithoutTZ.getEnd.toDateTime(DateTimeZone.UTC))

我在utcInterval中看到的并不是我所期待的:

2016-09-30T22:00:00.000Z/2016-10-01T09:00:00.000Z

这是为什么?我期待utcInterval:

2016-10-01T00:00:00.000Z/2016-10-01T11:00:00.000Z

这是我使用Scala REPL时得到的结果:

scala> import org.joda.time._
import org.joda.time._

scala> val startWithoutTZ = new DateTime("2016-10-01T00:00:00")
startWithoutTZ: org.joda.time.DateTime = 2016-10-01T00:00:00.000+02:00

scala> val endWithoutTZ = new DateTime("2016-10-01T11:00:00")
endWithoutTZ: org.joda.time.DateTime = 2016-10-01T11:00:00.000+02:00

scala> val intervalWithoutTZ = new Interval(startWithoutTZ, endWithoutTZ)
intervalWithoutTZ: org.joda.time.Interval = 2016-10-01T00:00:00.000+02:00/2016-10-01T11:00:00.000+02:00

scala> val utcInterval = new Interval(intervalWithoutTZ.getStart.toDateTime(DateTimeZone.UTC),
     | intervalWithoutTZ.getEnd.toDateTime(DateTimeZone.UTC))
utcInterval: org.joda.time.Interval = 2016-09-30T22:00:00.000Z/2016-10-01T09:00:00.000Z

scala> 

为什么不呢?

2 个答案:

答案 0 :(得分:1)

从逻辑上讲,我一直觉得Interval应该在两个Instant值而不是两个DateTime值之间。但是,Joda Time API就是它。

从两个Interval值创建DateTime时,结束时间将转换为开始时间的时区。在您的情况下,这实际上并不需要做任何事情,因为intervalWithTZ他们都是UTC,而intervalWithoutTZ他们都在你的系统默认时区。此处的命名不准确,因为即使您没有指定一个值,时区中的所有值都是DateTime始终有一个时区;对于没有时区的值,您需要LocalDateTime

因此,我们可以摆脱您的intervalWithoutTZ,只需将您的代码编写为:

DateTime startInDefaultZone = new DateTime("2016-10-01T00:00:00")
DateTime endInDefaultZone = new DateTime("2016-10-01T11:00:00")

val utcInterval = new Interval(startInDefaultZone.toDateTime(DateTimeZone.UTC),
                               endInDefaultZone.toDateTime(DateTimeZone.UTC));

根本不会改变结果...但基本点是你要转换DateTime" 2016-10-01T00:00:00您的系统默认时区"到UTC ...并且可能你的默认时区比UTC晚了2个小时,所以UTC的上午11点是当地时间早上9点等。

简而言之,我们实际上可以在这里完全摆脱间隔 - 您所看到的内容可以更简单地显示为:

DateTime startInDefaultZone = new DateTime("2016-10-01T00:00:00")
DateTime startInUtc = startInDefaultZone.toDateTime(DateTimeZone.UTC);

您似乎期望2016-10-01T00:00:00Z,但它实际上是startInDefaultZone代表的时刻,但以UTC"表示。在您的机器上是2016-10-01T02:00:00Z。

如果确实想要更改时区而不更改本地值"您可以使用withZoneRetainFields,例如

DateTime startInDefaultZone = new DateTime("2016-10-01T00:00:00")
DateTime startInUtc = startInDefaultZone.withZoneRetainFields(DateTimeZone.UTC);

但是,这通常意味着您使用了错误的类型,并且应该使用LocalDateTime。在精心设计的系统中,它很少是有用的操作。

答案 1 :(得分:0)

我猜你的当地时区目前是UTC-2,因为你没有给"没有TZ"变量,Joda-Time给它默认(本地)时区。

要更改时区 à posteriori ,您必须将DateTime转换为LocalDateTime对象,然后将其转换回{{1使用正确的时区,这里是一个在Java中重用代码的示例。

<强> EDIT2: 正如@JonSkeet所建议的那样,最好直接在DateTime对象上使用DateTime.withZoneRetainFields(DateTimeZone)而不是转换它。

DateTime

输出:

  

2016-10-01T00:00:00.000Z / 2016-10-01T11:00:00.000Z

修改

正如@JonSkeet在评论中提到的那样,你得到了奇怪的结果,请查阅他的评论以纠正你的输出。