如何在java中将1413225446.92000
之类的纪元转换为ZonedDateTime
给出的代码需要 long 值,因此这将为上面给出的值抛出NumberFormatException
。
ZonedDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(dateInMillis)), ZoneId.of(TIME_ZONE_PST));
答案 0 :(得分:1)
将数字拆分为一对64位长整数:
将这些数字传递给工厂方法Instant.ofEpochSecond(long epochSecond, long nanoAdjustment)
手持Instant
后,继续指定时区以获取ZonedDateTime
。
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
答案 1 :(得分:1)
在负时间戳的特殊情况下(即在纪元之前),在此处扩展Basil和Ole的答案。那有可能吗?这是Jon Skeet在“关于java.util.Date的全部”中写的内容:
Date类使用“自Unix时代以来的毫秒数”,即 由getTime()返回的值,并由Date(long)设置 构造函数或setTime()方法。当月亮走过之前 Unix时期,该值为负:实际上是-14159020000。
Ole的答案之间唯一真正的区别(除了一些额外的断言)是,在这里,如果日期字符串以负号开头,我们不会反转nanos上的符号。原因是,当将nanos传递到Instant constructor时,这是 adjustment ,因此,如果我们将nanos发送为负数,则实际上会将秒数调整回来,因此整个ZonedDateTime值都偏离了纳秒级。
这来自JavaDoc,请注意有趣的行为:
此方法允许传递任意数量的纳秒。 工厂将更改秒和纳秒的值 为了确保存储的纳秒在0到 999,999,999。例如,以下结果将导致 同一时刻:
EpochSecond(3,1);
Instant.ofEpochSecond(4,-999_999_999);
Instant.ofEpochSecond(2,1000_000_001);
因此,第二个参数nanos,我们没有设置值,而是调整。因此,与正向时间戳记(时期之后)相同,我们要发送实际的nanos。
以Ole的代码为基础并添加上述更改:
String strDateZoned = "Jul 20 1969 21:56:20.599 CDT"; // yes, should use America/Chicago here as Ole points out
DateTimeFormatter dtfFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss.SSS zzz");
ZonedDateTime originalZoned = ZonedDateTime.parse(strDateZoned, dtfFormatter);
long epochSeconds = originalZoned.toInstant().getEpochSecond();
int nanoSeconds = originalZoned.toInstant().getNano();
String dateInMillis = epochSeconds + "." + nanoSeconds;
String[] secondsAndFraction = dateInMillis.split("\\.");
int nanos = 0;
if (secondsAndFraction.length > 1) { // there’s a fractional part
// extend fractional part to 9 digits to obtain nanoseconds
String nanosecondsString
= (secondsAndFraction[1] + "000000000").substring(0, 9);
nanos = Integer.parseInt(nanosecondsString);
}
ZonedDateTime zdt = Instant
.ofEpochSecond(Long.parseLong(secondsAndFraction[0]), nanos)
.atZone(ZoneId.of("America/Chicago"));
String formattedZdt = dtfFormatter.format(zdt);
System.out.println("zoneDateTime expected = " + strDateZoned);
System.out.println("zoneDateTime from millis = " + formattedZdt);
assertEquals("date in millis is wrong", "-14159020.599000000", dateInMillis);
assertEquals("date doesn't match expected",strDateZoned, dtfFormatter.format(zdt));
代码输出:
zoneDateTime expected = Jul 20 1969 21:56:20.599 CDT
zoneDateTime from millis = Jul 20 1969 21:56:20.599 CDT
如果在秒部分为负的情况下反转nanos上的符号,则可以看到格式化的ZonedDateTime中的差异:
org.junit.ComparisonFailure: date doesn't match expected
Expected :Jul 20 1969 21:56:20.599 CDT
Actual :Jul 20 1969 21:56:19.401 CDT
P.S。乔恩·斯凯特(Jon Skeet)所说的“宽大处理”在“关于日期的所有内容”一文中还有一些想法,在其他地方我也看到了“规范化”,这可能是由于POSIX的影响:
宽容没有明显的理由:“在所有情况下, 用于这些目的的方法不必落在指定的范围内; 例如,日期可以指定为1月32日并被解释为 意思是2月1日。”多久有用一次?
答案 2 :(得分:0)
Basil Bourque’s answer是个好人。从小数部分取纳纳秒到纳秒的整数可能会导致一两个陷阱。我建议:
String dateInMillis = "1413225446.92000";
String[] secondsAndFraction = dateInMillis.split("\\.");
int nanos = 0;
if (secondsAndFraction.length > 1) { // there’s a fractional part
// extend fractional part to 9 digits to obtain nanoseconds
String nanosecondsString
= (secondsAndFraction[1] + "000000000").substring(0, 9);
nanos = Integer.parseInt(nanosecondsString);
// if the double number was negative, the nanos must be too
if (dateInMillis.startsWith("-")) {
nanos = -nanos;
}
}
ZonedDateTime zdt = Instant
.ofEpochSecond(Long.parseLong(secondsAndFraction[0]), nanos)
.atZone(ZoneId.of("Asia/Manila"));
System.out.println(zdt);
打印
2014-10-14T02:37:26.920+08:00[Asia/Manila]
纳秒时我们不需要64位,所以我只使用int
。
如果有一天您的纪元时间以科学记数法出现(1.41322544692E9),则上述情况将不起作用。
如果碰巧不是亚洲/马尼拉,请用地区/城市格式替换您想要的时区,例如America / Vancouver,America / Los_Angeles或Pacific / Pitcairn。避免像PST这样的三个字母缩写,它们含糊不清,通常不是真正的时区。