8

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

Xofo
  • 1,256
  • 4
  • 18
  • 33
Ansh Sehgal
  • 111
  • 1
  • 4
  • The question is a good question because it discusses one of many time specification - The GPS Time specification. Programming languages do not comprehensively address all the various time implementations and their nuances (e.g. GPS Time, Atomic Time, Leap Seconds, etc). – Xofo Jul 31 '17 at 20:46
  • To those who are down voting this question, please note that this a serious question - Another similar question https://stackoverflow.com/questions/44274989/utc-time-to-gps-time-converter-by-python which is also incomplete – Xofo Aug 02 '17 at 21:58

5 Answers5

6

Calculating day difference then dividing by 7

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
Community
  • 1
  • 1
Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
  • 2
    I am interested in this question as well, as I would have thought Python would have a GPS friendly DateTime object (one that spits out a GPS weeknumber from a method call). – Xofo Jul 31 '17 at 20:43
  • This only works with `date` objects, with `datetime` you end up off-by-one. The simplest solution for datetime objects is to use floored division: `(today - datetime.datetime(year=1980, month=1, day=6)) // 7` – Felix May 13 '20 at 16:05
  • Typo correction: `(today - datetime.datetime(year=1980, month=1, day=6)).days // 7` – Felix May 13 '20 at 18:24
4

@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
jtwilson
  • 305
  • 3
  • 11
2

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)
  # correction per https://stackoverflow.com/a/54520579/1653571

    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:20'

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)
  # correction per https://stackoverflow.com/a/54520579/1653571
    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:20',"%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.

Answer updated per https://stackoverflow.com/a/54520579/1653571 Note that if the second function needed a sign change, the code copied from the gist did as well.

Dave X
  • 4,831
  • 4
  • 31
  • 42
1

You can try gnsscal module by:

$ pip install gnsscal

then using it like:

>>> import gnsscal
>>> import datetime
>>> day = datetime.date(2019, 2, 22)
>>> gnsscal.date2gpswd(day)
(2041, 5)

But if You want to convert UTC to GPS Time, there is some difference called leap seconds, you can get infomation of leap seconds from IERS.

Jon Jiang
  • 51
  • 6
1

I'd like to add a pandas solution

UTCtime =pd.to_datetime("1980-01-06 00:00:00")+pd.Timedelta(weeks=week)+pd.Timedelta(seconds=seconds)-pd.Timedelta(seconds=leapseconds)

currently, the leap second values is 37

https://hpiers.obspm.fr/eoppc/bul/bulc/Leap_Second.dat