• Post Reply Bookmark Topic Watch Topic
  • New Topic

Reconciling Java date/time with GPS times and leap seconds

 
Gary W. Lucas
Ranch Hand
Posts: 65
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I was wondering if anyone had experience using GPS times and the Java time/date classes and might be able to offer me advice on a problem I am working on.

I have some data that was collected at various times over a period of years. The time values in the data are stored using GPS Satellite Times, which are measured in seconds from epoch January 6, 1980. I want to format these times in user-readable strings, probably using the Java SimpleDateFormat. I’m thinking that this is more than just a adding a simple offset to adjust the times to the Java epoch January 1, 1970 because the GPS times are absolute measures of duration while terrestrial times are adjusted for leap seconds every couple of years.

Searching on the web, I get the impression that the Java classes always assume a fixed 86400 seconds in a day and to not observe leap seconds. Is this correct? If so, then I would think that a simple offset calculation would result in a Java string formatted for a time 10 to 15 seconds higher than would have been showing on a terrestrial clock when the data was collected.

My plan is to (1) get a table of dates for when leap seconds were observed, (2) use these to adjust the GPS Satellite Times down to the appropriate Java time in milliseconds, (3) use that time value to create a Date object and pass it into SimpleDateFormat.

The downside to this approach is that it will only work until the next leap second occurs and new data arrives. However, the application I’m working on isn’t that critical (no airplanes will fall from the sky). I just want to make it as good as I reasonably can.

Any recommendations?

Thanks in advance.

P.S. Would the new Java 8 date/time classes have any advantage for this application?
 
Stephan van Hulst
Bartender
Posts: 6669
90
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Gary W. Lucas wrote:Searching on the web, I get the impression that the Java classes always assume a fixed 86400 seconds in a day and to not observe leap seconds. Is this correct?

No. Especially the new java.time API is very concerned with calendar rules.

My plan is to (1) get a table of dates for when leap seconds were observed, (2) use these to adjust the GPS Satellite Times down to the appropriate Java time in milliseconds, (3) use that time value to create a Date object and pass it into SimpleDateFormat.

Don't. Any assumptions you make about time are likely going to be wrong. 1) Never roll your own cryptography. 2) Never roll your own calendar.

Any recommendations?

Yes, as you already guessed, Java has new classes that handle this perfectly.

First, make a LocalDateTime instance using one of its static factory methods that represents the GPS epoch. Then you can use plusSeconds() to add your GPS timestamp. Now you'll have a LocalDateTime instance that represents the time your measurement was taken.

If you know and care about the time-zone where the measurements were taken, you can use ZonedDateTime instead, but most of the time this is not necessary.
 
Salil Wadnerkar
Ranch Hand
Posts: 77
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It looks like Java Date/time classes consider leap year seconds, while the Satellite times do not. http://stackoverflow.com/questions/20521750/ticks-between-unix-epoch-and-gps-epoch
 
fred rosenberger
lowercase baba
Bartender
Posts: 12377
40
Chrome Java Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Watch this and cry for folk who do have to write the calendar/time classes:



 
Bear Bibeault
Author and ninkuma
Marshal
Posts: 65681
129
IntelliJ IDE Java jQuery Mac Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In one of my jobs, I work on global mapping and charting software. I loathe dealing with timezones with a passion bordering on the pathological.
 
Gary W. Lucas
Ranch Hand
Posts: 65
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I'm glad to see that my post drew such an enthusiastic response.

I'm afraid I struck out on this. I've not used the Java 8 time API's before and they turn out to be a LOT more complex than their predecessors. So I'm thinking I may have missed something. So I have a few questions:

How does one get a GPS Epoch? Do you have an example? I went looking for some way to get a reference to the GPS epoch from the ZoneId class. I found the following snippet of code that dumps all the available ZoneID values. I searched through them and and none of the entries included the strings "GPS", "TAI", or "atom" (TAI being the standard abbreviation for the international atomic clock time).


Just for good measure, I downloaded the latest JDK from Oracle to ensure that I wasn't running an incomplete version of the API. Same result...


