Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GPS time in weeks since epoch in Python?

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

like image 207
Ansh Sehgal Avatar asked Jul 31 '17 18:07

Ansh Sehgal


3 Answers

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
like image 70
Joe Iddon Avatar answered Sep 18 '22 12:09

Joe Iddon


@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
like image 42
jtwilson Avatar answered Sep 18 '22 12:09

jtwilson


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.

like image 37
Dave X Avatar answered Sep 18 '22 12:09

Dave X