Это будет работать до 2262 года:
ZonedDateTime zdt = LocalDateTime.of(2019, 1, 25, 14, 34, 34, 123456789)
.atZone(ZoneId.of("Asia/Kolkata"));
Instant i = zdt.toInstant();
long epochNano = Math.addExact(Math.multiplyExact(i.getEpochSecond(), TimeUnit.SECONDS.toNanos(1)),
i.getNano());
System.out.println(NumberFormat.getNumberInstance(Locale.ENGLISH).format(epochNano));
Вывод:
1,548,407,074,123,456,789
Почему я не просто использую TimeUnit.SECONDS.toNanos(i.getEpochSecond())
, этов случае переполнения это даст мне Long.MAX_VALUE
, то есть неверный результат.Math.multiplyExact
выдаст исключение в случае переполнения, поэтому мы обнаружим, что я явно предпочитаю.
Чтобы избежать переполнения в 2262 году и позже, используйте BigInteger
:
BigInteger epochNano = BigInteger.valueOf(i.getEpochSecond())
.multiply(BigInteger.valueOf(TimeUnit.SECONDS.toNanos(1)))
.add(BigInteger.valueOf(i.getNano()));
Результат тот же.
Плюсы и минусы: в моем коде немного больше ручной работы, чем в коде Славомира Ходницкого, что, безусловно, является недостатком.С другой стороны, я не нашел здесь использование Duration
очень хорошо мотивированным, и это не сработает и после 2262 года (бросает ArithmeticException
).Идеального решения не существует.