带有时区信息的 Joda DateTime
Joda DateTime with TimeZone Information
我有以下内容:
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>
为什么不是?
从逻辑上讲,我一直认为 Interval
应该介于两个 Instant
值之间,而不是两个 DateTime
值之间。然而,Joda 时间 API 就是这样。
当您从两个 DateTime
值创建 Interval
时,结束时间将转换为开始时间的时区。在你的情况下,这实际上不需要做任何事情,因为对于 intervalWithTZ
它们都在 UTC 中,对于 intervalWithoutTZ
它们都在你的系统默认时区中。您的命名在这里不准确,因为所有值 都是 在一个时区中,即使您没有指定一个。 A 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,但它实际上是 "the instant in time represented by startInDefaultZone
, but expressed in UTC",在你的机器上是 2016-10-01T02:00:00Z。
如果您真的想要"change time zone without changing local values",您可以使用withZoneRetainFields
,例如
DateTime startInDefaultZone = new DateTime("2016-10-01T00:00:00")
DateTime startInUtc = startInDefaultZone.withZoneRetainFields(DateTimeZone.UTC);
然而,这通常意味着您一开始就使用了错误的类型,应该使用 LocalDateTime
。在设计良好的系统中,它很少是有用的操作。
我猜你的本地时区目前是 UTC-2,因为你没有给 "withoutTZ" 变量提供时区信息,Joda-Time 给它默认的(本地)时区。
为了更改时区 à posteriori, you have to convert your DateTime
to a LocalDateTime
对象,然后将其转换回具有正确时区的 DateTime
,这里有一个在 [=36= 中重用您的代码的示例].
编辑2:
正如@JonSkeet 所建议的,最好直接在 DateTime
对象上使用 DateTime.withZoneRetainFields(DateTimeZone)
而不是转换它。
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
public class HelloWorld {
public static void main(String[] args) {
DateTime startWithTZ = new DateTime("2016-10-01T00:00:00", DateTimeZone.UTC);
DateTime endWithTZ = new DateTime("2016-10-01T11:00:00", DateTimeZone.UTC);
Interval intervalWithTZ = new Interval(startWithTZ, endWithTZ);
DateTime startWithoutTZ = new DateTime("2016-10-01T00:00:00");
DateTime endWithoutTZ = new DateTime("2016-10-01T11:00:00");
Interval intervalWithoutTZ = new Interval(startWithoutTZ, endWithoutTZ);
Interval utcInterval =
new Interval(intervalWithoutTZ.getStart().withZoneRetainFields(DateTimeZone.UTC),
intervalWithoutTZ.getEnd().withZoneRetainFields(DateTimeZone.UTC));
System.out.println(utcInterval);
}
}
输出:
2016-10-01T00:00:00.000Z/2016-10-01T11:00:00.000Z
编辑:
正如@JonSkeet 在他的评论中提到的那样,您得到了奇怪的结果,请查阅他的评论以更正您的输出。
我有以下内容:
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>
为什么不是?
从逻辑上讲,我一直认为 Interval
应该介于两个 Instant
值之间,而不是两个 DateTime
值之间。然而,Joda 时间 API 就是这样。
当您从两个 DateTime
值创建 Interval
时,结束时间将转换为开始时间的时区。在你的情况下,这实际上不需要做任何事情,因为对于 intervalWithTZ
它们都在 UTC 中,对于 intervalWithoutTZ
它们都在你的系统默认时区中。您的命名在这里不准确,因为所有值 都是 在一个时区中,即使您没有指定一个。 A 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,但它实际上是 "the instant in time represented by startInDefaultZone
, but expressed in UTC",在你的机器上是 2016-10-01T02:00:00Z。
如果您真的想要"change time zone without changing local values",您可以使用withZoneRetainFields
,例如
DateTime startInDefaultZone = new DateTime("2016-10-01T00:00:00")
DateTime startInUtc = startInDefaultZone.withZoneRetainFields(DateTimeZone.UTC);
然而,这通常意味着您一开始就使用了错误的类型,应该使用 LocalDateTime
。在设计良好的系统中,它很少是有用的操作。
我猜你的本地时区目前是 UTC-2,因为你没有给 "withoutTZ" 变量提供时区信息,Joda-Time 给它默认的(本地)时区。
为了更改时区 à posteriori, you have to convert your DateTime
to a LocalDateTime
对象,然后将其转换回具有正确时区的 DateTime
,这里有一个在 [=36= 中重用您的代码的示例].
编辑2:
正如@JonSkeet 所建议的,最好直接在 DateTime
对象上使用 DateTime.withZoneRetainFields(DateTimeZone)
而不是转换它。
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
public class HelloWorld {
public static void main(String[] args) {
DateTime startWithTZ = new DateTime("2016-10-01T00:00:00", DateTimeZone.UTC);
DateTime endWithTZ = new DateTime("2016-10-01T11:00:00", DateTimeZone.UTC);
Interval intervalWithTZ = new Interval(startWithTZ, endWithTZ);
DateTime startWithoutTZ = new DateTime("2016-10-01T00:00:00");
DateTime endWithoutTZ = new DateTime("2016-10-01T11:00:00");
Interval intervalWithoutTZ = new Interval(startWithoutTZ, endWithoutTZ);
Interval utcInterval =
new Interval(intervalWithoutTZ.getStart().withZoneRetainFields(DateTimeZone.UTC),
intervalWithoutTZ.getEnd().withZoneRetainFields(DateTimeZone.UTC));
System.out.println(utcInterval);
}
}
输出:
2016-10-01T00:00:00.000Z/2016-10-01T11:00:00.000Z
编辑:
正如@JonSkeet 在他的评论中提到的那样,您得到了奇怪的结果,请查阅他的评论以更正您的输出。