mt_metadata.common.mttime ========================= .. py:module:: mt_metadata.common.mttime .. autoapi-nested-parse:: Created on Wed May 13 19:10:46 2020 For dealing with obsy.core.UTCDatetime and an soft requirement imports have a look at https://github.com/pydantic/pydantic/discussions/3673. @author: jpeacock Attributes ---------- .. autoapisummary:: mt_metadata.common.mttime.from_obspy mt_metadata.common.mttime.leap_second_dict mt_metadata.common.mttime.TMIN mt_metadata.common.mttime.TMAX Classes ------- .. autoapisummary:: mt_metadata.common.mttime.MTime mt_metadata.common.mttime.MDate Functions --------- .. autoapisummary:: mt_metadata.common.mttime.calculate_leap_seconds mt_metadata.common.mttime.parse mt_metadata.common.mttime.get_now_utc Module Contents --------------- .. py:data:: from_obspy :value: True .. py:data:: leap_second_dict .. py:function:: calculate_leap_seconds(year, month, day) Get the leap seconds for the given year to convert GPS time to UTC time. GPS time started in 1980. GPS time is leap seconds ahead of UTC time, therefore you should subtract leap seconds from GPS time to get UTC time. :param year: Year of the date. :type year: int :param month: Month of the date (1-12). :type month: int :param day: Day of the date (1-31). :type day: int :returns: Number of leap seconds for the given date. :rtype: int :raises ValueError: If the date is outside the defined leap second range (1981-07-01 to 2026-07-01). .. rubric:: Notes Leap seconds are defined for the following date ranges: =========================== =============================================== Date Range Leap Seconds =========================== =============================================== 1981-07-01 - 1982-07-01 1 1982-07-01 - 1983-07-01 2 1983-07-01 - 1985-07-01 3 1985-07-01 - 1988-01-01 4 1988-01-01 - 1990-01-01 5 1990-01-01 - 1991-01-01 6 1991-01-01 - 1992-07-01 7 1992-07-01 - 1993-07-01 8 1993-07-01 - 1994-07-01 9 1994-07-01 - 1996-01-01 10 1996-01-01 - 1997-07-01 11 1997-07-01 - 1999-01-01 12 1999-01-01 - 2006-01-01 13 2006-01-01 - 2009-01-01 14 2009-01-01 - 2012-07-01 15 2012-07-01 - 2015-07-01 16 2015-07-01 - 2017-01-01 17 2017-01-01 - ????-??-?? 18 =========================== =============================================== .. py:data:: TMIN .. py:data:: TMAX .. py:function:: parse(dt_str = None, gps_time = False) Parse a datetime input into a pandas Timestamp with UTC timezone. Accepts various input types and converts them to a standardized pandas Timestamp object. Handles special cases like GPS time conversion, nanosecond timestamps, and out-of-bounds dates. :param dt_str: Input to be parsed. Can be: - None, empty string, or "none" variants: returns default 1980-01-01 - float/int: interpreted as epoch seconds (or nanoseconds if large) - numpy numeric types: converted to standard Python types first - pd.Timestamp: validated and timezone-corrected - str: parsed using dateutil.parser with flexible formatting - dict: extracted time_stamp and gps_time fields Default is None. :type dt_str: float, int, np.number, np.datetime64, pd.Timestamp, str, dict, or None, optional :param gps_time: If True, converts GPS time to UTC by subtracting leap seconds. Default is False. :type gps_time: bool, optional :returns: UTC-localized timestamp object. :rtype: pd.Timestamp :raises ValueError: If input is before GPS start time when gps_time=True. If string parsing fails with invalid format. .. rubric:: Notes - Large numeric inputs (ratio > 1000 vs 3e8) are assumed to be nanoseconds - Timestamps outside pandas bounds are clamped to min/max values - GPS time conversion uses calculated leap seconds for the date - All outputs are forced to UTC timezone regardless of input timezone .. py:class:: MTime(/, **data) Bases: :py:obj:`pydantic.BaseModel` Date and time container based on pandas.Timestamp with UTC enforcement. A flexible datetime container that accepts various input formats and converts them to a UTC-localized pandas.Timestamp object. Provides convenient access to date/time components and handles nanosecond precision. :param time_stamp: Input timestamp in various formats: - float/int: epoch seconds - np.number: numpy numeric types (converted to Python types) - np.datetime64: numpy datetime - pd.Timestamp: pandas timestamp (will be UTC-localized) - str: ISO format or parseable date string - None: defaults to 1980-01-01T00:00:00+00:00 Default is None. :type time_stamp: float, int, np.number, np.datetime64, pd.Timestamp, str, or None, optional :param gps_time: If True, interprets time_stamp as GPS time and converts to UTC. Default is False. :type gps_time: bool, optional .. attribute:: time_stamp The stored timestamp, always UTC-localized. :type: pd.Timestamp .. attribute:: gps_time Whether GPS time conversion was applied. :type: bool .. rubric:: Notes The pandas.Timestamp backend allows nanosecond precision timing. Input values outside pandas timestamp bounds are automatically clamped: - Values > 2200: set to pandas.Timestamp.max (2262-04-11 23:47:16.854775807) - Values < 1900: set to pandas.Timestamp.min (1677-09-21 00:12:43.145224193) All timestamps are forced to UTC timezone regardless of input timezone. .. rubric:: Examples Create from various input types: >>> t = MTime() # Default time >>> t.isoformat() '1980-01-01T00:00:00+00:00' >>> t = MTime(time_stamp="2020-01-15T12:30:45") >>> t.year 2020 >>> t = MTime(time_stamp=1579095045.0) # Epoch seconds >>> t.isoformat() '2020-01-15T12:30:45+00:00' Access and modify components: >>> t.year = 2025 >>> t.month = 12 >>> t.day = 31 >>> t.epoch_seconds 1767225045.0 .. py:attribute:: model_config Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict]. .. py:attribute:: gps_time :type: Annotated[bool, Field(description='Defines if the time give in GPS time [True] or UTC [False]', default=False, json_schema_extra={'units': None, 'required': False, 'examples': [True, False]})] :value: False .. py:attribute:: time_stamp :type: Annotated[float | int | numpy.number | numpy.datetime64 | pandas.Timestamp | str | None, Field(default_factory=lambda: pd.Timestamp(MTime._default_time.default), description='Time in UTC format', examples=['1980-01-01T00:00:00+00:00'])] .. py:method:: validate_time_stamp(field_value, validation_info) :classmethod: Validate and convert input timestamp to pandas Timestamp. Pydantic field validator that processes various timestamp input formats and converts them to a standardized UTC pandas Timestamp object. :param field_value: Input timestamp value in any supported format. :type field_value: float, int, np.datetime64, pd.Timestamp, str, or UTCDateTime :param validation_info: Pydantic validation context containing model data including gps_time setting. :type validation_info: ValidationInfo :returns: UTC-localized timestamp object, clamped to pandas bounds if necessary. :rtype: pd.Timestamp .. rubric:: Notes This method is automatically called during model instantiation. GPS time conversion is applied if gps_time=True in the model data. Out-of-bounds timestamps are automatically clamped to valid ranges. .. py:method:: is_default() Test if the time_stamp value is the default value .. py:method:: to_dict(nested=False, single=False, required=True) Convert the time stamp to a dictionary with the ISO format string. :returns: The ISO format string. :rtype: str .. py:method:: from_dict(value, skip_none=False) This will have to accept just a single value, not a dict. This is to keep original functionality. :param value: time stamp value :type value: str | int | float | np.datetime64 | pd.Timestamp .. py:property:: iso_str :type: str returns: ISO formatted string of the time stamp. :rtype: str .. py:property:: iso_no_tz :type: str ISO formatted string of the time stamp without the timezone. This is useful for storing the time stamp in a database or other format where the timezone is not needed. :returns: ISO formatted string of the time stamp without the timezone. :rtype: str .. py:property:: epoch_seconds :type: float Epoch seconds of the time stamp. This is the number of seconds since the epoch (1970-01-01 00:00:00 UTC). :returns: epoch seconds of the time stamp. :rtype: float .. py:property:: date :type: str Date in ISO format. This is the date part of the time stamp without the time part. This is useful for storing the date in a database or other format where the time is not needed. The date is in the format YYYY-MM-DD. :returns: ISO formatted date string of the time stamp. :rtype: str .. py:property:: year :type: int Year of the time stamp :returns: year of the time stamp :rtype: int .. py:property:: month :type: int Month of the time stamp. This is the month part of the time stamp without the time part. This is useful for storing the month in a database or other format where the time is not needed. :returns: month of time stamp :rtype: int .. py:property:: day :type: int Day of the time stamp. This is the day part of the time stamp without the time part. :returns: Day of the time stamp :rtype: int .. py:property:: hour :type: int Hour of the time stamp. :returns: hour of the time stamp :rtype: int .. py:property:: minutes :type: int .. py:property:: seconds :type: int .. py:property:: microseconds :type: int .. py:property:: nanoseconds :type: int .. py:method:: now() The current time in UTC format. :returns: The current time as an MTime object. :rtype: MTime .. py:method:: copy() make a copy of the time .. py:method:: isoformat() ISO formatted string of the time stamp. This is the ISO format string of the time stamp. formatted as: YYYY-MM-DDThh:mm:ss.ssssss+00:00 :returns: ISO formatted date time string :rtype: str .. py:method:: isodate() ISO formatted date string of the time stamp. This is the ISO format string of the date part of the time stamp. formatted as: YYYY-MM-DD :returns: _description_ :rtype: str .. py:method:: isocalendar() ISO formatted calendar string of the time stamp. This is the ISO format string of the calendar part of the time stamp. Formatted as: YYYY-WW-D where YYYY is the year, WW is the week number, and D is the day of the week. :returns: ISO formatted calendar string of the time stamp. :rtype: str .. py:function:: get_now_utc() Get the current UTC time as an MTime object. Creates an MTime instance set to the current UTC time. :returns: ISO format string of the current UTC time. :rtype: str .. rubric:: Notes Despite the return type annotation suggesting MTime, this function actually returns an ISO format string from the MTime object. .. py:class:: MDate(/, **data) Bases: :py:obj:`MTime` Date and time container based on pandas.Timestamp with UTC enforcement. A flexible datetime container that accepts various input formats and converts them to a UTC-localized pandas.Timestamp object. Provides convenient access to date/time components and handles nanosecond precision. :param time_stamp: Input timestamp in various formats: - float/int: epoch seconds - np.number: numpy numeric types (converted to Python types) - np.datetime64: numpy datetime - pd.Timestamp: pandas timestamp (will be UTC-localized) - str: ISO format or parseable date string - None: defaults to 1980-01-01T00:00:00+00:00 Default is None. :type time_stamp: float, int, np.number, np.datetime64, pd.Timestamp, str, or None, optional :param gps_time: If True, interprets time_stamp as GPS time and converts to UTC. Default is False. :type gps_time: bool, optional .. attribute:: time_stamp The stored timestamp, always UTC-localized. :type: pd.Timestamp .. attribute:: gps_time Whether GPS time conversion was applied. :type: bool .. rubric:: Notes The pandas.Timestamp backend allows nanosecond precision timing. Input values outside pandas timestamp bounds are automatically clamped: - Values > 2200: set to pandas.Timestamp.max (2262-04-11 23:47:16.854775807) - Values < 1900: set to pandas.Timestamp.min (1677-09-21 00:12:43.145224193) All timestamps are forced to UTC timezone regardless of input timezone. .. rubric:: Examples Create from various input types: >>> t = MTime() # Default time >>> t.isoformat() '1980-01-01T00:00:00+00:00' >>> t = MTime(time_stamp="2020-01-15T12:30:45") >>> t.year 2020 >>> t = MTime(time_stamp=1579095045.0) # Epoch seconds >>> t.isoformat() '2020-01-15T12:30:45+00:00' Access and modify components: >>> t.year = 2025 >>> t.month = 12 >>> t.day = 31 >>> t.epoch_seconds 1767225045.0 .. py:method:: is_default() Test if time_stamp is the default value .. py:method:: isoformat() ISO formatted string of the time stamp. This is the ISO format string of the time stamp. formatted as: YYYY-MM-DDThh:mm:ss.ssssss+00:00 :returns: ISO formatted date time string :rtype: str .. py:method:: to_dict(nested=False, single=False, required=True) Convert the time stamp to a dictionary with the ISO format string. :returns: The ISO format string. :rtype: str .. py:method:: from_dict(value, skip_none=False) This will have to accept just a single value, not a dict. This is to keep original functionality. :param value: time stamp value :type value: str | int | float | np.datetime64 | pd.Timestamp