GPS Time Representation library
Asked Answered
V

4

13

I am looking for a Java library that handles conversion to/from GPS Time.

GPS Time has an epoch of 6 January 1980, and does not have leap seconds, so it differs from the more standard time representations. Here is the relevant description from wikipedia:

While most clocks are synchronized to Coordinated Universal Time (UTC), the atomic clocks on the satellites are set to GPS time. The difference is that GPS time is not corrected to match the rotation of the Earth, so it does not contain leap seconds or other corrections which are periodically added to UTC. GPS time was set to match Coordinated Universal Time (UTC) in 1980, but has since diverged. The lack of corrections means that GPS time remains at a constant offset with International Atomic Time (TAI) (TAI - GPS = 19 seconds). Periodic corrections are performed on the on-board clocks to correct relativistic effects and keep them synchronized with ground clocks.

The GPS navigation message includes the difference between GPS time and UTC, which as of 2009 is 15 seconds due to the leap second added to UTC December 31, 2008. Receivers subtract this offset from GPS time to calculate UTC and specific timezone values. New GPS units may not show the correct UTC time until after receiving the UTC offset message. The GPS-UTC offset field can accommodate 255 leap seconds (eight bits) which, given the current rate of change of the Earth's rotation (with one leap second introduced approximately every 18 months), should be sufficient to last until approximately the year 2300.

As opposed to the year, month, and day format of the Gregorian calendar, the GPS date is expressed as a week number and a seconds-into-week number. The week number is transmitted as a ten-bit field in the C/A and P(Y) navigation messages, and so it becomes zero again every 1,024 weeks (19.6 years). GPS week zero started at 00:00:00 UTC (00:00:19 TAI) on January 6, 1980, and the week number became zero again for the first time at 23:59:47 UTC on August 21, 1999 (00:00:19 TAI on August 22, 1999). To determine the current Gregorian date, a GPS receiver must be provided with the approximate date (to within 3,584 days) to correctly translate the GPS date signal. To address this concern the modernized GPS navigation message uses a 13-bit field, which only repeats every 8,192 weeks (157 years), thus lasting until the year 2137 (157 years after GPS week zero).

I'd rather not have to roll my own; I don't see anything in Joda time indicating it can handle GPS encoded dates.. is there a way to extend it?

Voluptuary answered 14/6, 2010 at 14:53 Comment(0)
E
2

This website seems to be doing the conversion on the fly in javascript. link text

Ebonyeboracum answered 27/7, 2010 at 17:21 Comment(5)
Thanks, I used this website to build my own Java library code that does the conversion.Voluptuary
@Voluptuary Could you elaborate on what do you mean by you used that website?Fugue
I looked at the source to see what he was doing and converted it to JavaVoluptuary
@Voluptuary Might you post your code as an Answer to your own Question?Tournedos
Sorry - it belongs to my previous employer.Voluptuary
T
4

JSR-310 has classes TAIInstant and UTCInstant which would help solve this problem (as GPS time scale is a variation of TAI). These are located in the ThreeTen-Extra project.

Tovatovar answered 7/9, 2010 at 9:35 Comment(0)
E
2

This website seems to be doing the conversion on the fly in javascript. link text

Ebonyeboracum answered 27/7, 2010 at 17:21 Comment(5)
Thanks, I used this website to build my own Java library code that does the conversion.Voluptuary
@Voluptuary Could you elaborate on what do you mean by you used that website?Fugue
I looked at the source to see what he was doing and converted it to JavaVoluptuary
@Voluptuary Might you post your code as an Answer to your own Question?Tournedos
Sorry - it belongs to my previous employer.Voluptuary
E
0

Can you elaborate on what you are trying to do?

If you are reading data from a GPSr, the NMEA stream should be corrected for the UTC drift according to your quote and confirmed by this.

Ebonyeboracum answered 7/7, 2010 at 22:23 Comment(1)
This website seems to be doing the conversion on the fly in javascript. leapsecond.com/java/gpsclock.htmEbonyeboracum
L
0

This is a very old question, however I just had the same problem. Maybe someone in the future will read this and save two hours of time that I just spent.

Based on the answer from JodaStephen, I came up with the following code, using the TheeTen-Extra project and java8 Instant as input and output:

private final static int TAI_GPS_OFFSET = 19;
private final static LocalDate MODIFIED_JULIAN_EPOCH = LocalDate.of(1858, 11, 17);

public static Instant fromGpsTimeToUtc(Instant gpsTime) {
    LocalDate day = LocalDate.ofInstant(gpsTime, ZoneOffset.UTC);
    long days = ChronoUnit.DAYS.between(MODIFIED_JULIAN_EPOCH, day);
    long taiUtcOffset = UtcRules.system().getTaiOffset(days);
    return gpsTime.minusSeconds(taiUtcOffset).plusSeconds(TAI_GPS_OFFSET);
}

I validated this method with a few tests containing data from the german GPS-time Wikipedia page:

// after 2017-01-01: 18 seconds
Instant today = OffsetDateTime.of(2022, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(today))
        .isEqualTo(today.minus(18, ChronoUnit.SECONDS));
Instant firstOf2017 = OffsetDateTime.of(2017, 1, 1, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(firstOf2017))
        .isEqualTo(firstOf2017.minus(18, ChronoUnit.SECONDS));
// after 2015-07-01: 17 seconds
Instant lastOf2016 = OffsetDateTime.of(2016, 12, 31, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(lastOf2016))
        .isEqualTo(lastOf2016.minus(17, ChronoUnit.SECONDS));
Instant firstOfJuly2015 = OffsetDateTime.of(2015, 7, 1, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(firstOfJuly2015))
        .isEqualTo(firstOfJuly2015.minus(17, ChronoUnit.SECONDS));
// after 2012-07-01: 16 seconds
Instant lastOfJune2015 = OffsetDateTime.of(2015, 6, 30, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(lastOfJune2015))
        .isEqualTo(lastOfJune2015.minus(16, ChronoUnit.SECONDS));
Instant firstOfJuly2012 = OffsetDateTime.of(2012, 7, 1, 10, 0, 0, 0, ZoneOffset.UTC).toInstant();
assertThat(fromGpsTimeToUtc(firstOfJuly2012))
        .isEqualTo(firstOfJuly2012.minus(16, ChronoUnit.SECONDS));
Lamentation answered 3/8, 2022 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.