I want to get the TAI timestamp in kotlin in "seconds":"nanoseconds" format.
It's my current solution and I'm sure there would be some better way to achieve this,
import java.time.Instant
import java.time.temporal.ChronoUnit;
fun main() {
val epochNanoseconds = ChronoUnit.NANOS.between(Instant.EPOCH, Instant.now())
val epochSeconds = epochNanoseconds/1000000000
val remainingNanoSeconds = (epochNanoseconds.toDouble()/1000000000 - epochSeconds).toString().split(".")[1]
println("$epochSeconds:$remainingNanoSeconds")
}
Example output:
1670190945:027981042861938477
Is there any way to get seconds and remaining nanoseconds directly from java.time.Instant
or any other library available to achieve this conveniently?
I think even my solution is not entirely correct
val remainingNanoSeconds = (epochNanoseconds.toDouble()/1000000000 - epochSeconds).toString().split(".")[1]
This gives me the seconds, not the nanoseconds.
CodePudding user response:
tl;dr
You are working too hard.
Ask the Instant
object for its count of whole seconds since 1970-01-01T00:00Z. Make a string of that, append the FULL STOP character. Then append the count of nanoseconds in the fractional second of the Instant
.
instant.getEpochSecond()
"."
instant.getNano()
1670220134.130848
Details
Neither the legacy date-time classes (Calendar
, Date
, etc.) nor the modern java.time classes support International Atomic Time (TAI). Time-keeping on conventional computers (and therefore Java) is nowhere near as accurate as an atomic clock.
Perhaps you used that term loosely, and really just want a count of nanoseconds since the epoch reference of first moment of 1970 as seen with an offset from UTC of zero hours-minutes-seconds (1970-01-01T00:00Z) within the limits of conventional computer hardware.
If so, the Instant
class will work for you. But beware of limitations in the implementations of Java based on the OpenJDK codebase.
- In Java 8, the first with java.time classes, the current moment is captured with a resolution of milliseconds.
- In Java 9 , the current moment is captured with a resolution of microseconds (generally, depending on the limits of your computer hardware).
Note that in all versions (8, 9, and later), an Instant
is capable of nanosecond resolution. The limitations bulleted above relate to capturing the current moment from the computer hardware clock.
The internal representation of a moment in the Instant
class comprises two parts:
- A count of whole seconds since 1970-01-01T00:00Z.
- A fractional second represented by a count of nanoseconds.
The Instant
class provides a pair of accessor methods (getters) to see both of these numbers.
Your Question is not entirely clear, you seem to be asking for those two numbers with a FULL STOP character between them.
Instant instant = Instant.now() ;
String nanos = Long.toString( instant.getNano() ) ;
String output =
instant.getEpochSecond()
"."
instant.getNano()
;
instant.toString(): 2022-12-05T06:12:33.294698Z
output: 1670220753.294698
If you want to pad zeros to the right of your fractional second, use String.format
.
Instant instant = Instant.now() ;
String nanos = Long.toString( instant.getNano() ) ;
String output =
instant.getEpochSecond()
"."
String.format( "%1$" nanos.length() "s", nanos ).replace(' ', '0') // Pad with leading zeros if needed.
;
See this code run at Ideone.com.
instant.toString(): 2022-12-05T06:12:33.294698Z
output: 1670220753.294698000
Alternatively, you could instantiate a BigDecimal
object.
CodePudding user response:
Yes, you can use the toEpochMilli() method of the Instant class to obtain the number of milliseconds since the start of the epoch as a long value. You can then use this long value to calculate the number of seconds and nanoseconds remaining. The following example demonstrates how this can be done:
Java:
long epochMilli = Instant.now().toEpochMilli();
long secondsRemaining = epochMilli / 1000;
long nanosecondsRemaining = (epochMilli % 1000) * 1000000;
System.out.println("Seconds remaining: " secondsRemaining);
System.out.println("Nanoseconds remaining: " nanosecondsRemaining);
Kotlin:
val epochMilli = Instant.now().toEpochMilli()
val secondsRemaining = epochMilli / 1000
val nanosecondsRemaining = (epochMilli % 1000) * 1000000
println("Seconds remaining: $secondsRemaining")
println("Nanoseconds remaining: $nanosecondsRemaining")