Source code for cadati.jd_date

# Copyright (c) 2023, TU Wien, Department of Geodesy and Geoinformation
# Distributed under the MIT License (see LICENSE.txt)

"""
Module provides function to convert julian dates into other date formats.
"""


import datetime
import numpy as np

from cadati.np_date import dt2cal
from cadati.check_date import is_leap_year


# leap year
days_past = np.array([0, 31, 60, 91, 121, 152, 182, 213,
                      244, 274, 305, 335, 366])


[docs]def julday(month, day, year, hour=0, minute=0, second=0): """ Julian date from month, day, and year. Adapted from "Numerical Recipes in C', 2nd edition, pp. 11 Parameters ---------- month : numpy.ndarray or int32 Month. day : numpy.ndarray or int32 Day. year : numpy.ndarray or int32 Year. hour : numpy.ndarray or int32, optional Hour. minute : numpy.ndarray or int32, optional Minute. second : numpy.ndarray or int32, optional Second. Returns ------- jd : numpy.ndarray or float64 Julian day. """ month = np.array(month) day = np.array(day) in_jan_feb = month <= 2 jy = year - in_jan_feb jm = month + 1 + in_jan_feb * 12 jd = np.int32(np.floor(365.25 * jy) + np.floor(30.6001 * jm) + (day + 1720995.0)) ja = np.int32(0.01 * jy) jd += 2 - ja + np.int32(0.25 * ja) jd = jd + hour / 24.0 - 0.5 + minute / 1440.0 + second / 86400.0 return jd
[docs]def caldat(jd): """ Calendar date (month, day, year) from julian date, inverse of 'julday()' Return value: month, day, and year in the Gregorian calendar. Adapted from "Numerical Recipes in C', 2nd edition, pp. 11 Works only for years past 1582! Parameters ---------- jd : numpy.ndarray or float64 Julian day. Returns ------- month : numpy.ndarray or int32 Month. day : numpy.ndarray or int32 Day. year : numpy.ndarray or int32 Year. """ jn = np.int32(((np.array(jd) + 0.000001).round())) jalpha = np.int32(((jn - 1867216) - 0.25) / 36524.25) ja = jn + 1 + jalpha - (np.int32(0.25 * jalpha)) jb = ja + 1524 jc = np.int32(6680.0 + ((jb - 2439870.0) - 122.1) / 365.25) jd2 = np.int32(365.0 * jc + (0.25 * jc)) je = np.int32((jb - jd2) / 30.6001) day = jb - jd2 - np.int32(30.6001 * je) month = je - 1 month = (month - 1) % 12 + 1 year = jc - 4715 year = year - (month > 2) return month, day, year
[docs]def julian2datetime(jd, tz=None): """ Converts julian date to python datetime. Default is not time zone aware. Parameters ---------- julian : float64 Julian date. Returns ------- dt : datetime Datetime object. """ year, month, day, hour, minute, second, microsecond = julian2date(jd) if type(jd) == np.array or type(jd) == np.memmap or \ type(jd) == np.ndarray or type(jd) == np.flatiter: return np.array([datetime.datetime(y, m, d, h, mi, s, ms, tz) for y, m, d, h, mi, s, ms in zip(np.atleast_1d(year), np.atleast_1d(month), np.atleast_1d(day), np.atleast_1d(hour), np.atleast_1d(minute), np.atleast_1d(second), np.atleast_1d(microsecond))]) return datetime.datetime(year, month, day, hour, minute, second, microsecond, tz)
[docs]def julian2num(jd): """ Convert a matplotlib date to a Julian days. Parameters ---------- jd : numpy.ndarray : int32 Julian days. Returns ------- num : numpy.ndarray : int32 Number of days since 0001-01-01 00:00:00 UTC *plus* *one*. """ return jd - 1721424.5
[docs]def num2julian(num): """ Convert a Julian days to a matplotlib date. Parameters ---------- num : numpy.ndarray : int32 Number of days since 0001-01-01 00:00:00 UTC *plus* *one*. Returns ------- jd : numpy.ndarray : int32 Julian days. """ return num + 1721424.5
def julian2date(jd, return_doy=False, doy_leap_year=True): """ Calendar date from julian date. Works only for years past 1582. Parameters ---------- jd : numpy.ndarray Julian day. return_doy : bool Add day of year to output. doy_leap_year : bool, optional Flag if leap year has to be respected or not (default: True). Returns ------- year : numpy.ndarray Year. month : numpy.ndarray Month. day : numpy.ndarray Day. hour : numpy.ndarray Hour. minute : numpy.ndarray Minute. second : numpy.ndarray Second. day_of_year : numpy.ndarray Day of year. Only returned when return_doy is set to True. """ min_julian = 2299160 max_julian = 1827933925 is_single_value = False if type(jd) in (float, int): is_single_value = True julian = np.atleast_1d(np.array(jd, dtype=float)) if np.min(julian) < min_julian or np.max(julian) > max_julian: raise ValueError("Value of Julian date is out of allowed range.") jn = (np.round(julian + 0.0000001)).astype(np.int32) jalpha = (((jn - 1867216) - 0.25) / 36524.25).astype(np.int32) ja = jn + 1 + jalpha - (np.int32(0.25 * jalpha)) jb = ja + 1524 jc = (6680.0 + ((jb - 2439870.0) - 122.1) / 365.25).astype(np.int32) jd2 = (365.0 * jc + (0.25 * jc)).astype(np.int32) je = ((jb - jd2) / 30.6001).astype(np.int32) day = jb - jd2 - np.int64(30.6001 * je) month = je - 1 month = (month - 1) % 12 + 1 year = jc - 4715 year = year - (month > 2) fraction = (julian + 0.5 - jn).astype(np.float64) eps = (np.float64(1e-12) * np.abs(jn)).astype(np.float64) eps.clip(min=np.float64(1e-12), max=None) hour = (fraction * 24. + eps).astype(np.int64) hour.clip(min=0, max=23) fraction -= hour / 24. minute = (fraction * 1440. + eps).astype(np.int64) minute = minute.clip(min=0, max=59) second = (fraction - minute / 1440.) * 86400. second = second.clip(min=0, max=None) microsecond = ((second - np.int32(second)) * 1e6).astype(np.int32) microsecond = microsecond.clip(min=0, max=999999) second = second.astype(np.int32) if is_single_value: year, month, day, hour, minute, second, microsecond = ( year.item(), month.item(), day.item(), hour.item(), minute.item(), second.item(), microsecond.item()) if return_doy: day_of_year = days_past[month - 1] + day if doy_leap_year: nonleap_years = np.invert(is_leap_year(year)) day_of_year = day_of_year - nonleap_years + np.logical_and( day_of_year < 60, nonleap_years) if is_single_value: day_of_year = day_of_year.item() return year, month, day, hour, minute, second, microsecond, day_of_year else: return year, month, day, hour, minute, second, microsecond def jd2dt(jd): """ Convert array of julian dates to numpy.datetime64[ms] array. Parameters ---------- jd : numpy.float64 Array of julian dates. Returns ------- dt : numpy.datetime64[ms] Array of dates in datetime64[ms] format. """ dt = ((((jd - 2440587.5)*24.*3600.*1e6).astype('datetime64[us]') + np.timedelta64(500, 'us')).astype('datetime64[ms]')) return dt def jd2cal(jd, doy_respect_nonleap_year=True): """ Convert array of julian dates to a calendar array of year, month, day, hour, minute, seconds, millisecond, day of year, with these quantites indexed on the last axis. Parameters ---------- dt : numpy.ndatetime64 numpy.ndarray of datetime64[ms] of arbitrary shape doy_respect_nonleap_year : bool, optional If True (default), leap years vary between 1-366 and non-leap years 1-365. If False, doy varies between 1-366 for all years. Returns ------- cal_dt : numpy.uint32 (..., 8) calendar array with last axis representing year, month, day, hour, minute, second, microsecond, day of year. """ return dt2cal(jd2dt(jd), doy_respect_nonleap_year) def jd2doy(jd, doy_respect_nonleap_year=True): """ Convert julian date to day of year. Parameters ---------- jd : numpy.float64 Array of julian dates. doy_respect_nonleap_year : bool, optional If True (default), leap years vary between 1-366 and non-leap years 1-365. If False, doy varies between 1-366 for all years. Returns ------- doy : numpy.int64 Day of year. """ return jd2cal(jd, doy_respect_nonleap_year)[..., 7]