File size: 5,319 Bytes
5b483a6
 
 
 
 
 
 
 
 
 
 
 
 
 
084afc2
5b483a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
from fastapi import FastAPI, HTTPException, Body
from fastapi.middleware.cors import CORSMiddleware


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.",
    servers=[{"url": "https://arcticaurora-timetool.hf.space"}]
)


origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# -------------------------------
# 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