I want to convert from Unix Time to GPS Time, i.e. calculate the number of weeks since the beginning of the GPS epoch (January 6, 1980) in Python. I am not looking for the weeks in a year but the weeks since 1980.
To start my attempt has been to get the number of seconds elapsed by using time.time() to return the time since the 1970 epoch known as Unix time and subtract it from the number of seconds elapsed between that epoch and GPS start date.
This returns a correct value, in seconds, for the time since 1980 but I would like the GPS week number. Is there a standard Python function that returns this?
NOTES
GPS date is expressed as a week number since epoch and a seconds-into-week number. The GPS Epoch is different - January 6, 1980 00:00:00. Furthermore, "GPS counts weeks" since the epoch - A GPS week is defined to start on Sunday. NOTE: January 6 is the first Sunday of 1980. 1
The Unix time system has an Epoch of January 1, 1970 00:00:00 and ISO defines the first week of the year as - "The one which contains the fourth day of January, which is equivalent to saying that it's the first week to overlap the new year by at least four days".
There are other time systems, most notably J2000. Converting from one time system to another is non-trivial.
To deal with GPS Time, Perl provides the DateTime::Precise library, which performs common time and date operations with additional GPS operations. The question again is, does Python provide a similar library?
Wikipedia Entry on GPS Time
A way to do this would be to use python's datetime
module. One useful function of this is that it lets you take a date and convert it into a number of days using date.days
. Using these days, we can subtract them and divide by 7
(days in a week :p) to get the weeks between.
However, before converting each to days, you need to first subtract from that date
the day of the week. This will give you the date of that week's Monday
which will eliminate out-by-one errors.
To do this, you could do something like:
from datetime import date, timedelta
epoch = date(1980, 1, 6)
today = date.today()
epochMonday = epoch - timedelta(epoch.weekday())
todayMonday = today - timedelta(today.weekday())
Now that you have the dates of the Monday
of their weeks, you need to subtract them to find the difference and divide by 7
to get the weeks.
This gives the final output:
noWeeks = (todayMonday - epochMonday).days / 7
@Dave X's answer def utctoweekseconds(utc,leapseconds):
is good, however you need to ADD the timedelta in tdiff = utc -epoch -datetime.timedelta(seconds=leapseconds)
, not subtract (GPS time is ahead of UTC). If you add the datetime rather than subtract the function works perfect.
I noticed this when i ran my computer's datetime.utcnow() through the function and compared it to the time of a GPS receiver i had connected to the device, they were initially off by 36 seconds (double the number of leap seconds).
2014-09-22 21:36:52 was GPS time of week 164212, not 164196 (according to https://www.labsat.co.uk/index.php/en/gps-time-calculator).
(sorry i couldnt leave a comment, i don't have enough reputation)
correct function:
def utctoweekseconds(utc,leapseconds):
""" Returns the GPS week, the GPS day, and the seconds
and microseconds since the beginning of the GPS week """
import datetime, calendar
datetimeformat = "%Y-%m-%d %H:%M:%S"
epoch = datetime.datetime.strptime("1980-01-06 00:00:00",datetimeformat)
tdiff = utc -epoch + datetime.timedelta(seconds=leapseconds)
gpsweek = tdiff.days // 7
gpsdays = tdiff.days - 7*gpsweek
gpsseconds = tdiff.seconds + 86400* (tdiff.days -7*gpsweek)
return gpsweek,gpsdays,gpsseconds,tdiff.microseconds
An inverse function was available on gist: https://gist.github.com/jeremiahajohnson/eca97484db88bcf6b124
def weeksecondstoutc(gpsweek,gpsseconds,leapseconds):
import datetime, calendar
datetimeformat = "%Y-%m-%d %H:%M:%S"
epoch = datetime.datetime.strptime("1980-01-06 00:00:00",datetimeformat)
elapsed = datetime.timedelta(days=(gpsweek*7),seconds=(gpsseconds+leapseconds))
return datetime.datetime.strftime(epoch + elapsed,datetimeformat)
weeksecondstoutc(1811,164196.732,16) ## --> '2014-09-22 21:36:52'
Note that this solution manually accounts for the difference in leap seconds between the POSIX and TAI. (See https://en.wikipedia.org/wiki/Leap_second for the leap seconds) Leapseconds are available as in https://stackoverflow.com/a/33445945/1653571 but this code doesn't use it.
So converting from unix time back to GPS also needs to care about leap seconds:
def utctoweekseconds(utc,leapseconds):
""" Returns the GPS week, the GPS day, and the seconds
and microseconds since the beginning of the GPS week """
import datetime, calendar
datetimeformat = "%Y-%m-%d %H:%M:%S"
epoch = datetime.datetime.strptime("1980-01-06 00:00:00",datetimeformat)
tdiff = utc -epoch -datetime.timedelta(seconds=leapseconds)
gpsweek = tdiff.days // 7
gpsdays = tdiff.days - 7*gpsweek
gpsseconds = tdiff.seconds + 86400* (tdiff.days -7*gpsweek)
return gpsweek,gpsdays,gpsseconds,tdiff.microseconds
utctoweekseconds(datetime.datetime.strptime('2014-09-22 21:36:52',"%Y-%m-%d %H:%M:%S"),16)
## gives: (1811, 1, 164196,0)
I needed the day of the GPS week as well, since I was calculating filenames for the GPS clock and orbital files from https://cddis.nasa.gov/Data_and_Derived_Products/GNSS/orbit_and_clock_products.html &c.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With