I have gps unsegmented time like this:
Tgps = 1092121243.0
And I'd like to understand what date and time is that. The begining of GPS time is 6 January 1980. Python function
datetime.utcfromtimestamp
could give seconds from 1 January 1970 year.
I found following:
from datetime import datetime
GPSfromUTC = (datetime(1980,1,6) - datetime(1970,1,1)).total_seconds()
curDate = datetime.utcfromtimestamp(Tgps + GPSfromUTC)
Out[83]: datetime.datetime(2014, 8, 15, 7, 0, 43)
I'm not sure about leapseconds are they included in function datetime or I should calculate them and substract from the result? May be also exists better solution of this problem?
GPS time started in sync with UTC: 1980-01-06 (UTC) == 1980-01-06 (GPS)
. Both tick in SI seconds. The difference between GPS time and UTC time increases with each (intercalary) leap second.
To find the correct UTC time, you need to know the number of leap seconds occurred before the given GPS time:
#!/usr/bin/env python
from datetime import datetime, timedelta
# utc = 1980-01-06UTC + (gps - (leap_count(2014) - leap_count(1980)))
utc = datetime(1980, 1, 6) + timedelta(seconds=1092121243.0 - (35 - 19))
print(utc)
2014-08-15 07:00:27 # (UTC)
where leap_count(date)
is the number of leap seconds introduced before the given date. From TAI-UTC table (note: the site is the authoritative source on leap seconds. It publishes Bulletin C announcing new leap seconds ):
1980..: 19s
2012..: 35s
and therefore:
(leap_count(2014) - leap_count(1980)) == (35 - 19)
If you are on Unix then you could use "right"
time zone to get UTC time from TAI time (and it is easy to get TAI time from GPS time: TAI = GPS + 19 seconds (constant offset) ):
#!/usr/bin/env python
import os
import time
os.environ['TZ'] = 'right/UTC' # TAI scale with 1970-01-01 00:00:10 (TAI) epoch
time.tzset() # Unix
from datetime import datetime, timedelta
gps_timestamp = 1092121243.0 # input
gps_epoch_as_gps = datetime(1980, 1, 6)
# by definition
gps_time_as_gps = gps_epoch_as_gps + timedelta(seconds=gps_timestamp)
gps_time_as_tai = gps_time_as_gps + timedelta(seconds=19) # constant offset
tai_epoch_as_tai = datetime(1970, 1, 1, 0, 0, 10)
# by definition
tai_timestamp = (gps_time_as_tai - tai_epoch_as_tai).total_seconds()
print(datetime.utcfromtimestamp(tai_timestamp)) # "right" timezone is in effect!
2014-08-15 07:00:27 # (UTC)
You could avoid changing the timezone if you extract the leap seconds list from the corresponding tzfile(5)
. It is a combination of the first two methods where the leap count computation from the first method is automated and the autoupdating tzdata
(system package for the tz database ) from the second method is used:
>>> from datetime import datetime, timedelta
>>> import leapseconds
>>> leapseconds.gps_to_utc(datetime(1980,1,6) + timedelta(seconds=1092121243.0))
datetime.datetime(2014, 8, 15, 7, 0, 27)
where leapseconds.py
can extract leap seconds from /usr/share/zoneinfo/right/UTC
file (part of tzdata
package).
All three methods produce the same result.
You can use the astropy.time package to do this:
from astropy.time import Time
mytime = 1092121243.0
t = Time(mytime, format='gps')
t = Time(t, format='iso') # same as scale='tai'
print(t)
which returns 2014-08-15 07:01:02.000
from astropy.time import Time
sec = 1092121243.0
t_in = Time(sec, format='gps')
t_out = Time(t_in, format='iso', scale='utc')
print(t_out)
which outputs 2014-08-15 07:00:27.000
I use the following function that counts leap seconds:
import bisect
from datetime import datetime, timedelta
_LEAP_DATES = ((1981, 6, 30), (1982, 6, 30), (1983, 6, 30),
(1985, 6, 30), (1987, 12, 31), (1989, 12, 31),
(1990, 12, 31), (1992, 6, 30), (1993, 6, 30),
(1994, 6, 30), (1995, 12, 31), (1997, 6, 30),
(1998, 12, 31), (2005, 12, 31), (2008, 12, 31),
(2012, 6, 30), (2015, 6, 30), (2016, 12, 31))
LEAP_DATES = tuple(datetime(i[0], i[1], i[2], 23, 59, 59) for i in _LEAP_DATES)
def leap(date):
"""
Return the number of leap seconds since 1980-01-01
:param date: datetime instance
:return: leap seconds for the date (int)
"""
# bisect.bisect returns the index `date` would have to be
# inserted to keep `LEAP_DATES` sorted, so is the number of
# values in `LEAP_DATES` that are less than `date`, or the
# number of leap seconds.
return bisect.bisect(LEAP_DATES, date)
Of course, you need to update _LEAP_DATES
occasionally, but these updates are quite rare.
In general, GPS time consists of two numbers: GPS week and the number of seconds since the beginning of the current GPS week. Therefore, you can use the following:
def gps2utc(week, secs):
"""
:param week: GPS week number, i.e. 1866
:param secs: number of seconds since the beginning of `week`
:return: datetime instance with UTC time
"""
secs_in_week = 604800
gps_epoch = datetime(1980, 1, 6, 0, 0, 0)
date_before_leaps = gps_epoch + timedelta(seconds=week * secs_in_week + secs)
return date_before_leaps - timedelta(seconds=leap(date_before_leaps))
In your case week = 0
, so:
In [1]: gps2utc(0, 1092121243.0)
Out[1]: datetime.datetime(2014, 8, 15, 7, 0, 27)
A linear combination between Ru887321 and Yury Kirienko answers.
from astropy.time import Time
def gps2utc(gpsweek, gpsseconds):
""" GPS time to UTC.
Parameters
----------
gpsweek : int
GPS week number, i.e. 1866.
gpsseconds : int
Number of seconds since the beginning of week.
Returns
-------
datetime
datetime instance with UTC time.
"""
secs_in_week = 604800
secs = gpsweek * secs_in_week + gpsseconds
t_gps = Time(secs, format="gps")
t_utc = Time(t_gps, format="iso", scale="utc")
return t_utc.datetime
In your case week = 0
, so:
In [1]: gps2utc(0, 1092121243.0)
Out[1]: datetime.datetime(2014, 8, 15, 7, 0, 27)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.