Reputation: 933
As the title states, I'm required to find the number of TAI seconds since 00:00:00 UTC, January 1st, 2004 (in Java). I've just recently learned what TAI is and my attempts at working out the above have left me a bit confused.
What I've tried:
I know in Java you can use System.currentTimeMillis()
to get the number of milliseconds since January 1st, 1970 UTC (Javadocs).
Additionally, from my brief research of atomic time I understand that currently TAI is exactly 37 (leap) seconds ahead of UTC.
Therefore, my thought process was to:
I wasn't certain of the math here (1 day = 86400 seconds):
At this point I started questioning whether the 37 leap seconds added to TAI were to account for leap years when comparing to UTC and thus I should use Option 2. Unfortunately, I'm not certain whether my thought process is correct and I figured it'd be better to ask here to make certain.
Also, I found this cite claiming that 1,072,915,200 (seconds) is equivalent to 01/01/2004 @ 12:00am (UTC). Which kind of threw me off because it's not equal to either of my calculations.
Upvotes: 3
Views: 1289
Reputation: 44061
Tai-seconds are essentially atomic SI-seconds including leap seconds. My library Time4J supports this feature out of the box. For more details about TAI-support see also the javadoc of class Moment
:
Moment m2004 = PlainTimestamp.of(2004, 1, 1, 0, 0).atUTC();
Moment now = SystemClock.currentMoment(); // other clocks based on NTP are possible
long seconds = SI.SECONDS.between(m2004, now);
System.out.println(seconds); // 425222084L
System.out.println(now); // 2017-06-22T13:15:24,570000000Z
Update after Ricolas comment:
There was one wrong value in my old answer displayed probably due to executing the test code twice and effectively looked at the results at two different points in time for "now" (45 secs distance). Proof with new test code that my library is correct:
Moment m2004 = PlainTimestamp.of(2004, 1, 1, 0, 0).atUTC();
Moment m2017 = PlainTimestamp.of(2017, 6, 22, 13, 15, 24).atUTC();
long seconds = SI.SECONDS.between(m2004, m2017);
System.out.println(seconds); // 425222129L instead of 425222084L
Thanks to Ricola for having seen the wrong displayed value in the old answer of 2017. So yes, Time4J really shows the same value for what Ricola has manually calculated.
However, Ricola seems to suggest that TAI seconds and UTC seconds are somehow different. No, they have the same constant length and effectively are both SI-seconds by definition. The only thing different is just the representation of seconds in the space of year-month-day-hour-minute-second terms for TAI and UTC. Example using Time4J for that difference in representation:
System.out.println("UTC: " + m2017.toString(TimeScale.UTC));
System.out.println("TAI: " + m2017.toString(TimeScale.TAI));
// Output:
// UTC: UTC-2017-06-22T13:15:24Z
// TAI: TAI-2017-06-22T13:16:01Z
And another tricky caveat, I would not talk about UTC before its official introduction in year 1972 (two years after Unix epoch!). Handling inofficial UTC seconds before 1972 are far more complex (even using decimal parts in seconds or UT based on astronomical seconds with varying length). Therefore it was a wise decision in Time4J to handle UTC only after 1972 (and before just using fuzzy UT seconds).
Upvotes: 1
Reputation: 2922
I see three ways to solve this. To reuse the same values as @Meno Hochschild, I'll assume that "now" is 2017-06-22T13:15:24Z .
This gives
Instant.now()
= 1498137324 (Unix timestamp, which is the same as System.currentTimeMillis()/1000
)Instant.parse("2004-01-01T00:00:00Z").getEpochSecond()
= 1072915200I don't think there is a native way to get time in TAI without using external libraries so we'll just compute it manually. But you can still create a constant table of leap seconds to get it manually.
2017-06-22T13:15:24Z
UTC is 2017-06-22T13:16:01Z
TAI (you can either use an online converter like https://astroconverter.com/clocks.html or add 37 seconds)2004-01-01T00:00:00Z
UTC is 2004-01-01T00:00:32Z
TAI (in this case if you don't use the converter you need to add 22 seconds)ChronoUnit.SECONDS.between( Instant.parse("2004-01-01T00:00:32Z"), Instant.parse("2017-06-22T13:16:01Z")
gives 425,222,129 TAI seconds elapsedYou wrote
- Find the number of seconds between 1970 and 2004 (34 years)
- Subtract that from the current UTC time to get the number of since 2004
- Add 37 to get the actual number of seconds in TAI
In 1. it's not clear if you mean the number of UTC seconds or TAI (actual) seconds. But I guess you meant TAI seconds as it wouldn't work otherwise.
However the way you compute the TAI seconds is off for three reasons:
Problem for 1. is that you can't use 365.25 days/year as the number of days is discrete, so this would only give an estimation (Also it's not exactly once every four years as the rules of leap years are: Every year that is exactly divisible by four is a leap year, except for years that are exactly divisible by 100, but these centurial years are leap years if they are exactly divisible by 400, but luckily between 1970 and 2004 it was indeed once every four year).
For 2. the fix is straightforward
For 3. you have two options.
Either you compute all timestamps as the seconds since Jan 1st 1958, which is when UTC and TAI were the same. Then you can add 37 at the end.
Or you keep the timestamps as the seconds since Jan 1st 1970 UTC (Unix Epoch) and need to only add 27 to take into account the 10 seconds offset.
Math.floor(34.0 / 4)
, but as mentioned above, this only works if there is no centurial year not divisible 400 during the time period).So your approach become
This works because {UTC seconds since Unix Epoch} = {TAI seconds since Unix Epoch} - 27
. So we have
{UTC seconds now since Unix Epoch} - {TAI seconds in 2004 since Unix Epoch} + 27 =
{TAI seconds now since Unix Epoch} - 27 - {TAI seconds in 2004 since Unix Epoch} + 27 =
{TAI seconds now since Unix Epoch} - {TAI seconds in 2004 since Unix Epoch} =
{TAI seconds between 2004 and now}
Somehow I don't have the same result as @Meno Hochschild
Upvotes: 2