123 lines
3.4 KiB
Python
123 lines
3.4 KiB
Python
from datetime import datetime, timedelta
|
|
import re
|
|
|
|
class OurTime:
|
|
def __init__(self, dt: datetime = None):
|
|
self._dt = dt if dt else datetime.min
|
|
|
|
def __str__(self) -> str:
|
|
return self.str()
|
|
|
|
def str(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%Y-%m-%d %H:%M')
|
|
|
|
def day(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%Y-%m-%d')
|
|
|
|
def key(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%Y_%m_%d_%H_%M_%S')
|
|
|
|
def md(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%Y-%m-%d %H:%M:%S')
|
|
|
|
def unix(self) -> int:
|
|
if self._dt == datetime.min:
|
|
return 0
|
|
return int(self._dt.timestamp())
|
|
|
|
def empty(self) -> bool:
|
|
return self._dt == datetime.min
|
|
|
|
def dayhour(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%Y-%m-%d-%H')
|
|
|
|
def time(self):
|
|
# This is a simplified representation, as VLang's time() returns a time object.
|
|
# Here, we return self to allow chaining format_ss().
|
|
return self
|
|
|
|
def format_ss(self) -> str:
|
|
if self._dt == datetime.min:
|
|
return ""
|
|
return self._dt.strftime('%H:%M:%S')
|
|
|
|
def warp(self, expression: str):
|
|
if self._dt == datetime.min:
|
|
return
|
|
|
|
parts = expression.split()
|
|
for part in parts:
|
|
match = re.match(r'([+-]?\d+)([smhdwMQY])', part)
|
|
if not match:
|
|
continue
|
|
|
|
value = int(match.group(1))
|
|
unit = match.group(2)
|
|
|
|
if unit == 's':
|
|
self._dt += timedelta(seconds=value)
|
|
elif unit == 'm':
|
|
self._dt += timedelta(minutes=value)
|
|
elif unit == 'h':
|
|
self._dt += timedelta(hours=value)
|
|
elif unit == 'd':
|
|
self._dt += timedelta(days=value)
|
|
elif unit == 'w':
|
|
self._dt += timedelta(weeks=value)
|
|
elif unit == 'M':
|
|
# Approximate months, for more accuracy, a proper dateutil.relativedelta would be needed
|
|
self._dt += timedelta(days=value * 30)
|
|
elif unit == 'Q':
|
|
self._dt += timedelta(days=value * 90)
|
|
elif unit == 'Y':
|
|
self._dt += timedelta(days=value * 365)
|
|
|
|
def now() -> OurTime:
|
|
return OurTime(datetime.now())
|
|
|
|
def new(time_str: str) -> OurTime:
|
|
if not time_str:
|
|
return OurTime()
|
|
|
|
formats = [
|
|
'%Y-%m-%d %H:%M:%S',
|
|
'%Y-%m-%d %H:%M',
|
|
'%Y-%m-%d %H',
|
|
'%Y-%m-%d',
|
|
'%d-%m-%Y %H:%M:%S',
|
|
'%d-%m-%Y %H:%M',
|
|
'%d-%m-%Y %H',
|
|
'%d-%m-%Y',
|
|
'%H:%M:%S', # For time() and format_ss() usage
|
|
]
|
|
|
|
for fmt in formats:
|
|
try:
|
|
dt = datetime.strptime(time_str, fmt)
|
|
return OurTime(dt)
|
|
except ValueError:
|
|
pass
|
|
|
|
# Handle relative time expressions
|
|
try:
|
|
# Create a dummy OurTime object to use its warp method
|
|
temp_time = now()
|
|
temp_time.warp(time_str)
|
|
return temp_time
|
|
except Exception:
|
|
pass
|
|
|
|
raise ValueError(f"Could not parse time string: {time_str}")
|
|
|
|
def new_from_epoch(epoch: int) -> OurTime:
|
|
return OurTime(datetime.fromtimestamp(epoch)) |