【问题标题】:JodaTime Comparing two dates with different time zoneJodaTime比较具有不同时区的两个日期
【发布时间】:2015-06-10 10:00:21
【问题描述】:

如果我将两个 DateTime 与两个不同的时区进行比较,有问题,或者我应该让他在同一个时区?

例子:

DateTimeZone a = new DateTimeZone("Pacific/Kiritimati");
    DateTimeZone b = new DateTimeZone("Pacific/Gambier");

    DateTime dateOne = new DateTime(a);
    DateTime dateTwo = new DateTime(b);

    if (dateOne.compareTO(dateTwo) == 0) {
        // yes
    } else {
        // no
    }

谢谢你。 (对不起我的英语不好)

【问题讨论】:

  • 您决定如何比较。原则上,此类时间戳有两个标准(本地和全局)。要么比较时刻(在全局时间线上),要么只比较与忽略时区相关的本地时间戳。无论您决定什么,它都必须适合您的具体用例。您使用的compareTo()-方法只比较瞬间,而不是本地时间戳表示。也许这对你来说已经足够了。
  • 重要提示:如果您想使用表达式dateOne.compareTO(dateTwo) == 0 比较两个瞬间,那么您可能会体验到它几乎总是false,因为DateTime 的时间部分可以低至毫秒。如果您的DateTime-objects 的来源是时钟(通常发出不同的毫秒),则尤其如此。
  • 仅供参考,Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。见Tutorial by Oracle

标签: java datetime time jodatime


【解决方案1】:

使用 java.time

Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。

您确实可以比较不同时区的日期时间对象。在内部,时刻计算为自 1970-01-01T00:00:00Z 的纪元以来的秒数(加上小数秒)。虽然每个指定时区的挂钟时间看起来不同,但可以将它们的潜在含义视为 UTC 时间线上的一个点。因此,任何一对日期时间对象都可以轻松进行比较。

在 java.time 中,我们使用 ZonedDateTime 来完成这项工作。该类提供isEqualisBeforeisAfter方法进行比较。

ZoneId zP_K = ZoneId.of( "Pacific/Kiritimati" ) ;
ZoneId zP_G = ZoneId.of( "Pacific/Gambier" ) ;

Instant instant = Instant.now() ;  // Current moment in UTC, with resolution up to nanoseconds.

ZonedDateTime zdtP_K = instant.atZone( zP_K ) ;
ZonedDateTime zdtP_G = instant.atZone( zP_G ) ;

Boolean sameMoment = zdtP_K.isEqual( zdtP_G ) ; // Or `isBefore` or `isAfter`.

看到这个code run live at IdeOne.com

instant.toString(): 2017-06-15T12:53:35.276Z

zdtP_K.toString(): 2017-06-16T02:53:35.276+14:00[太平洋/Kiritimati]

zdtP_G.toString(): 2017-06-15T03:53:35.276-09:00[太平洋/甘比尔]

sameMoment: 真

提示:您的大部分思考、业务逻辑、日志记录和数据交换/存储都使用 UTC。将 UTC 视为 The One True Time™,而其他区域只是变体。仅在业务逻辑需要或向用户展示时应用时区。戴上你的程序员在工作帽子,忘记你自己的狭隘时区。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

从哪里获得 java.time 类?

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

【讨论】:

    【解决方案2】:

    人们总是对日期和时区感到困惑。日期(或时间或日期时间)是特定的时间点。这个瞬间在整个宇宙中都是相同的,因此它与时区无关,通常表示为 UTC(通用时间)或 Z(祖鲁时间)。 Timzone 是对 UTC 的修改,用于显示地球上这个特定区域的相对太阳时。通过设置时区,您只是告诉这个日期时间是相对于这个特定时区的,但在内部它仍将表示为 UTC。在这种情况下,如果时区具有不同的 UTC 偏移量,它们应该是不同的。

    【讨论】:

    • 嗯,我无法跟上——就 Joda-Time 而言。 DateTime 类型不仅仅是瞬间。它还引用了特定时区,而不仅仅是 UTC。所以它也知道本地/区域表示。这就是它的compareTo()-方法与equals()不一致的主要原因。顺便说一句:在 Joda-Time 中,LocalDate(纯日历日期)之类的类型不是即时的。
    • 是的,我知道。时间仍然存储为 UTC 并因此进行比较,时区无关紧要。我的意思是 10:00 GMT 与 11:00 GMT+1 相同。我知道LocalDate,但我不明白它与这个问题有什么关系。
    • 我只提到LocalDate 作为反例是因为您的陈述:“日期(或时间或日期时间)是特定的时间瞬间。”否则我们在这里讨论DateTime 类型,这不仅仅是瞬间。
    • “日期(或时间,或日期时间)”不是本地日期/时间。不,你错了,DateTime 精确地代表了一个瞬间:“它代表了时间线上的一个精确点”。 Read the documentation。正如我所说:人们总是对日期和时区感到困惑,但事实上,如果你以正确的方式思考它是非常简单的。
    • 考虑一下纽约和巴黎的两个人何时醒来,谁先醒来的问题。在这里,使用本地时间戳而不是瞬间进行比较是一个有效的选择(当然,通常巴黎在全球时间线上较早,但我们也可以从另一个角度来看当地一天的开始)。正确答案取决于 OP 的用例。这就是我试图通过针对 OP 的评论来表达的内容。如果他想要即时比较,那么他的代码就可以了,但他不应该使用运算符 ==。
    猜你喜欢
    • 1970-01-01
    • 2019-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    相关资源
    最近更新 更多