NexusCoder / nexus /tools /datetime_tool.py
AdminReal's picture
Import NexusCoder from github.com/mhieuhonda/NexusCoder
eca5751 verified
Raw
History Blame Contribute Delete
6.29 kB
"""DateTime Tool - time/date operations."""
from __future__ import annotations
from datetime import datetime, timezone, timedelta
from typing import Dict, Any
from .base import Tool, ToolResult, ToolContext, ToolCategory, ToolSafety
class DateTimeTool(Tool):
"""DateTime operations: now, parse, format, convert timezone, arithmetic."""
category = ToolCategory.SYSTEM
safety = ToolSafety.SAFE
@property
def name(self) -> str:
return "datetime"
@property
def description(self) -> str:
return (
"DateTime operations: now, parse, format, timezone convert, "
"date arithmetic, weekday, days between."
)
@property
def parameters(self) -> Dict[str, Any]:
return {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["now", "parse", "format", "convert_tz", "add", "diff"],
"default": "now",
},
"datetime_str": {"type": "string", "description": "For parse/format/convert: input datetime"},
"format_str": {"type": "string", "description": "strftime/strptime format"},
"from_tz": {"type": "string", "description": "Source timezone (IANA name)"},
"to_tz": {"type": "string", "description": "Target timezone"},
"delta_days": {"type": "integer", "description": "Days to add (can be negative)"},
"delta_hours": {"type": "integer"},
"start": {"type": "string", "description": "For diff: start datetime"},
"end": {"type": "string", "description": "For diff: end datetime"},
},
}
def execute(self, args: Dict[str, Any], context: ToolContext) -> ToolResult:
action = args.get("action", "now")
try:
if action == "now":
now_utc = datetime.now(timezone.utc)
now_local = datetime.now().astimezone()
return ToolResult(
success=True,
output=(
f"UTC: {now_utc.isoformat()}\n"
f"Local: {now_local.isoformat()}\n"
f"Timestamp: {now_utc.timestamp()}"
),
metadata={
"utc": now_utc.isoformat(),
"local": now_local.isoformat(),
"timestamp": now_utc.timestamp(),
"timezone": str(now_local.tzinfo),
},
)
elif action == "parse":
dt_str = args["datetime_str"]
fmt = args.get("format_str")
if fmt:
dt = datetime.strptime(dt_str, fmt)
else:
# Try ISO format
dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
return ToolResult(
success=True,
output=f"Parsed: {dt.isoformat()}",
metadata={"parsed": dt.isoformat(), "weekday": dt.strftime("%A")},
)
elif action == "format":
dt_str = args["datetime_str"]
fmt = args.get("format_str", "%Y-%m-%d %H:%M:%S")
dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
return ToolResult(
success=True,
output=dt.strftime(fmt),
metadata={"format": fmt},
)
elif action == "convert_tz":
dt_str = args["datetime_str"]
from_tz = args.get("from_tz", "UTC")
to_tz = args["to_tz"]
try:
from zoneinfo import ZoneInfo
tz_from = ZoneInfo(from_tz)
tz_to = ZoneInfo(to_tz)
except ImportError:
return ToolResult(
success=False,
error="zoneinfo not available (Python 3.9+)",
return_code=1,
)
dt = datetime.fromisoformat(dt_str).replace(tzinfo=tz_from)
converted = dt.astimezone(tz_to)
return ToolResult(
success=True,
output=f"{dt_str} ({from_tz}) → {converted.isoformat()} ({to_tz})",
metadata={"original": dt.isoformat(), "converted": converted.isoformat()},
)
elif action == "add":
dt_str = args["datetime_str"]
delta_days = args.get("delta_days", 0)
delta_hours = args.get("delta_hours", 0)
dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
new_dt = dt + timedelta(days=delta_days, hours=delta_hours)
return ToolResult(
success=True,
output=f"{dt.isoformat()} + {delta_days}d {delta_hours}h = {new_dt.isoformat()}",
metadata={"result": new_dt.isoformat()},
)
elif action == "diff":
start = datetime.fromisoformat(args["start"].replace("Z", "+00:00"))
end = datetime.fromisoformat(args["end"].replace("Z", "+00:00"))
delta = end - start
return ToolResult(
success=True,
output=(
f"Diff: {delta}\n"
f"Days: {delta.days}\n"
f"Seconds: {delta.total_seconds()}\n"
f"Hours: {delta.total_seconds() / 3600}"
),
metadata={
"days": delta.days,
"seconds": delta.total_seconds(),
},
)
else:
return ToolResult(success=False, error=f"Unknown action: {action}", return_code=2)
except Exception as e:
return ToolResult(success=False, error=str(e), return_code=1)