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.
91 lines
2.6 KiB
Python
91 lines
2.6 KiB
Python
import re
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Optional
|
|
|
|
import pytz
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
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))
|