Next I tried the following block of code that would compute the time difference in seconds between 1 January 2011 and 1 January 2014. According to Wikipedia, there was a leap second in 2012. There are 86400 seconds in a day, so if the leap second were ignored, the difference between these two times would be an integral multiple of 86400. But, if there was a leap second anywhere in between, I would expect to see a 1 in the low-order digit of the difference between the two times:


The value is basically consistent with the milliseconds value I got from the following old style code:


So it looks like neither API considers leap seconds in their calculations. Is there another option I need to pass into one of the calculations to support them in the new API?


Thanks again for your help here.

Gary


P.S. Just as a reference, in case it comes up in the discussion, the code I used to obtain the offset between the GPS epoch and the Java epoch was:

 
Stephan van Hulst
Bartender
Posts: 6669
90
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So I took a look at the documentation and while Java Time does account for leap seconds, it will just smear them out over the last 1000 seconds of the day the second is introduced. So it will appear that Java Time will indeed have 86400 'seconds' per day. GPS and TAI also have 86400 seconds, but these are actual SI seconds. GPS and TAI don't account for leap seconds. That means you can't use plusSeconds(), because those add non-SI seconds.

Seeing as all Java classes operate on Java Time, there's no easy way to convert to GPS time using the standard API. One solution is to use the ThreeTen-Extra library. You should define the GPS epoch as a TaiInstant, then add the number of SI seconds from your GPS timestamp, and then convert the whole thing back to a Java Time Instant.

Here's how I would do it:
 
Gary W. Lucas
Ranch Hand
Posts: 65
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan,

Thanks for your excellent suggestion! I'd never heard of the ThreeTen-Extra library. I just made a quick visit to that site and it seems like just what I need.

I see that ThreeTen-Extra even has support for the Coptic calendar. Now that's what I call being "detail oriented"!

Gary
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 15768
74
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:So it will appear that Java Time will indeed have 86400 'seconds' per day.

Except when you have a daylight savings transition, where a day may have 23 or 25 hours instead of the usual 24 hours.
 
Stephan van Hulst
Bartender
Posts: 6669
90
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Aye, but that's not an issue if you use UTC in your conversions.

I just figured that it's misleading to use minus(DURATION_BETWEEN_GPS_AND_TAI), because the resulting TaiInstant will not actually represent the GPS epoch, because it should still be interpreted as a TAI instant. Get rid of that, and then you also don't have to "convert the GPS instant to a TAI instant" in the ofGpsSeconds() method.
 
Meno Hochschild
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Some corrections about what Stephan van Hulst said:

- The new java.time-API does NOT handle leap seconds at all because a precondition of any leap second handling is not matched: There is no leap second table in JDK. It was intentionally removed by Oracle before releasing Java-8.
- Indeed, the new java.time-API TALKS about leap seconds and pretends to let `java.time.Instant` to be defined as UTC-SLS. But due to the fact of missing leap second data this specification detail cannot be implemented so it behaves like POSIX (extremely confusing documentation). My strong advise: Ignore the spec which promises non-existing features/things.
- Threeten-Extra does handle leap seconds (and has its own data) but also handles `java.time.Instant` as being UTC-SLS. This cries for interoperability problems between the outer IT-world which ignores leap seconds and UTC-SLS which is ONLY implemented by Threeten-Extra. If you are not very carefully, you can observe strange and unexpected fractional seconds during the last 1000 seconds before a leap second event if you just naively convert `java.time.Instant` to the Threeten-Extra-type `UTCInstant`.

A much better library handling leap seconds is Time4J which is also interoperable with `java.time`-package in Java-8 (written by me). Example:



You can also read my article on DZone https://dzone.com/articles/how-watch-next-coming-leap if you are more interested in the whole topic.

Small side note about the coptic calendar of Threeten-Extra mentioned here: It does not manage any internationalization (no coptic month names in any locale) so don't be too enthusiastic just because that lib implemented the algorithm of that calendar.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!