""" AUTHOR: Khushal P Soonderji DATE: Friday, 21st jun, 2024 OBJECTIVE: To provide an easy way to work with time. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys sys.path.append(".") sys.path.append("..") # For date and time handling: import pytz from datetime import datetime, timedelta import dateparser # To handle date-time objects from a Numpy array and Pandas Dataframe: import numpy as np import pandas as pd # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # Date-Time Formats: DATE_TIME_FORMATS = ( "%d/%m/%y", "%d-%b-%y", "%d-%m-%y", "%d.%m.%y", "%d/%m/%Y", "%d-%b-%Y", "%d-%m-%Y", "%d.%m.%Y", "%d/%b", "%d%m%Y", "%Y%m%d", "%Y-%m-%d %H:%M:%S" ) # Useful Timezones: TIMEZONE_UTC = pytz.timezone("UTC") TIMEZONE_IST = pytz.timezone("Asia/Kolkata") TIMEZONE_ET = pytz.timezone("America/New_York") TIMEZONE_CT = pytz.timezone("America/Chicago") TIMEZONE_MT = pytz.timezone("America/Denver") TIMEZONE_PT = pytz.timezone("America/Los_Angeles") TIMEZONE_JST = pytz.timezone("Asia/Tokyo") TIMEZONE_CET = pytz.timezone("Europe/Paris") TIMEZONE_GMT = pytz.timezone("GMT") TIMEZONE_AEST = pytz.timezone("Australia/Sydney") TIMEZONE_NZST = pytz.timezone("Pacific/Auckland") TIMEZONE_CST = pytz.timezone("Asia/Shanghai") TIMEZONE_KST = pytz.timezone("Asia/Seoul") TIMEZONE_MSK = pytz.timezone("Europe/Moscow") TIMEZONE_BRT = pytz.timezone("America/Sao_Paulo") TIMEZONE_GST = pytz.timezone("Asia/Dubai") TIMEZONE_SAST = pytz.timezone("Africa/Johannesburg") TIMEZONE_AST = pytz.timezone("Asia/Riyadh") # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** def translate_date_time_string( datetime_string, source_format = None, destination_format = "%Y-%m-%dT%H:%M:%S" ): """ To convert an input datetime string to a different format. :param datetime_string: The datetime string to translate. :param source_format: The current format of the string. If not provided, dateparser will be used. :param destination_format: The format to convert to. :return: The converted datetime string. """ try: if source_format is None: datetime_obj = dateparser.parse(datetime_string) else: datetime_obj = datetime.strptime(datetime_string, source_format) return datetime_obj.strftime(destination_format) except Exception as exception: return None # --------------------------------------------------------------------------------------------------------------------- def parse_date_time(input_value, timezone = None, date_formats = None): """ To take any kind of input and interpret the datetime from it. :param input_value: Either a string or an integer or some form of datetime representation. :param timezone: The timezone to apply to the interpreted datetime. EXISTING TIMEZONE INFO WILL BE OVERWRITTEN. :param date_formats: The string formats to consider when parsing a string input. :return: The parsed datetime or null. """ datetime_object = None date_formats = date_formats or DATE_TIME_FORMATS # It could either be in seconds or milliseconds from epoch time's base date (January 1, 1970), # or it could be days since Microsoft Excel's base date (December 31, 1899). if isinstance(input_value, (int, float, np.number)) and not np.isnan(input_value): if input_value > 9999999999.0: datetime_object = datetime.fromtimestamp(input_value / 1000.0) if input_value > 999999.0: datetime_object = datetime.fromtimestamp(input_value) else: datetime_object = datetime.fromtimestamp(input_value * 24 * 60 * 60.0) - timedelta(days = 25569) # The input can even be a pre-formatted date: if isinstance(input_value, str): datetime_object = dateparser.parse( input_value, date_formats = date_formats, settings = { "DATE_ORDER": "DMY", "PREFER_DAY_OF_MONTH": "first", } ) # If the type is a datetime object, then return it as it is: if isinstance(input_value, datetime): datetime_object = input_value # If the type is the native datetime format of pandas: if isinstance(input_value, pd._libs.tslibs.timestamps.Timestamp): datetime_object = input_value.to_pydatetime() # Process the timezone: if datetime_object is not None and timezone is not None: datetime_object = as_if_timezone(datetime_object, timezone) # Done here: return datetime_object # --------------------------------------------------------------------------------------------------------------------- def get_current_date_time(timezone = None, as_string = False): """ Returns the current time as a datetime object. :param timezone: The timezone to apply to the returned datetime. :param as_string: Whether, or not, you want the output as a string. :return: The datetime object/string representing the current time. """ if timezone is not None and isinstance(timezone, str): timezone = pytz.timezone(timezone) now = datetime.now(timezone) return now.isoformat() if as_string else now # --------------------------------------------------------------------------------------------------------------------- def get_current_ist_date_time(as_string = False): """ Gives out the current time in IST timezone. :param as_string: Whether, or not, you want the output as a string. :return: The datetime object or string representing the current time. """ return get_current_date_time( timezone = TIMEZONE_IST, as_string = as_string ) # --------------------------------------------------------------------------------------------------------------------- def get_current_utc_date_time(as_string = False): """ Gives out the current time in UTC timezone. :param as_string: Whether, or not, you want the output as a string. :return: The datetime object or string representing the current time. """ return get_current_date_time( timezone = TIMEZONE_UTC, as_string = as_string ) # --------------------------------------------------------------------------------------------------------------------- def as_if_timezone(datetime_object, timezone): """ Ignores existing timezone info and applies the intended timezone. The time stays the same, only the timezone marker changes. e.g. for IST to UTC: 2024-08-09 00:00:00+05:30 --> 2024-08-09 00:00:00+00:00 HINT: IT PRETENDS "AS IF" THE TIMEZONE WAS THE INPUT TIMEZONE. :param datetime_object: The datetime object on which the timezone needs to be applied. :param timezone: The timezone that needs to be applied. :return: A timezone-aware datetime object. """ tz_object = pytz.timezone(timezone) if isinstance(timezone, str) else timezone return tz_object.localize(datetime_object.replace(tzinfo = None)) # --------------------------------------------------------------------------------------------------------------------- def to_timezone(datetime_object, timezone): """ Converts from one timezone to another. The time is adjusted by computing the difference between the two timezones. NOTE: THIS FUNCTION ASSUMES THE INPUT WAS IN UTC IF THE INPUT WAS TIMEZONE-NAIVE. e.g. for IST to UTC: 2024-08-09 00:00:00+05:30 --> 2024-08-08 18:30:00+00:00 :param datetime_object: The datetime object on which the timezone needs to be applied. :param timezone: The timezone that needs to be applied. :return: A timezone-aware datetime object. """ if isinstance(timezone, str): timezone = pytz.timezone(timezone) if datetime_object.tzinfo is None: return datetime_object.replace(tzinfo = TIMEZONE_UTC) return datetime_object.astimezone(timezone) # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass