如何在 Java 8 (Scala) 中将日期时间字符串转换为长(UNIX 纪元时间)毫秒
How to convert a date time string to long (UNIX Epoch Time) Milliseconds in Java 8 (Scala)
本题秒解案例:
但是如果我想要毫秒,我似乎必须使用
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.atZone(ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0)))
.toInstant().toEpochMilli
这对于我在另一个问题中详述的 4 个问题来说是丑陋的(我不喜欢的主要是魔术文字 "UTC"
和魔术数字 0
)。
不幸的是以下不编译
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.toEpochMilliSecond(ZoneOffset.UTC)
因为toEpochMilliSecond
不存在
你能不能用LocalDateTime#atOffset and ZoneOffset#UTC?
LocalDateTime.parse(s, dateTimeFormatter).atOffset(ZoneOffset.UTC).toInstant().toEpochMilli()
正如@Andreas 在评论中指出的那样,ZoneOffset
是一个 ZoneId
,因此您可以使用
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli()
在使用 UNIX 纪元时,我建议使用 java.time.Instant
,因为它是为纪元表示而设计的,并且默认情况下会考虑 UTC
,因为它是标准的一部分。
import java.time.Instant
object InstantFormat extends App {
//Instant.parse uses DateTimeFormatter.ISO_INSTANT
println(Instant.parse("2019-03-12T15:15:13.147Z"))
println(Instant.parse("2019-03-12T15:15:13Z"))
println(Instant.parse("2019-03-12T15:15:13Z").toEpochMilli)
println(Instant.parse("2019-03-12T15:15:13Z").getEpochSecond)
println(Instant.ofEpochMilli(1552403713147L))
println(Instant.ofEpochSecond(1552403713L))
}
输出
2019-03-12T15:15:13.147Z
2019-03-12T15:15:13Z
1552403713000
1552403713
2019-03-12T15:15:13.147Z
2019-03-12T15:15:13Z
您可以将 更改为 return epoch millis
static long dateTimeStringToEpoch(String s, String pattern) {
return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
.parse(s, Instant::from).toEpochMilli();
}
或者,如果您甚至想避免构建临时 Instant
:
static long dateTimeStringToEpoch(String s, String pattern) {
return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
.parse(s, ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000
+ta.get(ChronoField.MILLI_OF_SECOND));
}
请注意,DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
和 ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000+ta.get(ChronoField.MILLI_OF_SECOND)
都是可重用的组件,例如你可以做
static final DateTimeFormatter MY_PATTERN
= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneOffset.UTC);
static final TemporalQuery<Long> EPOCH_MILLIS
= ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000+ta.get(ChronoField.MILLI_OF_SECOND);
和
long millis = MY_PATTERN.parse("2018-07-21 18:30", EPOCH_MILLIS);
问题是,您希望在您的应用程序中出现多少种不同的格式字符串。通常,它不会像您必须解析的格式化日期那样频繁更改。创建从格式字符串到准备好的 DateTimeFormatter
的缓存映射可能是有益的。无论如何,lambda 表达式都是单例。
本题秒解案例:
但是如果我想要毫秒,我似乎必须使用
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.atZone(ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0)))
.toInstant().toEpochMilli
这对于我在另一个问题中详述的 4 个问题来说是丑陋的(我不喜欢的主要是魔术文字 "UTC"
和魔术数字 0
)。
不幸的是以下不编译
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.toEpochMilliSecond(ZoneOffset.UTC)
因为toEpochMilliSecond
不存在
你能不能用LocalDateTime#atOffset and ZoneOffset#UTC?
LocalDateTime.parse(s, dateTimeFormatter).atOffset(ZoneOffset.UTC).toInstant().toEpochMilli()
正如@Andreas 在评论中指出的那样,ZoneOffset
是一个 ZoneId
,因此您可以使用
def dateTimeStringToEpoch(s: String, pattern: String): Long =
LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli()
在使用 UNIX 纪元时,我建议使用 java.time.Instant
,因为它是为纪元表示而设计的,并且默认情况下会考虑 UTC
,因为它是标准的一部分。
import java.time.Instant
object InstantFormat extends App {
//Instant.parse uses DateTimeFormatter.ISO_INSTANT
println(Instant.parse("2019-03-12T15:15:13.147Z"))
println(Instant.parse("2019-03-12T15:15:13Z"))
println(Instant.parse("2019-03-12T15:15:13Z").toEpochMilli)
println(Instant.parse("2019-03-12T15:15:13Z").getEpochSecond)
println(Instant.ofEpochMilli(1552403713147L))
println(Instant.ofEpochSecond(1552403713L))
}
输出
2019-03-12T15:15:13.147Z
2019-03-12T15:15:13Z
1552403713000
1552403713
2019-03-12T15:15:13.147Z
2019-03-12T15:15:13Z
您可以将
static long dateTimeStringToEpoch(String s, String pattern) {
return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
.parse(s, Instant::from).toEpochMilli();
}
或者,如果您甚至想避免构建临时 Instant
:
static long dateTimeStringToEpoch(String s, String pattern) {
return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
.parse(s, ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000
+ta.get(ChronoField.MILLI_OF_SECOND));
}
请注意,DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
和 ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000+ta.get(ChronoField.MILLI_OF_SECOND)
都是可重用的组件,例如你可以做
static final DateTimeFormatter MY_PATTERN
= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneOffset.UTC);
static final TemporalQuery<Long> EPOCH_MILLIS
= ta -> ta.getLong(ChronoField.INSTANT_SECONDS)*1000+ta.get(ChronoField.MILLI_OF_SECOND);
和
long millis = MY_PATTERN.parse("2018-07-21 18:30", EPOCH_MILLIS);
问题是,您希望在您的应用程序中出现多少种不同的格式字符串。通常,它不会像您必须解析的格式化日期那样频繁更改。创建从格式字符串到准备好的 DateTimeFormatter
的缓存映射可能是有益的。无论如何,lambda 表达式都是单例。