openapi-servers/servers/time/main.py
Timothy Jaeryang Baek d79d0ce834 init
2025-03-27 23:45:08 -07:00

162 lines
4.9 KiB
Python

from fastapi import FastAPI, HTTPException, Body
from pydantic import BaseModel, Field
from datetime import datetime, timezone
from typing import Literal
import pytz
from dateutil import parser as dateutil_parser
app = FastAPI(
title="Secure Time Utilities API",
version="1.0.0",
description="Provides secure UTC/local time retrieval, formatting, timezone conversion, and comparison.",
)
# -------------------------------
# Pydantic models
# -------------------------------
class FormatTimeInput(BaseModel):
format: str = Field(
"%Y-%m-%d %H:%M:%S", description="Python strftime format string"
)
timezone: str = Field(
"UTC", description="IANA timezone name (e.g., UTC, America/New_York)"
)
class ConvertTimeInput(BaseModel):
timestamp: str = Field(
..., description="ISO 8601 formatted time string (e.g., 2024-01-01T12:00:00Z)"
)
from_tz: str = Field(
..., description="Original IANA time zone of input (e.g. UTC or Europe/Berlin)"
)
to_tz: str = Field(..., description="Target IANA time zone to convert to")
class ElapsedTimeInput(BaseModel):
start: str = Field(..., description="Start timestamp in ISO 8601 format")
end: str = Field(..., description="End timestamp in ISO 8601 format")
units: Literal["seconds", "minutes", "hours", "days"] = Field(
"seconds", description="Unit for elapsed time"
)
class ParseTimestampInput(BaseModel):
timestamp: str = Field(
..., description="Flexible input timestamp string (e.g., 2024-06-01 12:00 PM)"
)
timezone: str = Field(
"UTC", description="Assumed timezone if none is specified in input"
)
# -------------------------------
# Routes
# -------------------------------
@app.get("/get_current_utc_time", summary="Current UTC time")
def get_current_utc():
"""
Returns the current time in UTC in ISO format.
"""
return {"utc": datetime.utcnow().replace(tzinfo=timezone.utc).isoformat()}
@app.get("/get_current_local_time", summary="Current Local Time")
def get_current_local():
"""
Returns the current time in local timezone in ISO format.
"""
return {"local_time": datetime.now().isoformat()}
@app.post("/format_time", summary="Format current time")
def format_current_time(data: FormatTimeInput):
"""
Return the current time formatted for a specific timezone and format.
"""
try:
tz = pytz.timezone(data.timezone)
except Exception:
raise HTTPException(
status_code=400, detail=f"Invalid timezone: {data.timezone}"
)
now = datetime.now(tz)
try:
return {"formatted_time": now.strftime(data.format)}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Invalid format string: {e}")
@app.post("/convert_time", summary="Convert between timezones")
def convert_time(data: ConvertTimeInput):
"""
Convert a timestamp from one timezone to another.
"""
try:
from_zone = pytz.timezone(data.from_tz)
to_zone = pytz.timezone(data.to_tz)
except Exception as e:
raise HTTPException(status_code=400, detail=f"Invalid timezone: {e}")
try:
dt = dateutil_parser.parse(data.timestamp)
if dt.tzinfo is None:
dt = from_zone.localize(dt)
else:
dt = dt.astimezone(from_zone)
converted = dt.astimezone(to_zone)
return {"converted_time": converted.isoformat()}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Invalid timestamp: {e}")
@app.post("/elapsed_time", summary="Time elapsed between timestamps")
def elapsed_time(data: ElapsedTimeInput):
"""
Calculate the difference between two timestamps in chosen units.
"""
try:
start_dt = dateutil_parser.parse(data.start)
end_dt = dateutil_parser.parse(data.end)
delta = end_dt - start_dt
except Exception as e:
raise HTTPException(status_code=400, detail=f"Invalid timestamps: {e}")
seconds = delta.total_seconds()
result = {
"seconds": seconds,
"minutes": seconds / 60,
"hours": seconds / 3600,
"days": seconds / 86400,
}
return {"elapsed": result[data.units], "unit": data.units}
@app.post("/parse_timestamp", summary="Parse and normalize timestamps")
def parse_timestamp(data: ParseTimestampInput):
"""
Parse human-friendly input timestamp and return standardized UTC ISO time.
"""
try:
tz = pytz.timezone(data.timezone)
dt = dateutil_parser.parse(data.timestamp)
if dt.tzinfo is None:
dt = tz.localize(dt)
dt_utc = dt.astimezone(pytz.utc)
return {"utc": dt_utc.isoformat()}
except Exception as e:
raise HTTPException(status_code=400, detail=f"Could not parse: {e}")
@app.get("/list_time_zones", summary="All valid time zones")
def list_time_zones():
"""
Return a list of all valid IANA time zones.
"""
return pytz.all_timezones