GPS时间表示库

12

我正在寻找一款Java库,用于处理与GPS时间的转换。

GPS时间的纪元起点为1980年1月6日,并且没有闰秒,因此它与更常见的时间表示不同。以下是来自维基百科的相关描述:

虽然大多数时钟都与协调世界时(UTC)同步,但卫星上的原子钟是根据GPS时间设置的。它们之间的区别在于,GPS时间不进行纠正以匹配地球的自转,因此它不包含定期添加到UTC的闰秒或其他更正。GPS时间在1980年被设置为与协调世界时(UTC)相匹配,但自那时以来已经发生了分歧。缺乏修正意味着GPS时间始终保持与国际原子时(TAI)有一个恒定偏移(TAI-GPS=19秒)。在卫星上执行定期修正以纠正相对论效应并使其与地面时钟同步。

GPS导航消息包括GPS时间和UTC之间的差异,截至2009年,由于在2008年12月31日添加了闰秒,该差异为15秒。接收器从GPS时间中减去此偏移量以计算UTC和特定时区值。新的GPS装置可能在接收到UTC偏移消息之后才会显示正确的UTC时间。 GPS-UTC偏移字段可以容纳255个闰秒(八位),考虑到地球自转变化的当前速率(大约每18个月引入一个闰秒),应足以持续到大约2300年。

与公历的年、月、日格式不同,GPS日期以周数和一周中的秒数表示。周数作为十位二进制字段在C/A和P(Y)导航消息中传输,因此每1024周(19.6年)它会再次变为0。 GPS第零周始于1980年1月6日00:00:00 UTC(TAI时间为00:00:19),并且周数在1999年8月21日23:59:47 UTC(1999年8月22日TAI时间00:00:19)第一次变为0。要确定当前公历日期,GPS接收器必须提供近似日期(误差在3584天以内),以正确翻译GPS日期信号。为了解决这个问题,现代化的GPS导航消息使用一个13位字段,它仅每8192周(157年)重复一次,因此持续到2137年(GPS第零周157年后)。

我不想自己编写代码,Joda时间库好像没有任何指示可以处理GPS编码日期..是否有一种方法扩展它呢?

4个回答

4

JSR-310中有TAIInstantUTCInstant类,可帮助解决此问题(因为GPS时间尺度是TAI的变体)。 这些类位于ThreeTen-Extra项目中。


2
这个网站似乎正在使用JavaScript实时进行转换。 链接文本

谢谢,我使用这个网站构建了自己的Java库代码来进行转换。 - I82Much
@I82Much,您能详细说明一下您所说的“使用”该网站是什么意思吗? - Pacerier
我查看了源代码,看他在做什么,并将其转换为Java。 - I82Much
@I82Much,您能否将您的代码作为答案发布到您自己的问题中? - Basil Bourque
抱歉 - 这属于我的前雇主。 - I82Much

0

这是一个非常古老的问题,然而我刚遇到了同样的问题。也许将来会有人阅读这篇文章并节省我刚刚花费的两个小时。

根据JodaStephen的答案,我使用了TheeTen-Extra项目和Java8的Instant作为输入和输出,编写了以下代码:

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);
}

我用一些包含来自德国GPS时间维基百科页面的数据的测试验证了这种方法:

// 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));

0

您能详细说明您试图做什么吗?

如果您正在从GPS接收器读取数据,则NMEA流应根据您的引用进行UTC漂移校正,并由this确认。


这个网站似乎在JavaScript中实时进行转换。http://leapsecond.com/java/gpsclock.htm - GinoA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接