【SRC-Python】GNSS 时间系统的转换代码实现

本文介绍了Python实现的GNSS时间系统转换,包括闰年判断、各种时间表示方式的转换,如GPS周、儒列日等。详细讲解了不同时间系统的概念,如UTC、TAI、GPS时等,并提供了相应的函数实现。
摘要由CSDN通过智能技术生成

Part.I Introduction

本文分享了常用的时间转换的函数,主要包括判断闰年、年月日 / 年积日 / GPS 周 / 儒列日 互转、时分秒 / 天内秒 / 周内秒 互转… 编程语言为:Python。

在这里插入图片描述

Chap.I 基础知识

我们常用的表示时间的方式是北京时『时分秒』,即hh:mm:ss;而且北京市并不是UTC,它和UTC存在这样的转换关系:UTC+8小时=北京时

  • 判断闰年:年份是 4 的倍数但不是 100 的倍数或者年份是 400 的倍数。
  • GPS 周:GPS Week,GPSW GPS系统内部描述时间的一种方式,它的起点为 1980 年 1 月 5 日夜晚与 1980 年 1 月 6 日凌晨之间 0 点(这天是周日,老外经常周日表示一周的第一天,以0表示)。
  • 儒列日:Julian Day,JD 是指由公元前 4713 年 1 月 1 日,协调世界时中午 12 时开始所经过的天数。
  • 简化儒列日:Modified Julian Day,MJD 后来经国际天文学联合会(1973 年)商讨,采用简化儒列日,其起点是 1858 年 11 月 17 日世界时 0 时;MJD = JD - 2400000.5
  • 年积日:Day Of Year,DOY 一年当中的第几天,其取值范围为[1,365]
  • 天内秒:Second Of Day,SOD 一天中的第几秒,其取值范围为[1,86400]
  • 周内秒:Second Of Week,SOW 一周中的第几秒,其取值范围为[1,604800]
  • 周内分:Hour Of Week,HOW 一周中的第几小时,其取值范围为[1,168]
  • 协调世界时(Universal Time of Coordination,UTC):以原子秒长为计量单位,在时刻上与平太阳时之差小于 0.9 秒的时间系统。UT0 是完全按照天体运行计算出来的时间,UT1 是在 UT0 的基础上做了一些调整,UT2 是在 UT0 和 UT1 的基础上又进行了一些调整。天体运动并不是十分稳定的,比如极移和章动的存在。
  • 国际原子时(International Atomic Time,TAI):取 1958 年 1 月 1 日 0 时 0 分 0 秒世界时(UT)的瞬间作为同年同月同日 0 时 0 分 0 秒TAI。
  • GPS 时(GPS Time,GPST):由 GPS 星载原子钟和地面监控站原子钟组成的一种原子时基准,与国际原子时保持有 19s 的常数差,并在 GPS 标准历元 1980 年 1 月 6 日 0 时与 UTC 保持一致。
  • 北斗时(BDS Time,BDT) :同 GPST 一样由原子钟保持基准,在 2006 年 1 月 1 日 0 时与 UTC 保持一致。因为从 1980 年到 2006 年共有 14 次跳秒发生,所以 BDT 和 GPST 相差 14 秒且基本恒定不变。
  • GLONASS 时(GLONASS Time,GLST):以莫斯科本地协调时 UCTsu 定义,其值与 UTC 存在 3 小时时差。
  • Galileo 时(Galileo Time,GST):同 GPST 保持一致。
  • 跳秒:leap second,在 1980 年 1 月 6 日 0 时 GPS 时与 UTC 时对齐,GPS 时是依靠稳定的原子钟来维持的,也就是说它的单位时间长度是很稳定的;而协调世界时是根据天文确定的,和地球自转有关,但是地球自转速度在不断变慢,也就是说协调世界时的单位时间长度并不是恒定的。但是总不能他们稍微不一致就调吧,这样也太麻烦了,所以就规定,当两者相差接近1秒时,就让UTC跳一秒。
  • 跳秒对是 UCT 的操作,原子时并不会跳秒。并且跳秒通常是把 UTC 『拨快』一秒(因为地球自转速度越来越慢),比如23:59:58下一秒是下一天的00:00:00,它不经过23:59:59;但不排除将其『拨慢』一秒的可能。
  • 为什么TAI - GPST = 19?这是因为国际原子时是在 1958 年与 UTC 对齐的,而 GPS 时是在 1980 年与 UTC 对齐的,从 1958 年到 1980 年已经跳了19秒。它们两个的单位时间长度都是靠原子钟维持的,只不过TAI靠的是全球分布的约 240 台原子钟维持的,而 GPS 时是靠数十台原子钟来维持的;但是原子钟的精度本身就很高了,所以它们两个的差值可以说是恒定的。

更多的关于时间系统的介绍可参看博文

Chap.II 函数总览

下面是涉及的函数总览图。
在这里插入图片描述
需要注意的有一下几点:

  • 目前关于UTC的跳秒,下面编写的函数并没有考虑到

Part.II Python 版代码实现

编写不易,积分多的可 给点积分(下面就是资源完整内容)。

Chap.I 完整源码

import math
import time

monthdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]


def leapyear(year):
    """ Determine if a year is a leap year """
    if year % 4 == 0 and year % 100 != 0:
        return 1
    if year % 400 == 0:
        return 1
    return 0


def norm_doy(year, doy):
    """ Determine if a doy is legal """
    while True:
        if doy <= 0:
            year -= 1
            doy += (365 + leapyear(year))
        elif doy > 365 + leapyear(year):
            doy -= (365 + leapyear(year))
            year += 1
        else:
            break
    return year, doy


