web-dev-qa-db-fra.com

Comment obtenir la date et l'heure actuelles de l'heure du segment GPS en python

J'ai le temps non segmenté gps comme ceci:

Tgps = 1092121243.0

Et j'aimerais comprendre quelle est la date et l'heure. Le début de l'heure GPS est le 6 janvier 1980. Fonction Python 

datetime.utcfromtimestamp 

pourrait donner secondes à partir du 1er janvier 1970 année.

J'ai trouvé suivant:

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)

Je ne suis pas sûr que des secondes soient écoulées, sont-elles incluses dans la fonction datetime ou devrais-je les calculer et soustraire du résultat? Peut-être existe-t-il également une meilleure solution à ce problème?

9
Anton Protopopov

L'heure GPS a commencé en synchronisation avec l'heure UTC: 1980-01-06 (UTC) == 1980-01-06 (GPS). Les deux cochent en secondes SI. La différence entre l'heure GPS et l'heure UTC augmente avec chaque seconde intercalaire (intercalaire).

Pour trouver l'heure UTC correcte, vous devez connaître le nombre de secondes bissextiles écoulées avant l'heure GPS donnée:

#!/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)

Sortie

2014-08-15 07:00:27 # (UTC)

leap_count(date) est le nombre de secondes bissextiles introduites avant la date donnée. De table TAI-UTC _ _ (remarque: le site est la source faisant autorité en secondes intercalaires. Il publie le bulletin C annonçant de nouvelles secondes intercalaires ):

1980..: 19s 
2012..: 35s

et donc: 

(leap_count(2014) - leap_count(1980)) == (35 - 19)

Si vous êtes sous Unix, vous pouvez utiliser le "right" fuseau horaire pour obtenir l'heure UTC à partir de l'heure TAI (Et il est facile d'obtenir l'heure TAI à partir de l'heure GPS: TAI = GPS + 19 secondes (décalage constant) } _):

#!/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!

Sortie

2014-08-15 07:00:27 # (UTC)

Vous pouvez éviter de modifier le fuseau horaire si vous extrayez la liste des secondes intercalaires à partir du tzfile(5) correspondant. C'est une combinaison des deux premières méthodes où le calcul du nombre de sauts de la première méthode est automatisé et la mise à jour automatique tzdata (package système pour la base de données tz ) de la deuxième méthode est utilisée:

>>> 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 peut extraire les secondes intercalaires du fichier /usr/share/zoneinfo/right/UTC (composant du package tzdata).

Les trois méthodes produisent le même résultat.

13
jfs

J'utilise la fonction suivante qui compte les secondes intercalaires:

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)

Bien sûr, vous devez mettre à jour _LEAP_DATES de temps en temps, mais ces mises à jour sont assez rares.

En général, l'heure GPS se compose de deux chiffres: Semaine GPS et le nombre de secondes depuis le début de la semaine GPS en cours. Par conséquent, vous pouvez utiliser les éléments suivants:

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))

Dans votre cas, week = 0, donc:

In [1]: gps2utc(0, 1092121243.0)
Out[1]: datetime.datetime(2014, 8, 15, 7, 0, 27)
4
Yury Kirienko

Vous pouvez utiliser le paquet astropy.time pour le faire:

from astropy.time import Time
mytime = 1172361618
t = Time(mytime, format='gps')
t = Time(t, format='iso')
print t

qui retourne:

2017-03-01 00: 00: 37.000

Je pense qu’il ya quelques légères définitions au niveau 1 seconde entre le temps UNIX rapporté par astropy et la définition stricte POSIX, mais c’est proche.

3
Ru887321