{
  "openapi": "3.0.0",
  "info": {
    "title": "UTCTime API",
    "version": "1.0.0",
    "description": "Free public REST API for time zone conversion, current time lookup, and working-hours overlap analysis. No authentication required. Rate limit: 60 req/10 s per IP.\n\n**Versioning policy**: this is v1 (stable, unversioned path). Breaking changes ship under /api/v2/ with ≥90 days notice via llms.txt and a Deprecation response header. Additive changes (new fields, new optional params) are non-breaking and may land at any time.",
    "contact": { "email": "contact@utctime.date", "url": "https://utctime.date/contact" },
    "license": { "name": "Public API, free to use", "url": "https://utctime.date/about" }
  },
  "servers": [{ "url": "https://utctime.date", "description": "Production (Cloudflare edge)" }],
  "paths": {
    "/api/convert": {
      "get": {
        "operationId": "convertTime",
        "summary": "Convert time between two IANA zones",
        "description": "Returns time conversion details including UTC reference, UTC offsets, and HH:MM local times in both zones. DST-aware. Cached 24 h when `time` is supplied, 30 s otherwise.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Source IANA timezone (e.g. America/New_York)",
            "schema": { "type": "string", "example": "America/New_York" }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Target IANA timezone (e.g. Europe/London)",
            "schema": { "type": "string", "example": "Europe/London" }
          },
          {
            "name": "time",
            "in": "query",
            "required": false,
            "description": "ISO 8601 timestamp. Defaults to current UTC time if omitted.",
            "schema": { "type": "string", "format": "date-time", "example": "2024-06-15T14:00:00Z" }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful conversion",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ConvertResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/now": {
      "get": {
        "operationId": "getCurrentTime",
        "summary": "Get current time in a specific timezone",
        "description": "Returns current UTC time and its local representation in the requested zone. Cached 30 s at the edge.",
        "parameters": [
          {
            "name": "zone",
            "in": "query",
            "required": true,
            "description": "IANA timezone (e.g. Asia/Tokyo)",
            "schema": { "type": "string", "example": "Asia/Tokyo" }
          }
        ],
        "responses": {
          "200": {
            "description": "Current time in the requested zone",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/NowResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/overlap": {
      "get": {
        "operationId": "findOverlapHours",
        "summary": "Find overlapping work hours across multiple time zones",
        "description": "Returns UTC hours (0–23) where all specified zones simultaneously fall within 09:00–17:00 local time. DST-aware. Cached 24 h when `date` is supplied, 30 s otherwise.",
        "parameters": [
          {
            "name": "zones",
            "in": "query",
            "required": true,
            "description": "Comma-separated IANA timezones (minimum 2, maximum 10)",
            "schema": { "type": "string", "example": "America/New_York,Europe/London,Asia/Tokyo" }
          },
          {
            "name": "date",
            "in": "query",
            "required": false,
            "description": "Date in YYYY-MM-DD format. Defaults to today (UTC).",
            "schema": { "type": "string", "format": "date", "example": "2024-06-15" }
          }
        ],
        "responses": {
          "200": {
            "description": "Overlap analysis result",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OverlapResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/zones": {
      "get": {
        "operationId": "listZones",
        "summary": "List all supported IANA time zones",
        "description": "Returns all IANA timezone identifiers supported by the runtime. Effectively static; cached 7 days.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of timezone identifiers",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ZonesResponse" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ConvertResponse": {
        "type": "object",
        "required": ["from", "to", "utc", "fromOffsetMinutes", "toOffsetMinutes", "diffMinutes", "fromLocal", "toLocal"],
        "properties": {
          "from": { "type": "string", "description": "Source IANA timezone" },
          "to": { "type": "string", "description": "Target IANA timezone" },
          "utc": { "type": "string", "format": "date-time", "description": "Reference UTC timestamp" },
          "fromOffsetMinutes": { "type": "number", "description": "Source zone UTC offset in minutes" },
          "toOffsetMinutes": { "type": "number", "description": "Target zone UTC offset in minutes" },
          "diffMinutes": { "type": "number", "description": "Offset difference: toOffsetMinutes − fromOffsetMinutes" },
          "fromLocal": { "type": "string", "description": "Local time in source zone, HH:MM" },
          "toLocal": { "type": "string", "description": "Local time in target zone, HH:MM" }
        }
      },
      "NowResponse": {
        "type": "object",
        "required": ["zone", "utc", "offsetMinutes", "local", "localDate"],
        "properties": {
          "zone": { "type": "string", "description": "IANA timezone" },
          "utc": { "type": "string", "format": "date-time", "description": "Current UTC time" },
          "offsetMinutes": { "type": "number", "description": "Zone UTC offset in minutes" },
          "local": { "type": "string", "description": "Current local time, HH:MM" },
          "localDate": { "type": "string", "format": "date", "description": "Current local date, YYYY-MM-DD" }
        }
      },
      "OverlapResponse": {
        "type": "object",
        "required": ["zones", "date", "overlapUtcHours", "workStart", "workEnd"],
        "properties": {
          "zones": { "type": "array", "items": { "type": "string" }, "description": "Input IANA zones" },
          "date": { "type": "string", "format": "date", "description": "Date used for DST calculation" },
          "overlapUtcHours": {
            "type": "array",
            "items": { "type": "number", "minimum": 0, "maximum": 23 },
            "description": "UTC hours (0–23) where every zone is within workStart–workEnd local"
          },
          "workStart": { "type": "number", "default": 9, "description": "Work day start hour (local)" },
          "workEnd": { "type": "number", "default": 17, "description": "Work day end hour (local)" }
        }
      },
      "ZonesResponse": {
        "type": "object",
        "required": ["zones"],
        "properties": {
          "zones": {
            "type": "array",
            "items": { "type": "string" },
            "description": "All IANA timezone identifiers supported at runtime"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string", "description": "Human-readable error message" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Missing or invalid parameter",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": { "error": "from and to zone required" }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded (60 req / 10 s per IP)",
        "headers": {
          "Retry-After": {
            "schema": { "type": "integer" },
            "description": "Seconds to wait before retrying"
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": { "error": "rate limited" }
          }
        }
      }
    }
  }
}