def doy2ymd(year, doy):
    """ Change year,day of year to year,month,day """
    day = doy
    mon = 0
    for i in range(13):
        monthday = monthdays[i]
        if i == 2 and leapyear(year) == 1:
            monthday += 1
        if day > monthday:
            day -= monthday
        else:
            mon = i
            break
    return mon, day


def ymd2doy(year, mon, day):
    """ Change year,month,day to year,day of year """
    doy = day
    for i in range(1, mon):
        doy += monthdays[i]
    if mon > 2:
        doy += leapyear(year)
    return doy


def ymd2mjd(year, mon, day):
    """ Change year,month,day to Modified Julian Day """
    mjd = 0.0
    if mon <= 2:
        mon += 12
        year -= 1
    mjd = 365.25 * year - 365.25 * year % 1.0 - 679006.0
    mjd += math.floor(30.6001 * (mon + 1)) + 2.0 - math.floor(year / 100.0) + math.floor(year / 400) + day
    return mjd


def doy2mjd(year, doy):
    """ Change year, day of year to Modified Julian Day """
    mon, day = doy2ymd(year, doy)
    return ymd2mjd(year, mon, day)


def doys2gpsweeks(doys):
    ''' str_yyyyddd > str_wwwwd '''
    year = int(doys[:4])
    doy = int(doys[4:])
    (mon, day) = doy2ymd(year, doy)
    (week, wday) = ymd2gpsweek(year, mon, day)
    return str(week) + str(wday)


def ymd2gpsweek(year, mon, day):
    """ Change year,month,day to GPS weeks """
    mjd = ymd2mjd(year, mon, day)
    week = int((mjd - 44244.0) / 7.0)
    day = math.floor(mjd - 44244.0 - week * 7.0)
    return week, day


def mjd2gpsweek(mjd):
    """ Change Modified Julian Day to GPS weeks """
    week = int((mjd - 44244.0) / 7.0)
    day = math.floor(mjd - 44244.0 - week * 7.0)
    return week, day


def mjdsod2sow(mjd,sod):
    week, day = mjd2gpsweek(mjd)
    return day*24*3600+sod


def gpsweek2mjd(week, day):
    """ Change GPS weeks to Modified Julian Day """
    return week * 7 + day + 44244


def gpsweek2doy(week, day):
    """ Change GPS weeks to doy, year """
    mjd = gpsweek2mjd(week, day)
    return mjd2ydoy(mjd)


def gpsweek2ymd(week, day):
    """ Change GPS weeks to year,month,day """
    doy, year = gpsweek2doy(week, day)
    mon, day = doy2ymd(year, doy)
    return year, mon, day


def mjd2ydoy(mjd):
    """ Change Modified Julian Day to year, day of year(1952+) """
    """ The input date must after 1952.0 """
    year = 1952
    dd = mjd + 1 - 34012
    yday = 366
    while dd > yday:
        dd -= yday
        year += 1
        if leapyear(year) == 0:
            yday = 365
        else:
            yday = 366
    return int(dd), int(year)


def mjd2ymd(mjd):
    """ Change year-mon-day to Modified Julian Day. """
    doy, year = mjd2ydoy(mjd)
    mon, day = doy2ymd(year, doy)
    return year, mon, day


def sod2hms(sod):
    """ Change seconds of day to hours, minutes and seconds """
    sod = float(sod)
    hh = math.floor(sod / 3600)
    mm = math.floor((sod - hh * 3600) / 60.0)
    ss = int(sod - hh * 3600 - mm * 60)
    return hh, mm, ss


def hms2sod(hh, mm=0, ss=0.0):
    """ Change hours:minutes:seconds to seconds of day """
    return int(hh) * 3600 + int(mm) * 60 + float(ss)


def sod2how(mjd, sod):
    """ Change (Modified Julian Day, seconds fo day) to (GPS week, hours of week) """
    """ not consider second slip now """
    doy, year = mjd2ydoy(mjd)
    mon, day = doy2ymd(year, doy)
    week, day = ymd2gpsweek(year, mon, day)
    return week, (sod + day * 86400) / 3600.0


def sod2sow(mjd, sod):
    """ Change (Modified Julian Day, seconds fo day) to (GPS week, seconds of week) """
    """ not consider second slip now """
    doy, year = mjd2ydoy(mjd)
    mon, day = doy2ymd(year, doy)
    week, day = ymd2gpsweek(year, mon, day)
    return week, sod + day * 86400


def sow2hms(sow):
    """ Change seconds of week to (day of week, hours, minutes and seconds) """
    """ not consider second slip now """
    sod = sow % (24*3600)
    dow = math.floor(sow/(24*3600)) + 1
    return dow, sod2hms(sod)


def sow2sod(sow):
    """ convert Second of Week to Second of Day """
    return sow % (24*3600)

Chap.II 调用示例

将上面的源码贴到文件中,然后在文件后面追加下面的内容:

def test():
    year = 2024
    mon = 4
    day = 28
    hor,min,sec=7,00,00
    mjd=ymd2mjd(year, mon, day)
    sod=hms2sod(hor,min,sec)
    print(mjd)
    print(sod)
    print(ymd2doy(year, mon, day))
    print(ymd2gpsweek(year, mon, day))
    print(sod2sow(mjd,sod))
    print(doy2ymd(2023, 310))

# -------- CALL -----------
test()

快捷键 F5 运行得到如下结果

60428.0
25200.0
119
(2312, 0)
(2312, 25200.0)
(11, 6)
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流浪猪头拯救地球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值