Module: date_util
Expand source code
# Copyright (C) 2023-present The Project Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime as dt
import re
from typing import Tuple
# Compile the regex pattern for date in ISO-8601 format yyyy-mm-dd
date_pattern = re.compile(r"^d{4}-d{2}-d{2}$")
class DateUtil:
"""Utility class for dt.date."""
@classmethod
def to_str(cls, value: dt.date) -> str:
"""Convert to string in ISO-8601 format: 'yyyy-mm-dd'"""
result = f"{value.year:04}-{value.month:02}-{value.day:02}"
return result
@classmethod
def from_str(cls, value: str) -> dt.date:
"""Convert from string in ISO-8601 format: 'yyyy-mm-dd'"""
# Validate string format
cls.validate_str(value)
# Convert to date using strict parsing
result = dt.date.fromisoformat(value)
return result
@classmethod
def to_fields(cls, value: dt.date) -> Tuple[int, int, int]:
"""Convert dt.date to fields."""
return value.year, value.month, value.day
@classmethod
def from_fields(cls, year: int, month: int, day: int) -> dt.date:
"""Convert fields to dt.date."""
result = dt.date(year, month, day)
return result
@classmethod
def to_iso_int(cls, value: dt.date) -> int:
"""Convert dt.date in yyyymmdd format."""
result = 1_00_00 * value.year + 1_00 * value.month + value.day
return result
@classmethod
def from_iso_int(cls, value: int) -> dt.date:
"""Convert int in yyyymmdd format."""
if value < 10000000:
raise RuntimeError(f"Date {value} is too short for 'yyyymmdd' format.")
if value > 99999999:
raise RuntimeError(f"Date {value} is too long for 'yyyymmdd' format.")
year: int = value // 1_00_00
value -= year * 1_00_00
if year > 9999 or year < 1899:
raise RuntimeError(f"Invalid year {year} for date {value} in 'yyyymmdd' format.")
month: int = value // 1_00
value -= month * 1_00
if month > 12 or month < 1:
raise RuntimeError(f"Invalid month {month} for date {value} in 'yyyymmdd' format.")
day: int = value
if day > 31 or day < 1:
raise RuntimeError(f"Invalid day {day} for date {value} in 'yyyymmdd' format.")
result = dt.date(year, month, day)
return result
@classmethod
def validate_str(cls, value: str) -> None:
"""Validate that date string is in ISO-8601 format: 'yyyy-mm-dd'"""
if not date_pattern.match(value):
raise RuntimeError(f"Date string {value} must be in ISO-8601 format: 'yyyy-mm-dd'.")
Classes
class DateUtil
-
Utility class for dt.date.
Expand source code
class DateUtil: """Utility class for dt.date.""" @classmethod def to_str(cls, value: dt.date) -> str: """Convert to string in ISO-8601 format: 'yyyy-mm-dd'""" result = f"{value.year:04}-{value.month:02}-{value.day:02}" return result @classmethod def from_str(cls, value: str) -> dt.date: """Convert from string in ISO-8601 format: 'yyyy-mm-dd'""" # Validate string format cls.validate_str(value) # Convert to date using strict parsing result = dt.date.fromisoformat(value) return result @classmethod def to_fields(cls, value: dt.date) -> Tuple[int, int, int]: """Convert dt.date to fields.""" return value.year, value.month, value.day @classmethod def from_fields(cls, year: int, month: int, day: int) -> dt.date: """Convert fields to dt.date.""" result = dt.date(year, month, day) return result @classmethod def to_iso_int(cls, value: dt.date) -> int: """Convert dt.date in yyyymmdd format.""" result = 1_00_00 * value.year + 1_00 * value.month + value.day return result @classmethod def from_iso_int(cls, value: int) -> dt.date: """Convert int in yyyymmdd format.""" if value < 10000000: raise RuntimeError(f"Date {value} is too short for 'yyyymmdd' format.") if value > 99999999: raise RuntimeError(f"Date {value} is too long for 'yyyymmdd' format.") year: int = value // 1_00_00 value -= year * 1_00_00 if year > 9999 or year < 1899: raise RuntimeError(f"Invalid year {year} for date {value} in 'yyyymmdd' format.") month: int = value // 1_00 value -= month * 1_00 if month > 12 or month < 1: raise RuntimeError(f"Invalid month {month} for date {value} in 'yyyymmdd' format.") day: int = value if day > 31 or day < 1: raise RuntimeError(f"Invalid day {day} for date {value} in 'yyyymmdd' format.") result = dt.date(year, month, day) return result @classmethod def validate_str(cls, value: str) -> None: """Validate that date string is in ISO-8601 format: 'yyyy-mm-dd'""" if not date_pattern.match(value): raise RuntimeError(f"Date string {value} must be in ISO-8601 format: 'yyyy-mm-dd'.")
Static methods
def from_fields(year: int, month: int, day: int) -> datetime.date
-
Convert fields to dt.date.
def from_iso_int(value: int) -> datetime.date
-
Convert int in yyyymmdd format.
def from_str(value: str) -> datetime.date
-
Convert from string in ISO-8601 format: ‘yyyy-mm-dd’
def to_fields(value: datetime.date) -> Tuple[int, int, int]
-
Convert dt.date to fields.
def to_iso_int(value: datetime.date) -> int
-
Convert dt.date in yyyymmdd format.
def to_str(value: datetime.date) -> str
-
Convert to string in ISO-8601 format: ‘yyyy-mm-dd’
def validate_str(value: str) -> None
-
Validate that date string is in ISO-8601 format: ‘yyyy-mm-dd’