151 lines
4.9 KiB
Python
151 lines
4.9 KiB
Python
#!/usr/bin/env python3.9
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
JFinal TimeKit - Date and Time Utilities
|
|
"""
|
|
|
|
from datetime import datetime, date, time, timedelta
|
|
from typing import Union
|
|
import threading
|
|
|
|
class TimeKit:
|
|
"""Date and time utility class"""
|
|
|
|
_formatters = {}
|
|
_sdf_cache = threading.local()
|
|
|
|
@staticmethod
|
|
def _get_sdf(pattern: str):
|
|
"""Get thread-local SimpleDateFormat equivalent"""
|
|
if not hasattr(TimeKit._sdf_cache, 'formatters'):
|
|
TimeKit._sdf_cache.formatters = {}
|
|
|
|
if pattern not in TimeKit._sdf_cache.formatters:
|
|
TimeKit._sdf_cache.formatters[pattern] = _SimpleDateFormat(pattern)
|
|
|
|
return TimeKit._sdf_cache.formatters[pattern]
|
|
|
|
@staticmethod
|
|
def now(pattern: str = "yyyy-MM-dd HH:mm:ss") -> str:
|
|
"""Get current time as string"""
|
|
return datetime.now().strftime(TimeKit._to_python_pattern(pattern))
|
|
|
|
@staticmethod
|
|
def now_with_millisecond() -> str:
|
|
"""Get current time with millisecond precision"""
|
|
return datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3]
|
|
|
|
@staticmethod
|
|
def format(dt: Union[datetime, date], pattern: str = "yyyy-MM-dd HH:mm:ss") -> str:
|
|
"""Format datetime or date to string"""
|
|
python_pattern = TimeKit._to_python_pattern(pattern)
|
|
|
|
if isinstance(dt, datetime):
|
|
return dt.strftime(python_pattern)
|
|
elif isinstance(dt, date):
|
|
return dt.strftime(TimeKit._to_python_pattern(pattern))
|
|
elif isinstance(dt, time):
|
|
return dt.strftime(TimeKit._to_python_pattern(pattern))
|
|
else:
|
|
raise ValueError(f"Unsupported type: {type(dt)}")
|
|
|
|
@staticmethod
|
|
def parse(date_string: str, pattern: str = "yyyy-MM-dd HH:mm:ss") -> datetime:
|
|
"""Parse string to datetime"""
|
|
try:
|
|
python_pattern = TimeKit._to_python_pattern(pattern)
|
|
return datetime.strptime(date_string, python_pattern)
|
|
except ValueError as e:
|
|
raise RuntimeError(f"Error parsing date: {e}")
|
|
|
|
@staticmethod
|
|
def parse_date(date_string: str, pattern: str = "yyyy-MM-dd") -> date:
|
|
"""Parse string to date"""
|
|
dt = TimeKit.parse(date_string, pattern)
|
|
return dt.date()
|
|
|
|
@staticmethod
|
|
def parse_time(time_string: str, pattern: str = "HH:mm:ss") -> time:
|
|
"""Parse string to time"""
|
|
dt = TimeKit.parse(f"1970-01-01 {time_string}", f"yyyy-MM-dd {pattern}")
|
|
return dt.time()
|
|
|
|
@staticmethod
|
|
def to_datetime(dt: Union[datetime, date]) -> datetime:
|
|
"""Convert date to datetime"""
|
|
if isinstance(dt, datetime):
|
|
return dt
|
|
elif isinstance(dt, date):
|
|
return datetime.combine(dt, time.min)
|
|
else:
|
|
raise ValueError(f"Unsupported type: {type(dt)}")
|
|
|
|
@staticmethod
|
|
def to_date(dt: Union[datetime, date]) -> date:
|
|
"""Convert datetime to date"""
|
|
if isinstance(dt, datetime):
|
|
return dt.date()
|
|
elif isinstance(dt, date):
|
|
return dt
|
|
else:
|
|
raise ValueError(f"Unsupported type: {type(dt)}")
|
|
|
|
@staticmethod
|
|
def is_after(dt1: datetime, dt2: datetime) -> bool:
|
|
"""Check if dt1 is after dt2"""
|
|
return dt1 > dt2
|
|
|
|
@staticmethod
|
|
def is_before(dt1: datetime, dt2: datetime) -> bool:
|
|
"""Check if dt1 is before dt2"""
|
|
return dt1 < dt2
|
|
|
|
@staticmethod
|
|
def is_equal(dt1: datetime, dt2: datetime) -> bool:
|
|
"""Check if dt1 equals dt2"""
|
|
return dt1 == dt2
|
|
|
|
@staticmethod
|
|
def _to_python_pattern(java_pattern: str) -> str:
|
|
"""Convert Java date pattern to Python strftime pattern"""
|
|
mapping = {
|
|
'yyyy': '%Y',
|
|
'yy': '%y',
|
|
'MM': '%m',
|
|
'dd': '%d',
|
|
'HH': '%H',
|
|
'mm': '%M',
|
|
'ss': '%S',
|
|
'SSS': '%f',
|
|
}
|
|
|
|
result = java_pattern
|
|
for java_fmt, python_fmt in mapping.items():
|
|
result = result.replace(java_fmt, python_fmt)
|
|
|
|
return result
|
|
|
|
|
|
class _SimpleDateFormat:
|
|
"""Simple date format implementation (Java SimpleDateFormat equivalent)"""
|
|
|
|
def __init__(self, pattern: str):
|
|
self.pattern = pattern
|
|
self.python_pattern = TimeKit._to_python_pattern(pattern)
|
|
|
|
def format(self, dt: Union[datetime, date]) -> str:
|
|
"""Format datetime to string"""
|
|
if isinstance(dt, datetime):
|
|
return dt.strftime(self.python_pattern)
|
|
elif isinstance(dt, date):
|
|
return dt.strftime(self.python_pattern)
|
|
else:
|
|
raise ValueError(f"Unsupported type: {type(dt)}")
|
|
|
|
def parse(self, date_string: str) -> datetime:
|
|
"""Parse string to datetime"""
|
|
try:
|
|
return datetime.strptime(date_string, self.python_pattern)
|
|
except ValueError as e:
|
|
raise RuntimeError(f"Error parsing date: {e}")
|