101 lines
2.9 KiB
Python
101 lines
2.9 KiB
Python
from datetime import datetime, timedelta
|
|
|
|
|
|
def _time_of_day_label(hour: int, *, for_today: bool) -> str:
|
|
if 5 <= hour < 12:
|
|
return "morning"
|
|
if 12 <= hour < 17:
|
|
return "afternoon"
|
|
return "tonight" if for_today else "night"
|
|
|
|
|
|
def describe_relative_time(
|
|
timestamp_str: str,
|
|
reference_time: datetime,
|
|
*,
|
|
prefer_day_part_for_today: bool = False,
|
|
) -> str:
|
|
try:
|
|
timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M")
|
|
except ValueError:
|
|
return "a long time ago"
|
|
|
|
delta = reference_time - timestamp
|
|
seconds = delta.total_seconds()
|
|
if seconds < 0:
|
|
return "just now"
|
|
|
|
if not prefer_day_part_for_today:
|
|
if seconds < 120:
|
|
return "just now"
|
|
if seconds < 15 * 60:
|
|
return "a few minutes ago"
|
|
if seconds < 90 * 60:
|
|
return "an hour ago"
|
|
if seconds < 3 * 60 * 60:
|
|
return "a couple hours ago"
|
|
|
|
day_diff = (reference_time.date() - timestamp.date()).days
|
|
if day_diff == 0:
|
|
return f"today {_time_of_day_label(timestamp.hour, for_today=True)}"
|
|
if day_diff == 1:
|
|
return f"yesterday {_time_of_day_label(timestamp.hour, for_today=False)}"
|
|
if day_diff == 2:
|
|
return "2 days ago"
|
|
if day_diff == 3:
|
|
return "3 days ago"
|
|
if day_diff <= 6:
|
|
return "a couple days ago"
|
|
if day_diff <= 10:
|
|
return "a week ago"
|
|
if day_diff <= 20:
|
|
return "a couple weeks ago"
|
|
if day_diff <= 45:
|
|
return "a month ago"
|
|
if day_diff <= 75:
|
|
return "a couple months ago"
|
|
if day_diff <= 420:
|
|
return "a year ago"
|
|
return "a long time ago"
|
|
|
|
|
|
class WorldClock:
|
|
def __init__(self, start_year=1999, month=5, day=14, hour=18, minute=0):
|
|
# We use a standard datetime object for easy math
|
|
self.current_time = datetime(start_year, month, day, hour, minute)
|
|
|
|
def advance_time(self, minutes=0, hours=0, days=0):
|
|
self.current_time += timedelta(minutes=minutes, hours=hours, days=days)
|
|
|
|
def advance_minutes(self, minutes: int):
|
|
"""Convenience method to advance clock by minutes."""
|
|
self.advance_time(minutes=minutes)
|
|
|
|
def get_time_str(self):
|
|
# 1999-05-14 18:00
|
|
return self.current_time.strftime("%Y-%m-%d %H:%M")
|
|
|
|
def get_vibe(self):
|
|
"""Helper to tell the LLM the 'feel' of the time."""
|
|
hour = self.current_time.hour
|
|
if 5 <= hour < 12:
|
|
return "Morning"
|
|
if 12 <= hour < 17:
|
|
return "Afternoon"
|
|
if 17 <= hour < 21:
|
|
return "Evening"
|
|
return "Night"
|
|
|
|
@classmethod
|
|
def from_time_str(cls, time_str: str | None):
|
|
if not time_str:
|
|
return cls()
|
|
parsed = datetime.strptime(time_str, "%Y-%m-%d %H:%M")
|
|
return cls(
|
|
start_year=parsed.year,
|
|
month=parsed.month,
|
|
day=parsed.day,
|
|
hour=parsed.hour,
|
|
minute=parsed.minute,
|
|
)
|