"""Date and time utilities.""" import re from datetime import datetime from abacus_common_logic.constants.constants import ( DATE_FORMAT, DATETIME_FORMAT, OPERATING_TIMEZONE, SYSTEM_TIMEZONE, ) DATE_REGEXP = r'([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])' TIME_REGEXP = r'([01][0-9]|2[0123]):([0-5][0-9]):([0-5][0-9])' ISO_DATETIME_REGEXP = re.compile( rf'^{DATE_REGEXP}T{TIME_REGEXP}\.\d\d\d\d\d\d([\+-]\d\d:\d\d)?$' ) def safe_format_date(date, fmt=DATE_FORMAT): """Format a date.""" return date and date.strftime(fmt) def safe_format_datetime(date_time, fmt=DATETIME_FORMAT): """Format datetime to string value.""" return date_time and date_time.strftime(fmt) def parse_date(date_string, fmt=DATE_FORMAT): """Attempt to parse a date string using provided date format.""" return datetime.strptime(date_string, fmt).date() def parse_datetime(datetime_string, fmt=DATETIME_FORMAT): """Parse a datetime string and return datetime object.""" return datetime.strptime(datetime_string, fmt) def current_timestamp(timezone=SYSTEM_TIMEZONE): """Return the current timestamp in the internal system timezone.""" return datetime.now(timezone) def operating_date(timestamp, operating_tz=OPERATING_TIMEZONE): """Given a timestamp, return its date in the operating timezone. If the timestamp is not timezone-aware, it is assumed to be in UTC. """ with_tz = ( timestamp if timestamp.tzinfo else timestamp.replace(tzinfo=SYSTEM_TIMEZONE) ) return with_tz.astimezone(operating_tz).date() def is_iso_datetime(str_datetime): """Check if given string value matches iso datetime format.""" return bool(ISO_DATETIME_REGEXP.match(str_datetime))