如何在Java 8(Scala)中将日期时间字符串转换为长整型(UNIX Epoch Time)

8

我希望能够获取一个以普通格式表示的字符串在某个pattern下的 UNIX Epoch 时间 (Posix 时间,Unix 时间),该字符串采用 UTC 格式。请使用 Java 8,不要使用 Joda 或旧版本的 Java。

(如需毫秒级别的时间,请参见How to convert a date time string to long (UNIX Epoch Time) Milliseconds in Java 8 (Scala))

到目前为止,我有以下代码,但我不喜欢它,因为:

  1. 对于最常见的日期操作(转换为 UNIX Epoch 时间),这段代码过于冗长。需要七个方法调用才能实现。
  2. 它必须指定 UTC,但是 UTC 只是一个默认值,为什么我必须在此处明确指定?
  3. 它有一个字符串字面量"UTC"
  4. 它有一个神奇数字ZoneOffset.ofHours(0)

我的最佳代码如下:

def dateTimeStringToEpoch(s: String, pattern: String): Long = 
    LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
      .atZone(ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0)))
      .toInstant().getEpochSeconds

此外,额外的问题是,这种方法是否有效?使用DateTimeFormatter.ofPattern(pattern)创建DateTimeFormatter是否存在任何开销?如果有,为什么?

2
至少有一个UTC常量ZoneOffset.UTC - Flown
3
输入长什么样子? - xingbin
3
“它太冗长了”:这就是为什么在计算机历史的早期就发明了子程序(也称为函数或方法)。 - Henry
2
是的,每次创建DateTimeFormatter可能会有一些开销。如果担心这个问题并且模式相同,请将其设置为常量。您可以安全地这样做,它是线程安全的。每次调用少一个方法调用... - Ole V.V.
大多数编程语言只需要2个或更少的调用(一个用于解析到某些结构,一个用于将结构转换为Unix时间)。在 Unix C 编程中,您只需使用两个调用即可完成,而 C 确实应该成为标准。https://dev59.com/fnNA5IYBdhLWcg3wVcT6#1002631 - samthebest
显示剩余4条评论
3个回答

3
这个更短,只需要3个方法调用:
def dateTimeStringToEpoch(s: String, pattern: String): Long = 
     LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
                  .toEpochSecond(ZoneOffset.UTC)

顺便说一下,我会在dateTimeStringToEpoch之外构建DateTimeFormatter并将其作为方法参数传递:

def dateTimeStringToEpoch(s: String, formatter: DateTimeFormatter): Long = 
     LocalDateTime.parse(s, formatter).toEpochSecond(ZoneOffset.UTC)

经过性能测试,将 DateTimeFormatter 初始化放到方法外部和方法内部相比,初始化在方法外部的性能只有略微提升(仅增加了2倍的因素)。

scala> val pattern = "yyyy/MM/dd HH:mm:ss"
pattern: String = yyyy/MM/dd HH:mm:ss

scala>   time(() => randomDates.map(dateTimeStringToEpoch(_, pattern)))
Took: 1216

scala>   time(() => randomDates.map(dateTimeStringToEpochFixed))
Took: 732

这里没有 .toEpochMilli 方法 :( - samthebest
1
此解决方案所需的库:import java.time.{LocalDateTime, ZoneOffset} import java.time.format.DateTimeFormatter - Ignacio Alorre

3
您可以使用以下Java代码的等效代码:
static long dateTimeStringToEpoch(String s, String pattern) {
    return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
        .parse(s, p -> p.getLong(ChronoField.INSTANT_SECONDS));
}

当然,处理DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)意味着需要进行一些工作,如果多次遇到相同的模式字符串,则可以避免这些工作。这种工作量是否与您的应用程序相关取决于它在此操作之外执行的任务。

2
非常好!只需要4个方法调用而不是7个(我不同意提问者认为应该只有1个的观点;在转换中,我们想要明确指定一些事情)。 - Ole V.V.
2
@OleV.V. …而DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)的结果可以被重复使用,因此实际操作只需进行一次parse调用,返回所需值而不是需要转换的内容。 - Holger

2

你可以尝试使用以下代码,根据你的说法,它正在解析UTC时间,这里是一个示例

Instant.parse("2019-01-24T12:48:14.530Z").getEpochSecond

翻译:此代码用于解析UTC时间并获取秒数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接