Skip to content

Add a scale-dependent gps_coord format analogous to MJD #20709

Open

Description

@ReinhardPrix

Motivation

The gravitational-wave community routinely uses GPS timestamps, including in barycentering calculations involving TT and TDB. For an example, see Sharma, Prix, Papa & Cutler, Validating Timing-Model Accuracy for Continuous Gravitational Waves: A Comparison of LALSuite and PINT, which tests LALSuite's timing model, including its Einstein-delay implementation, against PINT (a test implementation can be found here).

A GPS-like seconds format with MJD's scale-dependent behavior would make these calculations easier to express while retaining familiar numerical coordinates.

Current behavior

For one physical instant:

from astropy.time import Time

t = Time(1234567890, format="gps")

(t.tt.mjd - t.tdb.mjd) * 86400
# approximately -0.0012114 seconds

t.tt.gps - t.tdb.gps
# 0.0

MJD exposes the coordinates in the selected scale. GPS always converts through its intrinsic TAI scale before returning a value.

The same asymmetry affects input: equal numerical MJD values interpreted in TT and TDB identify different instants, whereas equal GPS values identify the same instant regardless of the supplied scale.

This makes format and scale less independent for GPS than for MJD. A scale-dependent seconds format would support the same operations already available with MJD, without manual day-to-second conversions.

Proposal

Preserve existing gps behavior for compatibility and add a format provisionally named gps_coord, defined by:

gps_coord = 86400 × (MJD_in_selected_scale − reference_MJD)

The reference is the fixed coordinate label 1980-01-06 00:00:19, interpreted in the selected scale. This follows MJD's origin convention: the reference coordinate stays fixed while its physical instant depends on the scale.

The default scale would be TAI, ensuring numerical agreement with conventional GPS timestamps:

Time(x, format="gps_coord")               # TAI; agrees with GPS
Time(x, format="gps_coord", scale="tt")   # interprets x in TT
Time(x, format="gps_coord", scale="tdb")  # interprets x in TDB

The Einstein-delay coordinate difference could then be expressed directly in seconds:

t.tdb.gps_coord - t.tt.gps_coord
# approximately +0.0012114 seconds

This parallels:

(t.tdb.mjd - t.tt.mjd) * 86400

Input interpretation would likewise follow MJD:

a = Time(1234567890, format="gps_coord", scale="tt")
b = Time(1234567890, format="gps_coord", scale="tdb")

(a - b).to_value("s")
# Nonzero: different instants assigned equal numerical coordinates.

Draft implementation

A small TimeNumeric subclass provides this behavior while retaining Astropy's two-part internal representation:

from astropy.time.formats import TimeNumeric
from astropy.time.utils import day_frac


class TimeGPSCoord(TimeNumeric):
    """Scale-dependent seconds from 1980-01-06 00:00:19 in that scale."""

    name = "gps_coord"
    unit = 1.0 / 86400
    _default_scale = "tai"

    _epoch_jd1 = 2444244.5
    _epoch_jd2 = 19.0 / 86400

    def set_jds(self, val1, val2):
        self._check_scale(self._scale)
        day, frac = day_frac(val1, val2, divisor=86400.0)
        self.jd1, self.jd2 = day_frac(
            self._epoch_jd1 + day, self._epoch_jd2 + frac
        )

    def to_value(self, **kwargs):
        seconds1 = (self.jd1 - self._epoch_jd1) * 86400
        seconds2 = (self.jd2 - self._epoch_jd2) * 86400
        return super().to_value(jd1=seconds1, jd2=seconds2, **kwargs)

    value = property(to_value)

A prototype passed representative checks against both Astropy 7.2.0 and the development checkout, version 8.1.0.dev837+g6edc126c5, for default GPS agreement, scale-dependent reference coordinates, round trips, and TT–TDB differences.

Related discussions

  • #10052, resolved by adding unix_tai in #10081, provides precedent for adding a format while preserving existing behavior.
  • #4312 discusses the scale-independent output of epoch-based formats.
  • #11265 and #11269 discuss GPS as a time scale.

Would a built-in format with these semantics be welcome? gps_coord is a provisional name; suggestions are welcome.

Environment

The development-checkout test used an editable installation with:

  • OS: Linux 6.12.113+deb13-amd64, x86_64, glibc 2.41
  • Python: 3.13.12
  • NumPy: 2.5.4
  • Astropy: 8.1.0.dev837+g6edc126c5

The prototype also passed with Astropy 7.2.0 and NumPy 2.3.5.

AI disclosure

Generative AI assisted with drafting this proposal and its prototype implementation.


Full-suite testing, extended-precision subformats, and UTC leap-day behavior remain unchecked.

cc @sharma-kartikey

Activity

  1. pllim commented on Oct 25, 2026

    @pllim
    Member
  2. ReinhardPrix commented on Oct 26, 2026

    @ReinhardPrix
    Author

    Thanks for the pointers!

    I think our request is complementary to those two issues (#2134, #8130): both concern the scale side of Time, namely GPS–UTC corrections and improved realizations of TT.

    Our request instead concerns the format side: a GPS-like, seconds-based numerical format, analogous to MJD, usable with whichever scale is selected. The current "gps" format instead always computes its numerical values in TAI scale.
    Using informal format(scale) notation, we'd like combinations such as gps_coord(tai), gps_coord(tt), gps_coord(tdb), and gps_coord(utc), potentially also gps_coord(tt_bipm) if that realization becomes available.

    Given the existing semantics and past discussions about gps, introducing a separate format name seems safest for backward compatibility.

    If there is interest/sufficient agreement, I'd be happy to supply a PR with a detailed implementation.

  3. pllim commented on Oct 27, 2026

    @pllim
    Member

    BTW, is there so such support in downstream libraries more specific to gravitational wave community, like LIGO?

  4. unpinned this issue on Nov 3, 2026
  5. neutrinoceros commented on Nov 3, 2026

    @neutrinoceros
    Contributor

    (pinned by mistake)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions