You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
be-optimumoh/src/utils.py

88 lines
2.6 KiB
Python

from datetime import datetime, timedelta, timezone
import re
from typing import Optional
from dateutil.relativedelta import relativedelta
import pytz
from src.config import TIMEZONE
def parse_relative_expression(date_str: str) -> Optional[datetime]:
"""
Parse relative date expressions using T (days), M (months), and Y (years)
Returns tuple of (datetime, type_description) or None if not a relative date
"""
pattern = r"^([HTMY])([+-]\d+)?$"
match = re.match(pattern, date_str)
if not match:
return None
unit, offset = match.groups()
offset = int(offset) if offset else 0
# Use UTC timezone for consistency
today = datetime.now(timezone.tzname("Asia/Jakarta"))
if unit == "H":
# For hours, keep minutes and seconds
result_time = today + timedelta(hours=offset)
return result_time
elif unit == "T":
return today + timedelta(days=offset)
elif unit == "M":
return today + relativedelta(months=offset)
elif unit == "Y":
return today + relativedelta(years=offset)
def parse_date_string(date_str: str) -> Optional[datetime]:
"""
Parse date strings in various formats including relative expressions
Returns tuple of (datetime, type)
"""
# Try parsing as relative expression first
relative_result = parse_relative_expression(date_str)
if relative_result:
return relative_result
# Try different date formats
date_formats = [
("%Y-%m-%d", "iso"), # 2024-11-08
("%Y/%m/%d", "slash"), # 2024/11/08
("%d-%m-%Y", "european"), # 08-11-2024
("%d/%m/%Y", "european_slash"), # 08/11/2024
("%Y.%m.%d", "dot"), # 2024.11.08
("%d.%m.%Y", "european_dot"), # 08.11.2024
]
for fmt, type_name in date_formats:
try:
# Parse the date and set it to start of day in UTC
dt = datetime.strptime(date_str, fmt)
dt = dt.replace(
hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.tzname("Asia/Jakarta")
)
return dt
except ValueError:
continue
raise ValueError(
"Invalid date format. Supported formats:\n"
"Relative formats:\n"
"- T (days): T, T-n, T+n\n"
"- M (months): M, M-1, M+2\n"
"- Y (years): Y, Y-1, Y+1\n"
"Regular formats:\n"
"- YYYY-MM-DD\n"
"- YYYY/MM/DD\n"
"- DD-MM-YYYY\n"
"- DD/MM/YYYY\n"
"- YYYY.MM.DD\n"
"- DD.MM.YYYY"
)
def time_now():
return datetime.now(pytz.timezone(TIMEZONE))