Source code for pymarine.utils.date_time

"""
Several date/time helper functions.
"""

import argparse
import datetime
from time import strptime

import numpy as np


def _from_matlab_to_python_num_days(x):
    # Matlab epoch time start at the year 0, python at the 1-1-0001.
    # Both formats differ 366 days.
    # So to convert the matlab format to the python format, convert it here
    return (
        datetime.datetime.fromordinal(int(x))
        + datetime.timedelta(days=x % 1)
        - datetime.timedelta(days=366)
    )


_from_matlab_to_python_num_days_vectorized = np.vectorize(
    _from_matlab_to_python_num_days
)


[docs] def matlabnum2date(x): """Convert a Matlab numerical date/time representation into a Python datetime object Parameters ---------- Parameters ---------- x : float or ndarrray Matlab numerical date/time representation giving the number of days since 0000 00 00:00:00 Returns ------- number_of_days : ndarray or scalar of the type datetime` Date/time corresponding to the float value `x` Notes ----- * In Matlab, the numerical date/time representation gives the number of days since Jan 00 0000 00:00:00 * In Python, the numerical date/time representation gives the number of days since Jan 01 0001 00:00:00 * To convert from matlab to python, 366 days need to be subtracted from the matlab numerical date/time representation to get the Python numerical data/time representation (note that matlab starts at Jan 0th!) Examples -------- The following two dates in numerical representation are obtained using the Matlab `datenum` function * 2012-12-21T12:12:12 -> 7.352245084722222e+05 # days since 0000 00 00:00:00 * 1973-11-12T09:15:43 -> 7.209403859143519e+05 # days since 0000 00 00:00:00 >>> num_date_matlab = np.array([7.352245084722222222222222e+05, ... 7.209403859143519e+05]) >>> matlabnum2date(num_date_matlab) array([datetime.datetime(2012, 12, 21, 12, 12, 12, 3), datetime.datetime(1973, 11, 12, 9, 15, 43, 5)], dtype=object) """ try: number_of_days = _from_matlab_to_python_num_days(x) except TypeError: x = np.asarray(x) if not x.size: raise number_of_days = _from_matlab_to_python_num_days_vectorized(x) return number_of_days
[docs] def valid_date(s): """Check if supplied data *s* is a valid date for the format Year-Month-Day Parameters ---------- s : str A valid date in the form of YYYY-MM-DD, so first the year, then the month, then the day Returns ------- datetime Date object with the year, month, day obtained from the valid string representation Raises ------ argparse.ArgumentTypeError: Notes ----- This is a helper function for the argument parser module argparse which allows you to check if the argument passed on the command line is a valid date. Examples -------- This is the direct usage of `valid_date` to see if the date supplied is of format YYYY-MM-DD >>> try: ... date = valid_date("1973-11-12") ... except argparse.ArgumentTypeError: ... print("This date is invalid") ... else: ... print("This date is valid") This date is valid In case an invalid date is supplied >>> try: ... date = valid_date("1973-15-12") ... except argparse.ArgumentTypeError: ... print("This date is invalid") ... else: ... print("This date is valid") This date is invalid Here it is demonstrated how to add a '--startdate' command line option to the argparse parser which checks if a valid date is supplied >>> parser = argparse.ArgumentParser() >>> p = parser.add_argument("--startdate", ... help="The Start Date - format YYYY-MM-DD ", ... required=True, ... type=valid_date) References ---------- https://stackoverflow.com/questions/25470844/ specify-format-for-input-arguments-argparse-python """ try: return strptime(s, "%Y-%m-%d") except ValueError: msg = f"Not a valid date: '{s}'.\nSupply date as YYYY-MM-DD" raise argparse.ArgumentTypeError(msg)