我有以下内容:
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 Time API就是这样的。
从两个DateTime
值创建Interval
时,结束时间被转换为开始时间所在的时区。在您的情况下,这实际上不需要做任何事情,因为对于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));
这根本不会改变结果…但基本要点是,您正在将"2016-10-01T00:00:00"的DateTime
转换为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
。在一个设计良好的系统中,它很少是一个有用的操作。
我猜你的本地时区是UTC-2的时刻,因为你没有给时区信息"withoutTZ"变量,Joda-Time给它默认的(本地)时区。
为了更改时区,您必须将DateTime
转换为LocalDateTime
对象,然后将其转换回具有正确时区的DateTime
,下面是在Java中重用代码的示例。
EDIT2: 正如@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 - 01 t00:00:00.000z/2016 - 10 - 01 t11:00:00.000z
正如@JonSkeet在他的评论中提到的,你会得到奇怪的结果,请参考他的评论来纠正你的输出