【问题标题】:Comparing time in java between epoch milliseconds and LocalDateTime比较纪元毫秒和LocalDateTime之间的Java时间
【发布时间】:2018-07-24 17:24:51
【问题描述】:

我有一个以纪元毫秒为单位的时间戳,我想检查它是否在两个 LocalDateTime 戳之间。在 java 中执行此操作的最佳方法是什么?

【问题讨论】:

  • 将两个localDate转换为毫秒并比较longs。
  • 最好的条件是什么?时间?内存?
  • 我正在尝试编写一个适用于多个时区的通用函数,有没有办法在不知道时区的情况下进行这种比较?
  • 极端情况:当夏季时间 (DST) 在秋季结束并且时钟倒转时,相同的 LocalDateTime 会出现两次。如果你的纪元时间介于两者之间,那么它是否在你的两次之间的答案可能是未知的。因此,即使知道时区,我们也无法给出 100% 肯定的答案。当然,您可以决定是否可以忍受这种不确定性。

标签: java date time


【解决方案1】:

一种方法是将毫秒转换为LocalDateTime

LocalDateTime date = Instant.ofEpochMilli(milliseconds)
        .atZone(ZoneId.systemDefault())
        .toLocalDateTime();
LocalDateTime start = LocalDateTime.now().minusMinutes(1);
LocalDateTime end = LocalDateTime.now().plusMinutes(1);

if (date.isAfter(start) && date.isBefore(end)) {
  // date is between start and end
}

【讨论】:

  • 此方法假定 LocalDateTime 旨在使用 UTC。如果它是针对另一个时区的,这将产生不正确的结果。
【解决方案2】:

tl;博士

无法LocalDateTime 与分配时区(或与UTC 的偏移量)之前的某个时刻进行比较。

org.threeten.extra.Interval                     // Represents a span-of-time attached to the timeline, as a pair of `Instant` objects, a pair of moments in UTC.
.of ( 

    myLocalDateTimeStart
    .atZone( ZoneId.of( "Pacific/Auckland" ) )  // Determine a moment by assigning an time zone to a `LocalDateTime` to produce a `ZonedDateTime`, from which we extract an `Instant` to adjust into UTC.
    .toInstant() ,

    myLocalDateTimeStop
    .atZone( ZoneId.of( "Pacific/Auckland" ) )  // Returns a `ZonedDateTime` object.
    .toInstant()                                // From the `ZonedDateTime`, extract a `Instant` object.

)                                               // Returns `Interval` object.
.contains(        
    Instant.ofEpochMilli( 1_532_463_173_752L )  // Parse a count of milliseconds since 1970-01-01T00:00:00Z as a moment in UTC, a `Instant` object.
)                                               // Returns a boolean.             

详情

比较 epoch 毫秒和 LocalDateTime 在 java 中的时间

你不能。这种比较不合逻辑。

LocalDateTime代表一个时刻,不是时间线上的一个点。 LocalDateTime 代表在大约 26-27 小时范围内的潜在时刻,即世界各地的时区范围。

因此,除非您将其置于时区的上下文中,否则它没有真正的意义。如果该特定日期和时间在该区域中无效,例如在 Daylight Saving Time (DST) 切换期间或在其他一些此类异常期间,ZonedDateTime 类会调整。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ; 
ZonedDateTime zdt = myLocalDateTime.atZone( z ) ;

为了进行比较,我们将通过从您的开始和停止 ZonedDateTime 对象中提取 Instant 对象来调整为 UTC。

Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;

现在将自 1970 年第一时刻的纪元参考以来的毫秒数解析为 InstantInstant 具有更精细的分辨率,纳秒级。

Instant instant = Instant.ofEpochMilli( 1_532_463_173_752L ) ;

比较以查看您的纪元毫秒是否代表我们停止和开始Instant 对象之间的时刻。通常在日期时间工作中,Half-Open 方法是最好的,其中开头是inclusive,而结尾是exclusive

提示:说“等于或之后”的更简短的说法是说“不在之前”。

boolean inRange = ( ! instant.isBefore( start ) ) && instant.isBefore( stop ) ;

为了使这项工作更容易,请将ThreeTen-Extra 库添加到您的项目中。使用Interval 类。

Interval interval = Interval.of( start , stop ) ;
boolean inRange = interval.contains( instant ) ;  // Uses Half-Open approach to comparisons.

提示:如果您打算跟踪时刻,则根本不应该使用 LocalDateTime 类。相反,请使用 InstantOffsetDateTimeZonedDateTime 类。


关于java.time

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

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

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

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

从哪里获得 java.time 类?

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

【讨论】:

  • 关于 java.time 的推销似乎真的没有必要。
  • @shmosel 考虑到上下文,我也会这么认为。但通常当我省略该部分时,我得到 cmets 询问“这些类是什么?”、“我从哪里得到它们?”、“这比 Joda-Time 好吗?”、“但我在 26 岁之前使用 Android?!” :-/
  • 也许你可以链接到某个地方的维基。此外,OP 显然已经在使用 java.time。
  • @shmosel 提出查询的是其他读者,而不是 OP。我根据经验发言,因为我省略了我的一些日期时间答案的部分,出于与您相同的担忧。我已经多次重写该部分以尽可能紧凑。
  • @BasilBourque 很好的答案
【解决方案3】:

在比较Instant(自纪元)和LocalDateTime 时,您始终需要考虑当地时间的时区。这是一个例子:

Instant now = Instant.now();

LocalDateTime start = LocalDateTime.of(2018, 7, 24, 0, 0);
LocalDateTime end = LocalDateTime.of(2018, 7, 24, 23, 59);

final ZoneId myLocalZone = ZoneId.of("Europe/Paris");

if (now.isAfter(start.atZone(myLocalZone).toInstant()) 
        && now.isBefore(end.atZone(myLocalZone).toInstant())) {

    // the instant is between the local date-times

}

【讨论】:

    猜你喜欢
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2012-03-08
    • 2018-04-11
    • 1970-01-01
    相关资源
    最近更新 更多