java.time 可以直接解析你的字符串
编辑:如果您的毫秒值始终为非负数,则以下DateTimeFormatter 可以解析它。
private static final String TIME_ZONE_PST = "America/Los_Angeles";
private static final DateTimeFormatter epochFormatter = new DateTimeFormatterBuilder()
.appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NEVER)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
.optionalEnd()
.toFormatter()
.withZone(ZoneId.of(TIME_ZONE_PST));
现在解析成ZonedDateTime 只是一种方法调用:
ZonedDateTime zdt = ZonedDateTime.parse(dateInMillis, epochFormatter);
System.out.println(zdt);
输出是:
2014-10-13T11:37:26.920-07:00[美国/洛杉矶]
负值无法正常工作:分数仍会被解析为正数,我假设这是不正确的。为了确保在出现负值的情况下得到通知,我在格式化程序中指定了该数字无法签名。
更通用的解决方案:使用 BigDecimal
如果您需要更通用的解决方案,例如包括负数,我认为最好让BigDecinmal 解析数字并进行数学运算。
BigDecimal bd = new BigDecimal(dateInMillis);
BigDecimal[] wholeAndFractional = bd.divideAndRemainder(BigDecimal.ONE);
long seconds = wholeAndFractional[0].longValueExact();
int nanos = wholeAndFractional[1].movePointRight(9).intValue();
ZonedDateTime zdt = Instant.ofEpochSecond(seconds, nanos)
.atZone(ZoneId.of(TIME_ZONE_PST));
输出与以前相同。只是现在我们还可以按预期处理负数:
String dateInMillis = "-1.5";
1969-12-31T15:59:58.500-08:00[美国/洛杉矶]
甚至科学记数法也被接受:
String dateInMillis = "1.41322544692E9";
2014-10-13T11:37:26.920-07:00[美国/洛杉矶]
如果字符串中的精度可能超过纳秒,请考虑您希望如何截断或舍入,并相应地指示BigDecimal,有多种选择。
原答案
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.50 意味着在纪元之前一秒半。如果有一天你的纪元时间以科学计数法出现(1.41322544692E9),上述方法将不起作用。
如果不是亚洲/马尼拉,请用 region/city 格式替换您想要的时区,例如 America/Vancouver、America/Los_Angeles 或 Pacific/Pitcairn。避免使用 PST 之类的三个字母缩写,它们不明确且通常不是真实的时区。