Source code for l3py.time
# Copyright (c) 2020 Andreas Kvas
# See LICENSE for copyright/license details.
""""
Convenience functions for Python datetime objects
"""
import datetime as dt
import calendar as cal
def __mjd_fepoch():
return dt.datetime(1858, 11, 17)
def __gps_fepoch():
return dt.datetime(1980, 1, 6)
def mjd(dtime):
"""
Convert datetime.datetime object to MJD.
Parameters
----------
dtime : datetime.datetime
datetime.datetime object
Returns
-------
mjd : float
datetime.datetime object expressed in modified julian date
"""
delta = (dtime - __mjd_fepoch())
return delta.days + delta.seconds/86400.0
def datetime(mjd):
"""
Convert MJD to datetime.datetime object
Parameters
----------
mjd : float
datetime.datetime object expressed in modified julian date
Returns
-------
dtime : datetime.datetime
datetime.datetime object
"""
return __mjd_fepoch() + dt.timedelta(days=mjd)
def date_iterator(start, stop, step):
"""
Generator for a sequence of datetime objects.
To be consistent with Python ranges, the last epoch generated will be strictly less than `stop`.
Parameters
----------
start : datetime object
first epoch
stop : datetime object
upper bound of datetime sequence, last epoch will be strictly less than stop
step : timedelta object
step size of sequence (negative steps are allowed)
Returns
-------
g : Generator object
Generator for datetime objects
"""
if step.total_seconds() == 0.0:
raise ValueError('Step size must not be zero')
op = dt.datetime.__gt__ if step.total_seconds() < 0 else dt.datetime.__lt__
current = start
while op(current, stop):
yield current
current += step
def month_iterator(start, stop, use_middle=False):
"""
Generator for a monthly sequence of datetime objects.
To be consistent with Python ranges, the last epoch generated will be strictly less than `stop`.
Parameters
----------
start : datetime object
epoch from which the first month will be generated
stop : datetime object
epoch from which the last month will be generated (last month will be strictly less than stop)
use_middle : bool
If True, the midpoint of each month will be returned, otherwise the first of each month is used (default: False)
Returns
-------
g : Generator object
Generator for monthly datetime objects
"""
current = dt.datetime(start.year, start.month,
round(cal.monthrange(start.year, start.month)[1]*0.5) if use_middle else 1)
while current < stop:
yield current
roll_over = (current.month == 12)
next_year = current.year+1 if roll_over else current.year
next_month = 1 if roll_over else current.month+1
next_day = round(cal.monthrange(next_year, next_month)[1]*0.5) if use_middle else current.day
current = dt.datetime(next_year, next_month, next_day)
def day_iterator(start, stop, use_middle=False):
"""
Generator for a daily sequence of datetime objects.
To be consistent with Python ranges, the last epoch generated will be strictly less than `stop`.
Parameters
----------
start : datetime object
epoch from which the first day will be generated
stop : datetime object
epoch from which the last day will be generated (last month will be strictly less than stop)
use_middle : bool
If True, the midpoint of each day (12:00) will be returned, otherwise 00:00 used (default: False)
Returns
-------
g : Generator object
Generator for monthly datetime objects
"""
current = dt.datetime(start.year, start.month, start.day, 12 if use_middle else 0)
while current < stop:
yield current
current += dt.timedelta(days=1)
def decyear2mjd(dy):
"""
Convert decimal year to MJD.
Parameters
----------
dy : float
epoch as decimal year
Returns
-------
mjd : float
epoch as MJD
"""
y0 = mjd(dt.datetime(int(dy), 1, 1))
y1 = mjd(dt.datetime(int(dy)+1, 1, 1))
return (dy-int(dy))*(y1-y0)+y0
def mjd2decyear(t_mjd):
"""
Convert MJD to decimal year.
Parameters
----------
mjd : float
epoch as MJD
Returns
-------
dy : float
epoch as decimal year
"""
t = datetime(t_mjd)
length = 366.0 if cal.isleap(t.year) else 365.0
days = (t - dt.datetime(t.year, 1, 1)).days
return float(t.year) + days/length
def gpsweekday(dt):
"""
Compute GPS week and day in week from datetime object
Parameters
----------
dt : datetime.datetime
epoch as datetime object
Returns
-------
week : int
GPS week
days : int
day in GPS week
"""
delta = dt - __gps_fepoch()
week = delta.days//7
days = delta.days - week*7
return week, days
def gpsweekseconds(dt):
"""
Compute GPS week and seconds in week from datetime object
Parameters
----------
dt : datetime.datetime
epoch as datetime object
Returns
-------
week : int
GPS week
seconds : float
seconds in GPS week
"""
delta = dt - __gps_fepoch()
week = delta.days//7
days = delta.total_seconds() - week*7*86400
return week, days
def gpsweekday2datetime(week, day):
"""
Convert GPS week and day in week to datetime object.
Parameters
----------
week : int
GPS week
days : int
day in GPS week
Returns
-------
dt : datetime.datetime
epoch as datetime objec
"""
delta = dt.timedelta(days=week*7+day)
return __gps_fepoch() + delta