Как получить текущую дату и время от времени отладки GPS в python
У меня есть gps unsegmented time, как это:
Tgps = 1092121243.0
И я хотел бы понять, что такое дата и время. Начало GPS-времени - 6 января 1980 года. Функция Python
datetime.utcfromtimestamp
может давать секунды с 1 января 1970 года.
Я нашел следующее:
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)
Я не уверен, что в leapseconds они включены в функцию datetime, или я должен рассчитать их и вычесть из результата?
Может быть, также существует лучшее решение этой проблемы?
Ответы
Ответ 1
Время GPS синхронизируется с UTC: 1980-01-06 (UTC) == 1980-01-06 (GPS)
. Оба тикают в секундах СИ. Разница между временем GPS и временем UTC увеличивается с каждой (интеркалярной) скачкообразной секундой.
Чтобы найти правильное время UTC, вам нужно знать количество секунд прыжка до заданного времени GPS:
#!/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)
где leap_count(date)
- количество секунд прыжка, введенное до указанной даты. Из таблица TAI-UTC (примечание: сайт является авторитетным источником на секундах секундного прыжка. Он публикует Бюллетень C, объявляющий о новых високосных секундах):
1980..: 19s
2012..: 35s
и поэтому:
(leap_count(2014) - leap_count(1980)) == (35 - 19)
Если вы находитесь в Unix, вы можете использовать часовой пояс "right"
, чтобы получить время UTC от времени TAI
(и легко получить TAI время от времени GPS: TAI = GPS + 19 секунд (постоянное смещение):
#!/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)
Вы можете избежать изменения часового пояса, если вы извлечете список секунд прыжка из соответствующего tzfile(5)
. Это комбинация первых двух методов, в которых вычисление счетчика прыжка от первого метода автоматизировано и автоопределение tzdata
(системный пакет для база данных tz) из второго метода:
>>> 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)
где leapseconds.py
может извлекать секунды прыжка из файла /usr/share/zoneinfo/right/UTC
(часть пакета tzdata
).
Все три метода дают одинаковый результат.
Ответ 2
Я использую следующую функцию, которая считает секунды прыжка:
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)
Конечно, вам нужно периодически обновлять _LEAP_DATES
, но эти обновления довольно редки.
В общем, время GPS состоит из двух чисел: недели GPS и количества секунд с начала текущей недели GPS. Поэтому вы можете использовать следующее:
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))
В вашем случае week = 0
, поэтому:
In [1]: gps2utc(0, 1092121243.0)
Out[1]: datetime.datetime(2014, 8, 15, 7, 0, 27)
Ответ 3
Вы можете использовать astropy.time для этого:
from astropy.time import Time
mytime = 1172361618
t = Time(mytime, format='gps')
t = Time(t, format='iso')
print t
который возвращает:
2017-03-01 00: 00: 37.000
Я думаю, что есть несколько небольших определений на уровне 1 секунды между временем UNIX, сообщенным астропией, и строгим определением POSIX, но это близко.