GPS time counts seconds since January 6, 1980, and crucially does not include leap seconds — making it run 18 seconds ahead of UTC as of 2017. This converter handles GPS seconds, GPS week + second-of-week format, and conversion to Unix epoch.
GPS time is the time scale used by the Global Positioning System. It starts at 1980-01-06 00:00:00 UTC — the start of the GPS epoch — and counts seconds continuously, without inserting leap seconds. This is a critical difference from UTC.
Because UTC has had 18 leap seconds added since GPS started in 1980, GPS time is currently 18 seconds ahead of UTC. This offset grows by one second every time the International Earth Rotation Service adds a leap second (rare in recent years; the last one was 2016-12-31).
1419724818 = 2025-01-01 00:00:18 GPS = 2025-01-01 00:00:00 UTC
GPS receivers commonly transmit time as a pair: GPS week number (starting at 0 for the week of January 6, 1980) and seconds within that week (0 to 604799).
week: 2347
sec-of-week: 259218
→ same instant as GPS seconds 1419724818
Older GPS receivers represent week numbers in 10 bits, allowing only 1024 weeks (~19.6 years) before rollover. The first rollover happened in 1999, the second in 2019. Modern receivers use the 13-bit "extended" format that won't roll over until 2137.
unix_seconds = gps_seconds + 315964800 - leap_seconds
gps_seconds = unix_seconds - 315964800 + leap_seconds
Where 315964800 is the seconds between 1970-01-01 and 1980-01-06, and leap_seconds is the cumulative count of leap seconds inserted into UTC since GPS started (18 as of 2017, unchanged through 2026).
from datetime import datetime, timezone, timedelta
GPS_EPOCH = datetime(1980, 1, 6, tzinfo=timezone.utc)
LEAP_SECONDS = 18 # as of 2017, still current in 2026
def gps_to_datetime(gps_seconds: float) -> datetime:
return GPS_EPOCH + timedelta(seconds=gps_seconds - LEAP_SECONDS)
def datetime_to_gps(dt: datetime) -> float:
return (dt - GPS_EPOCH).total_seconds() + LEAP_SECONDS
def gps_week_and_sow(gps_seconds: float) -> tuple:
week = int(gps_seconds // 604800)
sow = gps_seconds % 604800
return (week, sow)
const GPS_OFFSET = 315964800;
const LEAP_SECONDS = 18;
function gpsToDate(gpsSec) {
const unixSec = gpsSec + GPS_OFFSET - LEAP_SECONDS;
return new Date(unixSec * 1000);
}
function dateToGps(date) {
return Math.floor(date.getTime() / 1000) - GPS_OFFSET + LEAP_SECONDS;
}
function gpsToWeekSow(gpsSec) {
const week = Math.floor(gpsSec / 604800);
const sow = gpsSec % 604800;
return { week, sow };
}
Most programming libraries treat the leap-second offset as a constant (18). If you're doing high-precision time work that spans a leap-second insertion, you need to look up the actual offset for the date in question. The IERS maintains the official list at iers.org.