[
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: docs\n\non:\n  push:\n    branches: [\"main\"]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: true\n\njobs:\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Setup Pages\n        uses: actions/configure-pages@v2\n      - uses: mlugg/setup-zig@v2\n        with:\n          version: 0.15.2\n      - run: zig build docs\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: \"zig-out/docs\"\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: test\n\non:\n  pull_request:\n    branches: [\"main\", \"0.16\"]\n  workflow_dispatch:\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n    runs-on: ${{matrix.os}}\n    steps:\n      - uses: actions/checkout@v3\n      - uses: mlugg/setup-zig@v2\n        with:\n          version: master\n      - run: zig build test --summary new\n  check-fmt:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: mlugg/setup-zig@v2\n        with:\n          version: master\n      - run: zig fmt --check .\n"
  },
  {
    "path": ".gitignore",
    "content": ".zig-cache/\nzig-out/\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2024 Tim Culverhouse\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# zeit\n\nA time library written in zig.\n\n## Install \n```\nzig fetch --save git+https://github.com/rockorager/zeit?ref=main\n```\n\nOr install a [tag](https://github.com/rockorager/zeit/tags) instead of main.\n\n## Usage\n\n[API Documentation](https://rockorager.github.io/zeit/)\n\n```zig\nconst std = @import(\"std\");\nconst zeit = @import(\"zeit\");\n\npub fn main() !void {\n    const allocator = std.heap.page_allocator;\n    var threaded = std.Io.Threaded.init(allocator, .{});\n    defer threaded.deinit();\n    const io = threaded.io();\n\n    // Get a \"now\" instant in UTC.\n    const now = zeit.instant(.{.now = io}, &zeit.utc);\n\n    // Load our local timezone. This needs an allocator. Optionally pass in a\n    // zeit.EnvConfig to support TZ and TZDIR environment variables\n    const local = try zeit.local(allocator, io, .{});\n    defer local.deinit();\n\n    // Convert our instant to a new timezone\n    const now_local = now.in(&local);\n\n    // Generate date/time info for this instant\n    const dt = now_local.time();\n\n    // Print it out\n    std.debug.print(\"{}\", .{dt});\n\n    // zeit.Time{\n    //    .year = 2024,\n    //    .month = zeit.Month.mar,\n    //    .day = 16,\n    //    .hour = 8,\n    //    .minute = 38,\n    //    .second = 29,\n    //    .millisecond = 496,\n    //    .microsecond = 706,\n    //    .nanosecond = 64\n    //    .offset = -18000,\n    // }\n\n    var buf: [256]u8 = undefined;\n    var writer = std.Io.Writer.fixed(&buf);\n\n    // Format using strftime specifier. Format strings are not required to be comptime\n    try dt.strftime(&writer, \"%Y-%m-%d %H:%M:%S %Z\");\n    std.debug.print(\"{s}\\n\", .{writer.buffered()});\n\n    writer.end = 0;\n\n    // Or...golang magic date specifiers. Format strings are not required to be comptime\n    try dt.gofmt(&writer, \"2006-01-02 15:04:05 MST\");\n    std.debug.print(\"{s}\\n\", .{writer.buffered()});\n\n    // Load an arbitrary location using IANA location syntax. The location name\n    // comes from an enum which will automatically map IANA location names to\n    // Windows names, as needed. Pass an optional EnvConfig to support TZDIR\n    const vienna = try zeit.loadTimeZone(allocator, io, .@\"Europe/Vienna\", .{});\n    defer vienna.deinit();\n\n    // Parse an Instant from an ISO8601 or RFC3339 string\n    _ = try zeit.instantFromText(\n        .iso8601,\n        \"2024-03-16T08:38:29.496-1200\",\n        &zeit.utc,\n    });\n\n    _ = try zeit.instantFromText(\n        .rfc3339,\n        \"2024-03-16T08:38:29.496706064-1200\",\n        &zeit.utc,\n    });\n}\n```\n"
  },
  {
    "path": "bench/bench_benjoffe.zig",
    "content": "const std = @import(\"std\");\nconst builtin = @import(\"builtin\");\n\nconst Date = struct {\n    year: i32,\n    month: u4,\n    day: u5,\n};\n\nconst is_arm = builtin.cpu.arch == .aarch64 or builtin.cpu.arch == .arm;\n\nconst ERAS: u64 = 4726498270;\nconst D_SHIFT: u64 = 146097 * ERAS - 719469;\nconst Y_SHIFT: u64 = 400 * ERAS - 1;\n\nconst SCALE: u64 = if (is_arm) 1 else 32;\nconst SHIFT_0: u64 = 30556 * SCALE;\nconst SHIFT_1: u64 = 5980 * SCALE;\n\nconst C1: u64 = 505054698555331;\nconst C2: u64 = 50504432782230121;\nconst C3: u64 = @as(u64, 8619973866219416) * 32 / SCALE;\n\n/// Ben Joffe's very fast 64-bit date algorithm\n/// https://www.benjoffe.com/fast-date-64\nfn civilFromDays(days: i32) Date {\n    const rev: u64 = D_SHIFT -% @as(u64, @bitCast(@as(i64, days)));\n    const cen: u64 = @truncate(@as(u128, C1) * rev >> 64);\n    const jul: u64 = rev +% cen -% cen / 4;\n    const num: u128 = @as(u128, C2) * jul;\n    const yrs: u64 = Y_SHIFT -% @as(u64, @truncate(num >> 64));\n    const low: u64 = @truncate(num);\n    const ypt: u64 = @truncate(@as(u128, 24451 * SCALE) * low >> 64);\n\n    if (is_arm) {\n        const shift: u64 = SHIFT_0;\n        const N: u64 = (yrs % 4) * (16 * SCALE) +% shift -% ypt;\n        const M: u64 = N / (2048 * SCALE);\n        const D: u64 = @truncate(@as(u128, C3) * (N % (2048 * SCALE)) >> 64);\n        const bump: u64 = if (M > 12) 1 else 0;\n        const month: u4 = @intCast(if (bump == 1) M - 12 else M);\n        const day: u5 = @intCast(D + 1);\n        const year: i32 = @intCast(@as(i64, @bitCast(yrs)) + @as(i64, @intCast(bump)));\n        return .{ .year = year, .month = month, .day = day };\n    } else {\n        const bump: u64 = if (ypt < (3952 * SCALE)) 1 else 0;\n        const shift: u64 = if (bump == 1) SHIFT_1 else SHIFT_0;\n        const N: u64 = (yrs % 4) * (16 * SCALE) +% shift -% ypt;\n        const M: u64 = N / (2048 * SCALE);\n        const D: u64 = @truncate(@as(u128, C3) * (N % (2048 * SCALE)) >> 64);\n        const month: u4 = @intCast(M);\n        const day: u5 = @intCast(D + 1);\n        const year: i32 = @intCast(@as(i64, @bitCast(yrs)) + @as(i64, @intCast(bump)));\n        return .{ .year = year, .month = month, .day = day };\n    }\n}\n\npub fn main() !void {\n    var result: i64 = 0;\n    const iterations = 10_000_000;\n\n    for (0..iterations) |i| {\n        const days: i32 = @intCast(@as(i64, @intCast(i)) - iterations / 2);\n        const date = civilFromDays(days);\n        result +%= @as(i64, date.year) + @as(i64, date.month) + @as(i64, date.day);\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/bench_days_benjoffe.zig",
    "content": "const std = @import(\"std\");\n\nconst Date = struct {\n    year: i32,\n    month: u4,\n    day: u5,\n};\n\n/// Ben Joffe's fast overflow-safe inverse function\n/// https://www.benjoffe.com/fast-date-64\nfn daysFromCivil(date: Date) i32 {\n    const month: u32 = date.month;\n    const bump: u32 = if (month <= 2) 1 else 0;\n    const yrs: u32 = @bitCast(date.year +% 5880000 - @as(i32, @intCast(bump)));\n    const cen: u32 = yrs / 100;\n    const shift: i32 = if (bump == 1) 8829 else -2919;\n\n    const year_days: u32 = yrs * 365 + yrs / 4 - cen + cen / 4;\n    const month_days: u32 = @bitCast(@divFloor(979 * @as(i32, @intCast(month)) + shift, 32));\n    return @bitCast(year_days +% month_days +% date.day -% 2148345369);\n}\n\npub fn main() !void {\n    var result: i64 = 0;\n    const iterations = 10_000_000;\n\n    for (0..iterations) |i| {\n        const year: i32 = @intCast(@as(i64, @intCast(i)) - iterations / 2);\n        const date = Date{ .year = year, .month = 6, .day = 15 };\n        result +%= daysFromCivil(date);\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/bench_days_current.zig",
    "content": "const std = @import(\"std\");\n\nconst Date = struct {\n    year: i32,\n    month: u4,\n    day: u5,\n};\n\nconst days_per_era = 365 * 400 + 97;\n\n/// Current Hinnant algorithm\nfn daysFromCivil(date: Date) i32 {\n    const m: i32 = date.month;\n    const y: i32 = if (m <= 2) date.year - 1 else date.year;\n    const era = @divFloor(y, 400);\n    const yoe: u32 = @intCast(y - era * 400);\n    const doy = blk: {\n        const a: u32 = if (m > 2) @intCast(m - 3) else @intCast(m + 9);\n        const b = a * 153 + 2;\n        break :blk @divFloor(b, 5) + date.day - 1;\n    };\n    const doe: i32 = @intCast(yoe * 365 + @divFloor(yoe, 4) - @divFloor(yoe, 100) + doy);\n    return era * days_per_era + doe - 719468;\n}\n\npub fn main() !void {\n    var result: i64 = 0;\n    const iterations = 10_000_000;\n\n    for (0..iterations) |i| {\n        const year: i32 = @intCast(@as(i64, @intCast(i)) - iterations / 2);\n        const date = Date{ .year = year, .month = 6, .day = 15 };\n        result +%= daysFromCivil(date);\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/bench_hinnant.zig",
    "content": "const std = @import(\"std\");\n\nconst Date = struct {\n    year: i32,\n    month: u4,\n    day: u5,\n};\n\nconst days_per_era = 365 * 400 + 97;\n\n/// Howard Hinnant's algorithm\n/// https://howardhinnant.github.io/date_algorithms.html#civil_from_days\nfn civilFromDays(days: i32) Date {\n    const z = days + 719468;\n    const era = @divFloor(z, days_per_era);\n    const doe: u32 = @intCast(z - era * days_per_era);\n    const yoe: u32 = @intCast(\n        @divFloor(\n            doe -\n                @divFloor(doe, 1460) +\n                @divFloor(doe, 36524) -\n                @divFloor(doe, 146096),\n            365,\n        ),\n    );\n    const y: i32 = @as(i32, @intCast(yoe)) + era * 400;\n    const doy = doe - (365 * yoe + @divFloor(yoe, 4) - @divFloor(yoe, 100));\n    const mp = @divFloor(5 * doy + 2, 153);\n    const d = doy - @divFloor(153 * mp + 2, 5) + 1;\n    const m = if (mp < 10) mp + 3 else mp - 9;\n    return .{\n        .year = if (m <= 2) y + 1 else y,\n        .month = @intCast(m),\n        .day = @truncate(d),\n    };\n}\n\npub fn main() !void {\n    var result: i64 = 0;\n    const iterations = 10_000_000;\n\n    for (0..iterations) |i| {\n        const days: i32 = @intCast(@as(i64, @intCast(i)) - iterations / 2);\n        const date = civilFromDays(days);\n        result +%= @as(i64, date.year) + @as(i64, date.month) + @as(i64, date.day);\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/bench_leap_benjoffe.zig",
    "content": "const std = @import(\"std\");\n\n/// Ben Joffe's fast full-range leap year algorithm\n/// https://www.benjoffe.com/fast-leap-year\nfn isLeapYear(year: i32) bool {\n    const cen_bias: u32 = 2147483600;\n    const cen_mul: u32 = 42949673;\n    const cen_cutoff: u32 = 171798692;\n\n    const a: u32 = @bitCast(year +% @as(i32, @bitCast(cen_bias)));\n    const low: u32 = a *% cen_mul;\n    const is_likely_cen = low < cen_cutoff;\n    const mask: u5 = if (is_likely_cen) 15 else 3;\n    return (year & mask) == 0;\n}\n\npub fn main() !void {\n    var result: u64 = 0;\n    const iterations: i32 = 100_000_000;\n\n    var year: i32 = -iterations / 2;\n    while (year < iterations / 2) : (year += 1) {\n        if (isLeapYear(year)) result += 1;\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/bench_leap_current.zig",
    "content": "const std = @import(\"std\");\n\n/// Current Neri/Schneider algorithm\nfn isLeapYear(year: i32) bool {\n    const d: i32 = if (@mod(year, 100) != 0) 4 else 16;\n    return (year & (d - 1)) == 0;\n}\n\npub fn main() !void {\n    var result: u64 = 0;\n    const iterations: i32 = 100_000_000;\n\n    var year: i32 = -iterations / 2;\n    while (year < iterations / 2) : (year += 1) {\n        if (isLeapYear(year)) result += 1;\n    }\n\n    std.debug.print(\"result: {}\\n\", .{result});\n}\n"
  },
  {
    "path": "bench/test_days.zig",
    "content": "const std = @import(\"std\");\n\nconst Date = struct {\n    year: i32,\n    month: u4,\n    day: u5,\n};\n\nconst days_per_era = 365 * 400 + 97;\n\nfn daysFromCivilCurrent(date: Date) i32 {\n    const m: i32 = date.month;\n    const y: i32 = if (m <= 2) date.year - 1 else date.year;\n    const era = @divFloor(y, 400);\n    const yoe: u32 = @intCast(y - era * 400);\n    const doy = blk: {\n        const a: u32 = if (m > 2) @intCast(m - 3) else @intCast(m + 9);\n        const b = a * 153 + 2;\n        break :blk @divFloor(b, 5) + date.day - 1;\n    };\n    const doe: i32 = @intCast(yoe * 365 + @divFloor(yoe, 4) - @divFloor(yoe, 100) + doy);\n    return era * days_per_era + doe - 719468;\n}\n\nfn daysFromCivilBenjoffe(date: Date) i32 {\n    const month: u32 = date.month;\n    const bump: u32 = if (month <= 2) 1 else 0;\n    const yrs: u32 = @bitCast(date.year +% 5880000 - @as(i32, @intCast(bump)));\n    const cen: u32 = yrs / 100;\n    const shift: i32 = if (bump == 1) 8829 else -2919;\n\n    const year_days: u32 = yrs * 365 + yrs / 4 - cen + cen / 4;\n    const month_days: u32 = @bitCast(@divFloor(979 * @as(i32, @intCast(month)) + shift, 32));\n    return @bitCast(year_days +% month_days +% date.day -% 2148345369);\n}\n\npub fn main() void {\n    var mismatches: u32 = 0;\n\n    // Test a wide range of years and all months/days\n    const test_years = [_]i32{ -5000, -1000, -100, -1, 0, 1, 100, 1000, 1970, 2000, 2024, 5000, 100000, -100000 };\n\n    for (test_years) |year| {\n        for (1..13) |m| {\n            const month: u4 = @intCast(m);\n            for (1..29) |d| {\n                const day: u5 = @intCast(d);\n                const date = Date{ .year = year, .month = month, .day = day };\n                const current = daysFromCivilCurrent(date);\n                const benjoffe = daysFromCivilBenjoffe(date);\n\n                if (current != benjoffe) {\n                    mismatches += 1;\n                    if (mismatches <= 10) {\n                        std.debug.print(\"MISMATCH: {}-{:0>2}-{:0>2}: current={} benjoffe={}\\n\", .{ year, month, day, current, benjoffe });\n                    }\n                }\n            }\n        }\n    }\n\n    if (mismatches == 0) {\n        std.debug.print(\"All tests passed!\\n\", .{});\n    } else {\n        std.debug.print(\"Total mismatches: {}\\n\", .{mismatches});\n    }\n}\n"
  },
  {
    "path": "bench/test_leap.zig",
    "content": "const std = @import(\"std\");\n\nfn isLeapYearCurrent(year: i32) bool {\n    const d: i32 = if (@mod(year, 100) != 0) 4 else 16;\n    return (year & (d - 1)) == 0;\n}\n\nfn isLeapYearBenjoffe(year: i32) bool {\n    const cen_bias: u32 = 2147483600;\n    const cen_mul: u32 = 42949673;\n    const cen_cutoff: u32 = 171798692;\n\n    const a: u32 = @bitCast(year +% @as(i32, @bitCast(cen_bias)));\n    const low: u32 = a *% cen_mul;\n    const is_likely_cen = low < cen_cutoff;\n    const mask: u5 = if (is_likely_cen) 15 else 3;\n    return (year & mask) == 0;\n}\n\npub fn main() void {\n    var mismatches: u32 = 0;\n\n    // Test full range of interesting years\n    var year: i32 = -1_000_000;\n    while (year <= 1_000_000) : (year += 1) {\n        const current = isLeapYearCurrent(year);\n        const benjoffe = isLeapYearBenjoffe(year);\n\n        if (current != benjoffe) {\n            mismatches += 1;\n            if (mismatches <= 10) {\n                std.debug.print(\"MISMATCH: year={}: current={} benjoffe={}\\n\", .{ year, current, benjoffe });\n            }\n        }\n    }\n\n    if (mismatches == 0) {\n        std.debug.print(\"All tests passed!\\n\", .{});\n    } else {\n        std.debug.print(\"Total mismatches: {}\\n\", .{mismatches});\n    }\n}\n"
  },
  {
    "path": "build.zig",
    "content": "const std = @import(\"std\");\n\npub fn build(b: *std.Build) void {\n    const target = b.standardTargetOptions(.{});\n    const optimize = b.standardOptimizeOption(.{});\n\n    const root_module = b.addModule(\"zeit\", .{\n        .root_source_file = b.path(\"src/zeit.zig\"),\n        .target = target,\n        .optimize = optimize,\n    });\n\n    const lib_unit_tests = b.addTest(.{\n        .root_module = root_module,\n    });\n\n    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);\n\n    const test_step = b.step(\"test\", \"Run unit tests\");\n    test_step.dependOn(&run_lib_unit_tests.step);\n\n    const gen_step = b.step(\"generate\", \"Update timezone names\");\n    const gen = b.addExecutable(.{\n        .name = \"generate\",\n        .root_module = b.createModule(.{\n            .root_source_file = b.path(\"gen/main.zig\"),\n            .target = target,\n            .optimize = optimize,\n        }),\n    });\n    const fmt = b.addFmt(\n        .{ .paths = &.{\"src/location.zig\"} },\n    );\n    const gen_run = b.addRunArtifact(gen);\n    fmt.step.dependOn(&gen_run.step);\n    gen_step.dependOn(&fmt.step);\n\n    // Docs\n    {\n        const docs_step = b.step(\"docs\", \"Build the zeit docs\");\n        const docs_obj = b.addObject(.{\n            .name = \"zeit\",\n            .root_module = b.createModule(.{\n                .root_source_file = b.path(\"src/zeit.zig\"),\n                .target = target,\n                .optimize = optimize,\n            }),\n        });\n        const docs = docs_obj.getEmittedDocs();\n        docs_step.dependOn(&b.addInstallDirectory(.{\n            .source_dir = docs,\n            .install_dir = .prefix,\n            .install_subdir = \"docs\",\n        }).step);\n    }\n}\n"
  },
  {
    "path": "build.zig.zon",
    "content": ".{\n    .name = .zeit,\n    .fingerprint = 0x888df3e4939b8ee4,\n    .version = \"0.6.0\",\n    .dependencies = .{},\n    .paths = .{\n        \"LICENSE\",\n        \"build.zig\",\n        \"build.zig.zon\",\n        \"src\",\n    },\n    .minimum_zig_version = \"0.16.0-dev.2533+355c62600\",\n}\n"
  },
  {
    "path": "gen/main.zig",
    "content": "//! Generates zig code for well-known timezones. Makes an enum of the \"posix\" style name\n//! (\"America/Chicago\") and a function to return the timezone name as text. The name as text is\n//! portable by platform: on Windows it will return the Windows name of this timezone\n//!\n//! Source data available at https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml\nconst std = @import(\"std\");\n\npub fn main(init: std.process.Init) !void {\n    const allocator = init.arena.allocator();\n    var threaded: std.Io.Threaded = .init(allocator, .{});\n    defer threaded.deinit();\n    const io = threaded.io();\n    //const allocator = std.heap.page_allocator;\n    const data = @embedFile(\"windowsZones.xml\");\n\n    var zones: std.ArrayList(MapZone) = .empty;\n\n    var read_idx: usize = 0;\n    while (read_idx < data.len) {\n        const eol = std.mem.indexOfScalarPos(u8, data, read_idx, '\\n') orelse data.len;\n        defer read_idx = eol + 1;\n        const input_line = data[read_idx..eol];\n        const line = std.mem.trimEnd(u8, std.mem.trim(u8, input_line, \" \\t<>\"), \"/\");\n        if (!std.mem.startsWith(u8, line, \"mapZone\")) continue;\n        var idx: usize = 0;\n        const windows = blk: {\n            idx = std.mem.indexOfScalarPos(u8, line, idx, '\"') orelse unreachable;\n            const start = idx + 1;\n            idx = std.mem.indexOfScalarPos(u8, line, start, '\"') orelse unreachable;\n            const end = idx;\n            break :blk line[start..end];\n        };\n        const territory = blk: {\n            idx = std.mem.indexOfScalarPos(u8, line, idx + 1, '\"') orelse unreachable;\n            const start = idx + 1;\n            idx = std.mem.indexOfScalarPos(u8, line, start, '\"') orelse unreachable;\n            const end = idx;\n            break :blk line[start..end];\n        };\n        const posix = blk: {\n            idx = std.mem.indexOfScalarPos(u8, line, idx + 1, '\"') orelse unreachable;\n            const start = idx + 1;\n            idx = std.mem.indexOfScalarPos(u8, line, start, '\"') orelse unreachable;\n            const end = idx;\n            break :blk line[start..end];\n        };\n\n        var iter = std.mem.splitScalar(u8, posix, ' ');\n        while (iter.next()) |psx| {\n            const map_zone: MapZone = .{\n                .windows = windows,\n                .territory = territory,\n                .posix = psx,\n            };\n            if (psx.len == 0) continue;\n            for (zones.items) |item| {\n                if (std.mem.eql(u8, item.windows, map_zone.windows) and\n                    std.mem.eql(u8, item.posix, map_zone.posix)) break;\n            } else try zones.append(allocator, map_zone);\n        }\n    }\n\n    std.mem.sort(MapZone, zones.items, {}, lessThan);\n\n    var out = try std.Io.Dir.createFile(.cwd(), io, \"src/location.zig\", .{}); //.cwd().createFile(\"src/location.zig\", .{});\n    defer out.close(io);\n\n    var output_buffer: [2048]u8 = undefined;\n    var writer = out.writer(io, &output_buffer);\n\n    try writeFile(zones.items, &writer.interface);\n}\n\nfn lessThan(_: void, lhs: MapZone, rhs: MapZone) bool {\n    return std.mem.order(u8, lhs.posix, rhs.posix).compare(.lt);\n}\n\nconst MapZone = struct {\n    windows: []const u8,\n    territory: []const u8,\n    posix: []const u8,\n};\n\nfn writeFile(items: []const MapZone, writer: *std.Io.Writer) !void {\n    try writer.writeAll(\n        \\\\//!This file is generated. Do not edit directly! Run `zig build generate` to update after obtaining\n        \\\\//!the latest dataset.\n        \\\\\n        \\\\const builtin = @import(\"builtin\");\n        \\\\pub const Location = enum {\n        \\\\\n    );\n    for (items) |item| {\n        try writer.print(\"@\\\"{s}\\\",\\n\", .{item.posix});\n    }\n\n    try writer.writeAll(\"\\n\");\n\n    try writer.writeAll(\n        \\\\        pub fn asText(self: Location) []const u8 {\n        \\\\            switch (builtin.os.tag) {\n        \\\\                .windows => {},\n        \\\\                else => return @tagName(self),\n        \\\\            }\n    );\n\n    try writer.writeAll(\"        return switch (self) {\\n\");\n    for (items) |item| {\n        try writer.print(\".@\\\"{s}\\\" => \\\"{s}\\\",\\n\", .{ item.posix, item.windows });\n    }\n    try writer.writeAll(\"};}};\");\n    try writer.flush(); // don't forget to flush!\n}\n"
  },
  {
    "path": "gen/windowsZones.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE supplementalData SYSTEM \"../../common/dtd/ldmlSupplemental.dtd\">\n<!--\nCopyright © 1991-2013 Unicode, Inc.\nCLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)\nFor terms of use, see http://www.unicode.org/copyright.html\n-->\n\n<supplementalData>\n\t<version number=\"$Revision$\"/>\n\t<windowsZones>\n\t\t<mapTimezones otherVersion=\"7e11800\" typeVersion=\"2021a\">\n\n\t\t\t<!-- (UTC-12:00) International Date Line West -->\n\t\t\t<mapZone other=\"Dateline Standard Time\" territory=\"001\" type=\"Etc/GMT+12\"/>\n\t\t\t<mapZone other=\"Dateline Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+12\"/>\n\n\t\t\t<!-- (UTC-11:00) Coordinated Universal Time-11 -->\n\t\t\t<mapZone other=\"UTC-11\" territory=\"001\" type=\"Etc/GMT+11\"/>\n\t\t\t<mapZone other=\"UTC-11\" territory=\"AS\" type=\"Pacific/Pago_Pago\"/>\n\t\t\t<mapZone other=\"UTC-11\" territory=\"NU\" type=\"Pacific/Niue\"/>\n\t\t\t<mapZone other=\"UTC-11\" territory=\"UM\" type=\"Pacific/Midway\"/>\n\t\t\t<mapZone other=\"UTC-11\" territory=\"ZZ\" type=\"Etc/GMT+11\"/>\n\n\t\t\t<!-- (UTC-10:00) Aleutian Islands -->\n\t\t\t<mapZone other=\"Aleutian Standard Time\" territory=\"001\" type=\"America/Adak\"/>\n\t\t\t<mapZone other=\"Aleutian Standard Time\" territory=\"US\" type=\"America/Adak\"/>\n\n\t\t\t<!-- (UTC-10:00) Hawaii -->\n\t\t\t<mapZone other=\"Hawaiian Standard Time\" territory=\"001\" type=\"Pacific/Honolulu\"/>\n\t\t\t<mapZone other=\"Hawaiian Standard Time\" territory=\"CK\" type=\"Pacific/Rarotonga\"/>\n\t\t\t<mapZone other=\"Hawaiian Standard Time\" territory=\"PF\" type=\"Pacific/Tahiti\"/>\n\t\t\t<mapZone other=\"Hawaiian Standard Time\" territory=\"US\" type=\"Pacific/Honolulu\"/>\n\t\t\t<mapZone other=\"Hawaiian Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+10\"/>\n\n\t\t\t<!-- (UTC-09:30) Marquesas Islands -->\n\t\t\t<mapZone other=\"Marquesas Standard Time\" territory=\"001\" type=\"Pacific/Marquesas\"/>\n\t\t\t<mapZone other=\"Marquesas Standard Time\" territory=\"PF\" type=\"Pacific/Marquesas\"/>\n\n\t\t\t<!-- (UTC-09:00) Alaska -->\n\t\t\t<mapZone other=\"Alaskan Standard Time\" territory=\"001\" type=\"America/Anchorage\"/>\n\t\t\t<mapZone other=\"Alaskan Standard Time\" territory=\"US\" type=\"America/Anchorage America/Juneau America/Metlakatla America/Nome America/Sitka America/Yakutat\"/>\n\n\t\t\t<!-- (UTC-09:00) Coordinated Universal Time-09 -->\n\t\t\t<mapZone other=\"UTC-09\" territory=\"001\" type=\"Etc/GMT+9\"/>\n\t\t\t<mapZone other=\"UTC-09\" territory=\"PF\" type=\"Pacific/Gambier\"/>\n\t\t\t<mapZone other=\"UTC-09\" territory=\"ZZ\" type=\"Etc/GMT+9\"/>\n\n\t\t\t<!-- (UTC-08:00) Baja California -->\n\t\t\t<mapZone other=\"Pacific Standard Time (Mexico)\" territory=\"001\" type=\"America/Tijuana\"/>\n\t\t\t<mapZone other=\"Pacific Standard Time (Mexico)\" territory=\"MX\" type=\"America/Tijuana\"/>\n\n\t\t\t<!-- (UTC-08:00) Coordinated Universal Time-08 -->\n\t\t\t<mapZone other=\"UTC-08\" territory=\"001\" type=\"Etc/GMT+8\"/>\n\t\t\t<mapZone other=\"UTC-08\" territory=\"PN\" type=\"Pacific/Pitcairn\"/>\n\t\t\t<mapZone other=\"UTC-08\" territory=\"ZZ\" type=\"Etc/GMT+8\"/>\n\n\t\t\t<!-- (UTC-08:00) Pacific Time (US & Canada) -->\n\t\t\t<mapZone other=\"Pacific Standard Time\" territory=\"001\" type=\"America/Los_Angeles\"/>\n\t\t\t<mapZone other=\"Pacific Standard Time\" territory=\"CA\" type=\"America/Vancouver\"/>\n\t\t\t<mapZone other=\"Pacific Standard Time\" territory=\"US\" type=\"America/Los_Angeles\"/>\n\n\t\t\t<!-- (UTC-07:00) Arizona -->\n\t\t\t<mapZone other=\"US Mountain Standard Time\" territory=\"001\" type=\"America/Phoenix\"/>\n\t\t\t<mapZone other=\"US Mountain Standard Time\" territory=\"CA\" type=\"America/Creston America/Dawson_Creek America/Fort_Nelson\"/>\n\t\t\t<mapZone other=\"US Mountain Standard Time\" territory=\"MX\" type=\"America/Hermosillo\"/>\n\t\t\t<mapZone other=\"US Mountain Standard Time\" territory=\"US\" type=\"America/Phoenix\"/>\n\t\t\t<mapZone other=\"US Mountain Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+7\"/>\n\n\t\t\t<!-- (UTC-07:00) Chihuahua, La Paz, Mazatlan -->\n\t\t\t<mapZone other=\"Mountain Standard Time (Mexico)\" territory=\"001\" type=\"America/Mazatlan\"/>\n\t\t\t<mapZone other=\"Mountain Standard Time (Mexico)\" territory=\"MX\" type=\"America/Mazatlan\"/>\n\n\t\t\t<!-- (UTC-07:00) Mountain Time (US & Canada) -->\n\t\t\t<mapZone other=\"Mountain Standard Time\" territory=\"001\" type=\"America/Denver\"/>\n\t\t\t<mapZone other=\"Mountain Standard Time\" territory=\"CA\" type=\"America/Edmonton America/Cambridge_Bay America/Inuvik\"/>\n\t\t\t<mapZone other=\"Mountain Standard Time\" territory=\"MX\" type=\"America/Ciudad_Juarez\"/>\n\t\t\t<mapZone other=\"Mountain Standard Time\" territory=\"US\" type=\"America/Denver America/Boise\"/>\n\n\t\t\t<!-- (UTC-07:00) Yukon -->\n\t\t\t<mapZone other=\"Yukon Standard Time\" territory=\"001\" type=\"America/Whitehorse\"/>\n\t\t\t<mapZone other=\"Yukon Standard Time\" territory=\"CA\" type=\"America/Whitehorse America/Dawson\"/>\n\n\t\t\t<!-- (UTC-06:00) Central America -->\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"001\" type=\"America/Guatemala\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"BZ\" type=\"America/Belize\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"CR\" type=\"America/Costa_Rica\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"EC\" type=\"Pacific/Galapagos\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"GT\" type=\"America/Guatemala\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"HN\" type=\"America/Tegucigalpa\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"NI\" type=\"America/Managua\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"SV\" type=\"America/El_Salvador\"/>\n\t\t\t<mapZone other=\"Central America Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+6\"/>\n\n\t\t\t<!-- (UTC-06:00) Central Time (US & Canada) -->\n\t\t\t<mapZone other=\"Central Standard Time\" territory=\"001\" type=\"America/Chicago\"/>\n\t\t\t<mapZone other=\"Central Standard Time\" territory=\"CA\" type=\"America/Winnipeg America/Rankin_Inlet America/Resolute\"/>\n\t\t\t<mapZone other=\"Central Standard Time\" territory=\"MX\" type=\"America/Matamoros America/Ojinaga\"/>\n\t\t\t<mapZone other=\"Central Standard Time\" territory=\"US\" type=\"America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem\"/>\n\n\t\t\t<!-- (UTC-06:00) Easter Island -->\n\t\t\t<mapZone other=\"Easter Island Standard Time\" territory=\"001\" type=\"Pacific/Easter\"/>\n\t\t\t<mapZone other=\"Easter Island Standard Time\" territory=\"CL\" type=\"Pacific/Easter\"/>\n\n\t\t\t<!-- (UTC-06:00) Guadalajara, Mexico City, Monterrey -->\n\t\t\t<mapZone other=\"Central Standard Time (Mexico)\" territory=\"001\" type=\"America/Mexico_City\"/>\n\t\t\t<mapZone other=\"Central Standard Time (Mexico)\" territory=\"MX\" type=\"America/Mexico_City America/Bahia_Banderas America/Merida America/Monterrey America/Chihuahua \"/>\n\n\t\t\t<!-- (UTC-06:00) Saskatchewan -->\n\t\t\t<mapZone other=\"Canada Central Standard Time\" territory=\"001\" type=\"America/Regina\"/>\n\t\t\t<mapZone other=\"Canada Central Standard Time\" territory=\"CA\" type=\"America/Regina America/Swift_Current\"/>\n\n\t\t\t<!-- (UTC-05:00) Bogota, Lima, Quito, Rio Branco -->\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"001\" type=\"America/Bogota\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"BR\" type=\"America/Rio_Branco America/Eirunepe\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"CA\" type=\"America/Coral_Harbour\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"CO\" type=\"America/Bogota\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"EC\" type=\"America/Guayaquil\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"JM\" type=\"America/Jamaica\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"KY\" type=\"America/Cayman\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"PA\" type=\"America/Panama\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"PE\" type=\"America/Lima\"/>\n\t\t\t<mapZone other=\"SA Pacific Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+5\"/>\n\n\t\t\t<!-- (UTC-05:00) Chetumal -->\n\t\t\t<mapZone other=\"Eastern Standard Time (Mexico)\" territory=\"001\" type=\"America/Cancun\"/>\n\t\t\t<mapZone other=\"Eastern Standard Time (Mexico)\" territory=\"MX\" type=\"America/Cancun\"/>\n\n\t\t\t<!-- (UTC-05:00) Eastern Time (US & Canada) -->\n\t\t\t<mapZone other=\"Eastern Standard Time\" territory=\"001\" type=\"America/New_York\"/>\n\t\t\t<mapZone other=\"Eastern Standard Time\" territory=\"BS\" type=\"America/Nassau\"/>\n\t\t\t<mapZone other=\"Eastern Standard Time\" territory=\"CA\" type=\"America/Toronto America/Iqaluit\"/>\n\t\t\t<mapZone other=\"Eastern Standard Time\" territory=\"US\" type=\"America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville\"/>\n\n\t\t\t<!-- (UTC-05:00) Haiti -->\n\t\t\t<mapZone other=\"Haiti Standard Time\" territory=\"001\" type=\"America/Port-au-Prince\"/>\n\t\t\t<mapZone other=\"Haiti Standard Time\" territory=\"HT\" type=\"America/Port-au-Prince\"/>\n\n\t\t\t<!-- (UTC-05:00) Havana -->\n\t\t\t<mapZone other=\"Cuba Standard Time\" territory=\"001\" type=\"America/Havana\"/>\n\t\t\t<mapZone other=\"Cuba Standard Time\" territory=\"CU\" type=\"America/Havana\"/>\n\n\t\t\t<!-- (UTC-05:00) Indiana (East) -->\n\t\t\t<mapZone other=\"US Eastern Standard Time\" territory=\"001\" type=\"America/Indianapolis\"/>\n\t\t\t<mapZone other=\"US Eastern Standard Time\" territory=\"US\" type=\"America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay\"/>\n\n\t\t\t<!-- (UTC-05:00) Turks and Caicos -->\n\t\t\t<mapZone other=\"Turks And Caicos Standard Time\" territory=\"001\" type=\"America/Grand_Turk\"/>\n\t\t\t<mapZone other=\"Turks And Caicos Standard Time\" territory=\"TC\" type=\"America/Grand_Turk\"/>\n\n\t\t\t<!-- (UTC-04:00) Asuncion -->\n\t\t\t<mapZone other=\"Paraguay Standard Time\" territory=\"001\" type=\"America/Asuncion\"/>\n\t\t\t<mapZone other=\"Paraguay Standard Time\" territory=\"PY\" type=\"America/Asuncion\"/>\n\n\t\t\t<!-- (UTC-04:00) Atlantic Time (Canada) -->\n\t\t\t<mapZone other=\"Atlantic Standard Time\" territory=\"001\" type=\"America/Halifax\"/>\n\t\t\t<mapZone other=\"Atlantic Standard Time\" territory=\"BM\" type=\"Atlantic/Bermuda\"/>\n\t\t\t<mapZone other=\"Atlantic Standard Time\" territory=\"CA\" type=\"America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton\"/>\n\t\t\t<mapZone other=\"Atlantic Standard Time\" territory=\"GL\" type=\"America/Thule\"/>\n\n\t\t\t<!-- (UTC-04:00) Caracas -->\n\t\t\t<mapZone other=\"Venezuela Standard Time\" territory=\"001\" type=\"America/Caracas\"/>\n\t\t\t<mapZone other=\"Venezuela Standard Time\" territory=\"VE\" type=\"America/Caracas\"/>\n\n\t\t\t<!-- (UTC-04:00) Cuiaba -->\n\t\t\t<mapZone other=\"Central Brazilian Standard Time\" territory=\"001\" type=\"America/Cuiaba\"/>\n\t\t\t<mapZone other=\"Central Brazilian Standard Time\" territory=\"BR\" type=\"America/Cuiaba America/Campo_Grande\"/>\n\n\t\t\t<!-- (UTC-04:00) Georgetown, La Paz, Manaus, San Juan -->\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"001\" type=\"America/La_Paz\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"AG\" type=\"America/Antigua\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"AI\" type=\"America/Anguilla\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"AW\" type=\"America/Aruba\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"BB\" type=\"America/Barbados\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"BL\" type=\"America/St_Barthelemy\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"BO\" type=\"America/La_Paz\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"BQ\" type=\"America/Kralendijk\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"BR\" type=\"America/Manaus America/Boa_Vista America/Porto_Velho\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"CA\" type=\"America/Blanc-Sablon\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"CW\" type=\"America/Curacao\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"DM\" type=\"America/Dominica\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"DO\" type=\"America/Santo_Domingo\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"GD\" type=\"America/Grenada\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"GP\" type=\"America/Guadeloupe\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"GY\" type=\"America/Guyana\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"KN\" type=\"America/St_Kitts\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"LC\" type=\"America/St_Lucia\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"MF\" type=\"America/Marigot\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"MQ\" type=\"America/Martinique\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"MS\" type=\"America/Montserrat\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"PR\" type=\"America/Puerto_Rico\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"SX\" type=\"America/Lower_Princes\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"TT\" type=\"America/Port_of_Spain\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"VC\" type=\"America/St_Vincent\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"VG\" type=\"America/Tortola\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"VI\" type=\"America/St_Thomas\"/>\n\t\t\t<mapZone other=\"SA Western Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+4\"/>\n\n\t\t\t<!-- (UTC-04:00) Santiago -->\n\t\t\t<mapZone other=\"Pacific SA Standard Time\" territory=\"001\" type=\"America/Santiago\"/>\n\t\t\t<mapZone other=\"Pacific SA Standard Time\" territory=\"CL\" type=\"America/Santiago\"/>\n\n\t\t\t<!-- (UTC-03:30) Newfoundland -->\n\t\t\t<mapZone other=\"Newfoundland Standard Time\" territory=\"001\" type=\"America/St_Johns\"/>\n\t\t\t<mapZone other=\"Newfoundland Standard Time\" territory=\"CA\" type=\"America/St_Johns\"/>\n\n\t\t\t<!-- (UTC-03:00) Araguaina -->\n\t\t\t<mapZone other=\"Tocantins Standard Time\" territory=\"001\" type=\"America/Araguaina\"/>\n\t\t\t<mapZone other=\"Tocantins Standard Time\" territory=\"BR\" type=\"America/Araguaina\"/>\n\n\t\t\t<!-- (UTC-03:00) Brasilia -->\n\t\t\t<mapZone other=\"E. South America Standard Time\" territory=\"001\" type=\"America/Sao_Paulo\"/>\n\t\t\t<mapZone other=\"E. South America Standard Time\" territory=\"BR\" type=\"America/Sao_Paulo\"/>\n\n\t\t\t<!-- (UTC-03:00) Cayenne, Fortaleza -->\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"001\" type=\"America/Cayenne\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"AQ\" type=\"Antarctica/Rothera Antarctica/Palmer\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"BR\" type=\"America/Fortaleza America/Belem America/Maceio America/Recife America/Santarem\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"FK\" type=\"Atlantic/Stanley\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"GF\" type=\"America/Cayenne\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"SR\" type=\"America/Paramaribo\"/>\n\t\t\t<mapZone other=\"SA Eastern Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+3\"/>\n\n\t\t\t<!-- (UTC-03:00) City of Buenos Aires -->\n\t\t\t<mapZone other=\"Argentina Standard Time\" territory=\"001\" type=\"America/Buenos_Aires\"/>\n\t\t\t<mapZone other=\"Argentina Standard Time\" territory=\"AR\" type=\"America/Buenos_Aires America/Argentina/La_Rioja America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca America/Cordoba America/Jujuy America/Mendoza\"/>\n\n\t\t\t<!-- (UTC-03:00) Greenland -->\n\t\t\t<mapZone other=\"Greenland Standard Time\" territory=\"001\" type=\"America/Godthab\"/>\n\t\t\t<mapZone other=\"Greenland Standard Time\" territory=\"GL\" type=\"America/Godthab\"/>\n\n\t\t\t<!-- (UTC-03:00) Montevideo -->\n\t\t\t<mapZone other=\"Montevideo Standard Time\" territory=\"001\" type=\"America/Montevideo\"/>\n\t\t\t<mapZone other=\"Montevideo Standard Time\" territory=\"UY\" type=\"America/Montevideo\"/>\n\n\t\t\t<!-- (UTC-03:00) Punta Arenas -->\n\t\t\t<mapZone other=\"Magallanes Standard Time\" territory=\"001\" type=\"America/Punta_Arenas\"/>\n\t\t\t<mapZone other=\"Magallanes Standard Time\" territory=\"CL\" type=\"America/Punta_Arenas\"/>\n\n\t\t\t<!-- (UTC-03:00) Saint Pierre and Miquelon -->\n\t\t\t<mapZone other=\"Saint Pierre Standard Time\" territory=\"001\" type=\"America/Miquelon\"/>\n\t\t\t<mapZone other=\"Saint Pierre Standard Time\" territory=\"PM\" type=\"America/Miquelon\"/>\n\n\t\t\t<!-- (UTC-03:00) Salvador -->\n\t\t\t<mapZone other=\"Bahia Standard Time\" territory=\"001\" type=\"America/Bahia\"/>\n\t\t\t<mapZone other=\"Bahia Standard Time\" territory=\"BR\" type=\"America/Bahia\"/>\n\n\t\t\t<!-- (UTC-02:00) Coordinated Universal Time-02 -->\n\t\t\t<mapZone other=\"UTC-02\" territory=\"001\" type=\"Etc/GMT+2\"/>\n\t\t\t<mapZone other=\"UTC-02\" territory=\"BR\" type=\"America/Noronha\"/>\n\t\t\t<mapZone other=\"UTC-02\" territory=\"GS\" type=\"Atlantic/South_Georgia\"/>\n\t\t\t<mapZone other=\"UTC-02\" territory=\"ZZ\" type=\"Etc/GMT+2\"/>\n\n\t\t\t<!-- (UTC-01:00) Azores -->\n\t\t\t<mapZone other=\"Azores Standard Time\" territory=\"001\" type=\"Atlantic/Azores\"/>\n\t\t\t<mapZone other=\"Azores Standard Time\" territory=\"GL\" type=\"America/Scoresbysund\"/>\n\t\t\t<mapZone other=\"Azores Standard Time\" territory=\"PT\" type=\"Atlantic/Azores\"/>\n\n\t\t\t<!-- (UTC-01:00) Cabo Verde Is. -->\n\t\t\t<mapZone other=\"Cape Verde Standard Time\" territory=\"001\" type=\"Atlantic/Cape_Verde\"/>\n\t\t\t<mapZone other=\"Cape Verde Standard Time\" territory=\"CV\" type=\"Atlantic/Cape_Verde\"/>\n\t\t\t<mapZone other=\"Cape Verde Standard Time\" territory=\"ZZ\" type=\"Etc/GMT+1\"/>\n\n\t\t\t<!-- (UTC) Coordinated Universal Time -->\n\t\t\t<mapZone other=\"UTC\" territory=\"001\" type=\"Etc/UTC\"/>\n\t\t\t<mapZone other=\"UTC\" territory=\"ZZ\" type=\"Etc/UTC Etc/GMT\"/>\n\n\t\t\t<!-- (UTC+00:00) Dublin, Edinburgh, Lisbon, London -->\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"001\" type=\"Europe/London\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"ES\" type=\"Atlantic/Canary\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"FO\" type=\"Atlantic/Faeroe\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"GB\" type=\"Europe/London\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"GG\" type=\"Europe/Guernsey\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"IE\" type=\"Europe/Dublin\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"IM\" type=\"Europe/Isle_of_Man\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"JE\" type=\"Europe/Jersey\"/>\n\t\t\t<mapZone other=\"GMT Standard Time\" territory=\"PT\" type=\"Europe/Lisbon Atlantic/Madeira\"/>\n\n\t\t\t<!-- (UTC+00:00) Monrovia, Reykjavik -->\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"001\" type=\"Atlantic/Reykjavik\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"BF\" type=\"Africa/Ouagadougou\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"CI\" type=\"Africa/Abidjan\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"GH\" type=\"Africa/Accra\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"GL\" type=\"America/Danmarkshavn\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"GM\" type=\"Africa/Banjul\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"GN\" type=\"Africa/Conakry\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"GW\" type=\"Africa/Bissau\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"IS\" type=\"Atlantic/Reykjavik\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"LR\" type=\"Africa/Monrovia\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"ML\" type=\"Africa/Bamako\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"MR\" type=\"Africa/Nouakchott\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"SH\" type=\"Atlantic/St_Helena\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"SL\" type=\"Africa/Freetown\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"SN\" type=\"Africa/Dakar\"/>\n\t\t\t<mapZone other=\"Greenwich Standard Time\" territory=\"TG\" type=\"Africa/Lome\"/>\n\n\t\t\t<!-- (UTC+00:00) Sao Tome -->\n\t\t\t<mapZone other=\"Sao Tome Standard Time\" territory=\"001\" type=\"Africa/Sao_Tome\"/>\n\t\t\t<mapZone other=\"Sao Tome Standard Time\" territory=\"ST\" type=\"Africa/Sao_Tome\"/>\n\n\t\t\t<!-- (UTC+01:00) Casablanca -->\n\t\t\t<mapZone other=\"Morocco Standard Time\" territory=\"001\" type=\"Africa/Casablanca\"/>\n\t\t\t<mapZone other=\"Morocco Standard Time\" territory=\"EH\" type=\"Africa/El_Aaiun\"/>\n\t\t\t<mapZone other=\"Morocco Standard Time\" territory=\"MA\" type=\"Africa/Casablanca\"/>\n\n\t\t\t<!-- (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna -->\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"001\" type=\"Europe/Berlin\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"AD\" type=\"Europe/Andorra\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"AT\" type=\"Europe/Vienna\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"CH\" type=\"Europe/Zurich\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"DE\" type=\"Europe/Berlin Europe/Busingen\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"GI\" type=\"Europe/Gibraltar\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"IT\" type=\"Europe/Rome\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"LI\" type=\"Europe/Vaduz\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"LU\" type=\"Europe/Luxembourg\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"MC\" type=\"Europe/Monaco\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"MT\" type=\"Europe/Malta\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"NL\" type=\"Europe/Amsterdam\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"NO\" type=\"Europe/Oslo\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"SE\" type=\"Europe/Stockholm\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"SJ\" type=\"Arctic/Longyearbyen\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"SM\" type=\"Europe/San_Marino\"/>\n\t\t\t<mapZone other=\"W. Europe Standard Time\" territory=\"VA\" type=\"Europe/Vatican\"/>\n\n\t\t\t<!-- (UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague -->\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"001\" type=\"Europe/Budapest\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"AL\" type=\"Europe/Tirane\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"CZ\" type=\"Europe/Prague\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"HU\" type=\"Europe/Budapest\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"ME\" type=\"Europe/Podgorica\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"RS\" type=\"Europe/Belgrade\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"SI\" type=\"Europe/Ljubljana\"/>\n\t\t\t<mapZone other=\"Central Europe Standard Time\" territory=\"SK\" type=\"Europe/Bratislava\"/>\n\n\t\t\t<!-- (UTC+01:00) Brussels, Copenhagen, Madrid, Paris -->\n\t\t\t<mapZone other=\"Romance Standard Time\" territory=\"001\" type=\"Europe/Paris\"/>\n\t\t\t<mapZone other=\"Romance Standard Time\" territory=\"BE\" type=\"Europe/Brussels\"/>\n\t\t\t<mapZone other=\"Romance Standard Time\" territory=\"DK\" type=\"Europe/Copenhagen\"/>\n\t\t\t<mapZone other=\"Romance Standard Time\" territory=\"ES\" type=\"Europe/Madrid Africa/Ceuta\"/>\n\t\t\t<mapZone other=\"Romance Standard Time\" territory=\"FR\" type=\"Europe/Paris\"/>\n\n\t\t\t<!-- (UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb -->\n\t\t\t<mapZone other=\"Central European Standard Time\" territory=\"001\" type=\"Europe/Warsaw\"/>\n\t\t\t<mapZone other=\"Central European Standard Time\" territory=\"BA\" type=\"Europe/Sarajevo\"/>\n\t\t\t<mapZone other=\"Central European Standard Time\" territory=\"HR\" type=\"Europe/Zagreb\"/>\n\t\t\t<mapZone other=\"Central European Standard Time\" territory=\"MK\" type=\"Europe/Skopje\"/>\n\t\t\t<mapZone other=\"Central European Standard Time\" territory=\"PL\" type=\"Europe/Warsaw\"/>\n\n\t\t\t<!-- (UTC+01:00) West Central Africa -->\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"001\" type=\"Africa/Lagos\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"AO\" type=\"Africa/Luanda\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"BJ\" type=\"Africa/Porto-Novo\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"CD\" type=\"Africa/Kinshasa\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"CF\" type=\"Africa/Bangui\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"CG\" type=\"Africa/Brazzaville\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"CM\" type=\"Africa/Douala\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"DZ\" type=\"Africa/Algiers\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"GA\" type=\"Africa/Libreville\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"GQ\" type=\"Africa/Malabo\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"NE\" type=\"Africa/Niamey\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"NG\" type=\"Africa/Lagos\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"TD\" type=\"Africa/Ndjamena\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"TN\" type=\"Africa/Tunis\"/>\n\t\t\t<mapZone other=\"W. Central Africa Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-1\"/>\n\n\t\t\t<!-- (UTC+02:00) Amman -->\n\t\t\t<mapZone other=\"Jordan Standard Time\" territory=\"001\" type=\"Asia/Amman\"/>\n\t\t\t<mapZone other=\"Jordan Standard Time\" territory=\"JO\" type=\"Asia/Amman\"/>\n\n\t\t\t<!-- (UTC+02:00) Athens, Bucharest -->\n\t\t\t<mapZone other=\"GTB Standard Time\" territory=\"001\" type=\"Europe/Bucharest\"/>\n\t\t\t<mapZone other=\"GTB Standard Time\" territory=\"CY\" type=\"Asia/Nicosia Asia/Famagusta\"/>\n\t\t\t<mapZone other=\"GTB Standard Time\" territory=\"GR\" type=\"Europe/Athens\"/>\n\t\t\t<mapZone other=\"GTB Standard Time\" territory=\"RO\" type=\"Europe/Bucharest\"/>\n\n\t\t\t<!-- (UTC+02:00) Beirut -->\n\t\t\t<mapZone other=\"Middle East Standard Time\" territory=\"001\" type=\"Asia/Beirut\"/>\n\t\t\t<mapZone other=\"Middle East Standard Time\" territory=\"LB\" type=\"Asia/Beirut\"/>\n\n\t\t\t<!-- (UTC+02:00) Cairo -->\n\t\t\t<mapZone other=\"Egypt Standard Time\" territory=\"001\" type=\"Africa/Cairo\"/>\n\t\t\t<mapZone other=\"Egypt Standard Time\" territory=\"EG\" type=\"Africa/Cairo\"/>\n\n\t\t\t<!-- (UTC+02:00) Chisinau -->\n\t\t\t<mapZone other=\"E. Europe Standard Time\" territory=\"001\" type=\"Europe/Chisinau\"/>\n\t\t\t<mapZone other=\"E. Europe Standard Time\" territory=\"MD\" type=\"Europe/Chisinau\"/>\n\n\t\t\t<!-- (UTC+02:00) Damascus -->\n\t\t\t<mapZone other=\"Syria Standard Time\" territory=\"001\" type=\"Asia/Damascus\"/>\n\t\t\t<mapZone other=\"Syria Standard Time\" territory=\"SY\" type=\"Asia/Damascus\"/>\n\n\t\t\t<!-- (UTC+02:00) Gaza, Hebron -->\n\t\t\t<mapZone other=\"West Bank Standard Time\" territory=\"001\" type=\"Asia/Hebron\"/>\n\t\t\t<mapZone other=\"West Bank Standard Time\" territory=\"PS\" type=\"Asia/Hebron Asia/Gaza\"/>\n\n\t\t\t<!-- (UTC+02:00) Harare, Pretoria -->\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"001\" type=\"Africa/Johannesburg\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"BI\" type=\"Africa/Bujumbura\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"BW\" type=\"Africa/Gaborone\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"CD\" type=\"Africa/Lubumbashi\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"LS\" type=\"Africa/Maseru\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"MW\" type=\"Africa/Blantyre\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"MZ\" type=\"Africa/Maputo\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"RW\" type=\"Africa/Kigali\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"SZ\" type=\"Africa/Mbabane\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"ZA\" type=\"Africa/Johannesburg\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"ZM\" type=\"Africa/Lusaka\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"ZW\" type=\"Africa/Harare\"/>\n\t\t\t<mapZone other=\"South Africa Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-2\"/>\n\n\t\t\t<!-- (UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius -->\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"001\" type=\"Europe/Kiev\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"AX\" type=\"Europe/Mariehamn\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"BG\" type=\"Europe/Sofia\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"EE\" type=\"Europe/Tallinn\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"FI\" type=\"Europe/Helsinki\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"LT\" type=\"Europe/Vilnius\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"LV\" type=\"Europe/Riga\"/>\n\t\t\t<mapZone other=\"FLE Standard Time\" territory=\"UA\" type=\"Europe/Kiev\"/>\n\n\t\t\t<!-- (UTC+02:00) Jerusalem -->\n\t\t\t<mapZone other=\"Israel Standard Time\" territory=\"001\" type=\"Asia/Jerusalem\"/>\n\t\t\t<mapZone other=\"Israel Standard Time\" territory=\"IL\" type=\"Asia/Jerusalem\"/>\n\n\t\t\t<!-- (UTC+02:00) Juba -->\n\t\t\t<mapZone other=\"South Sudan Standard Time\" territory=\"001\" type=\"Africa/Juba\"/>\n\t\t\t<mapZone other=\"South Sudan Standard Time\" territory=\"SS\" type=\"Africa/Juba\"/>\n\n\t\t\t<!-- (UTC+02:00) Kaliningrad -->\n\t\t\t<mapZone other=\"Kaliningrad Standard Time\" territory=\"001\" type=\"Europe/Kaliningrad\"/>\n\t\t\t<mapZone other=\"Kaliningrad Standard Time\" territory=\"RU\" type=\"Europe/Kaliningrad\"/>\n\n\t\t\t<!-- (UTC+02:00) Khartoum -->\n\t\t\t<mapZone other=\"Sudan Standard Time\" territory=\"001\" type=\"Africa/Khartoum\"/>\n\t\t\t<mapZone other=\"Sudan Standard Time\" territory=\"SD\" type=\"Africa/Khartoum\"/>\n\n\t\t\t<!-- (UTC+02:00) Tripoli -->\n\t\t\t<mapZone other=\"Libya Standard Time\" territory=\"001\" type=\"Africa/Tripoli\"/>\n\t\t\t<mapZone other=\"Libya Standard Time\" territory=\"LY\" type=\"Africa/Tripoli\"/>\n\n\t\t\t<!-- (UTC+02:00) Windhoek -->\n\t\t\t<mapZone other=\"Namibia Standard Time\" territory=\"001\" type=\"Africa/Windhoek\"/>\n\t\t\t<mapZone other=\"Namibia Standard Time\" territory=\"NA\" type=\"Africa/Windhoek\"/>\n\n\t\t\t<!-- (UTC+03:00) Baghdad -->\n\t\t\t<mapZone other=\"Arabic Standard Time\" territory=\"001\" type=\"Asia/Baghdad\"/>\n\t\t\t<mapZone other=\"Arabic Standard Time\" territory=\"IQ\" type=\"Asia/Baghdad\"/>\n\n\t\t\t<!-- (UTC+03:00) Istanbul -->\n\t\t\t<mapZone other=\"Turkey Standard Time\" territory=\"001\" type=\"Europe/Istanbul\"/>\n\t\t\t<mapZone other=\"Turkey Standard Time\" territory=\"TR\" type=\"Europe/Istanbul\"/>\n\n\t\t\t<!-- (UTC+03:00) Kuwait, Riyadh -->\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"001\" type=\"Asia/Riyadh\"/>\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"BH\" type=\"Asia/Bahrain\"/>\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"KW\" type=\"Asia/Kuwait\"/>\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"QA\" type=\"Asia/Qatar\"/>\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"SA\" type=\"Asia/Riyadh\"/>\n\t\t\t<mapZone other=\"Arab Standard Time\" territory=\"YE\" type=\"Asia/Aden\"/>\n\n\t\t\t<!-- (UTC+03:00) Minsk -->\n\t\t\t<mapZone other=\"Belarus Standard Time\" territory=\"001\" type=\"Europe/Minsk\"/>\n\t\t\t<mapZone other=\"Belarus Standard Time\" territory=\"BY\" type=\"Europe/Minsk\"/>\n\n\t\t\t<!-- (UTC+03:00) Moscow, St. Petersburg -->\n\t\t\t<mapZone other=\"Russian Standard Time\" territory=\"001\" type=\"Europe/Moscow\"/>\n\t\t\t<mapZone other=\"Russian Standard Time\" territory=\"RU\" type=\"Europe/Moscow Europe/Kirov\"/>\n\t\t\t<mapZone other=\"Russian Standard Time\" territory=\"UA\" type=\"Europe/Simferopol\"/>\n\n\t\t\t<!-- (UTC+03:00) Nairobi -->\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"001\" type=\"Africa/Nairobi\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"AQ\" type=\"Antarctica/Syowa\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"DJ\" type=\"Africa/Djibouti\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"ER\" type=\"Africa/Asmera\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"ET\" type=\"Africa/Addis_Ababa\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"KE\" type=\"Africa/Nairobi\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"KM\" type=\"Indian/Comoro\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"MG\" type=\"Indian/Antananarivo\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"SO\" type=\"Africa/Mogadishu\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"TZ\" type=\"Africa/Dar_es_Salaam\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"UG\" type=\"Africa/Kampala\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"YT\" type=\"Indian/Mayotte\"/>\n\t\t\t<mapZone other=\"E. Africa Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-3\"/>\n\n\t\t\t<!-- (UTC+03:30) Tehran -->\n\t\t\t<mapZone other=\"Iran Standard Time\" territory=\"001\" type=\"Asia/Tehran\"/>\n\t\t\t<mapZone other=\"Iran Standard Time\" territory=\"IR\" type=\"Asia/Tehran\"/>\n\n\t\t\t<!-- (UTC+04:00) Abu Dhabi, Muscat -->\n\t\t\t<mapZone other=\"Arabian Standard Time\" territory=\"001\" type=\"Asia/Dubai\"/>\n\t\t\t<mapZone other=\"Arabian Standard Time\" territory=\"AE\" type=\"Asia/Dubai\"/>\n\t\t\t<mapZone other=\"Arabian Standard Time\" territory=\"OM\" type=\"Asia/Muscat\"/>\n\t\t\t<mapZone other=\"Arabian Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-4\"/>\n\n\t\t\t<!-- (UTC+04:00) Astrakhan, Ulyanovsk -->\n\t\t\t<mapZone other=\"Astrakhan Standard Time\" territory=\"001\" type=\"Europe/Astrakhan\"/>\n\t\t\t<mapZone other=\"Astrakhan Standard Time\" territory=\"RU\" type=\"Europe/Astrakhan Europe/Ulyanovsk\"/>\n\n\t\t\t<!-- (UTC+04:00) Baku -->\n\t\t\t<mapZone other=\"Azerbaijan Standard Time\" territory=\"001\" type=\"Asia/Baku\"/>\n\t\t\t<mapZone other=\"Azerbaijan Standard Time\" territory=\"AZ\" type=\"Asia/Baku\"/>\n\n\t\t\t<!-- (UTC+04:00) Izhevsk, Samara -->\n\t\t\t<mapZone other=\"Russia Time Zone 3\" territory=\"001\" type=\"Europe/Samara\"/>\n\t\t\t<mapZone other=\"Russia Time Zone 3\" territory=\"RU\" type=\"Europe/Samara\"/>\n\n\t\t\t<!-- (UTC+04:00) Port Louis -->\n\t\t\t<mapZone other=\"Mauritius Standard Time\" territory=\"001\" type=\"Indian/Mauritius\"/>\n\t\t\t<mapZone other=\"Mauritius Standard Time\" territory=\"MU\" type=\"Indian/Mauritius\"/>\n\t\t\t<mapZone other=\"Mauritius Standard Time\" territory=\"RE\" type=\"Indian/Reunion\"/>\n\t\t\t<mapZone other=\"Mauritius Standard Time\" territory=\"SC\" type=\"Indian/Mahe\"/>\n\n\t\t\t<!-- (UTC+04:00) Saratov -->\n\t\t\t<mapZone other=\"Saratov Standard Time\" territory=\"001\" type=\"Europe/Saratov\"/>\n\t\t\t<mapZone other=\"Saratov Standard Time\" territory=\"RU\" type=\"Europe/Saratov\"/>\n\n\t\t\t<!-- (UTC+04:00) Tbilisi -->\n\t\t\t<mapZone other=\"Georgian Standard Time\" territory=\"001\" type=\"Asia/Tbilisi\"/>\n\t\t\t<mapZone other=\"Georgian Standard Time\" territory=\"GE\" type=\"Asia/Tbilisi\"/>\n\n\t\t\t<!-- (UTC+04:00) Volgograd -->\n\t\t\t<mapZone other=\"Volgograd Standard Time\" territory=\"001\" type=\"Europe/Volgograd\"/>\n\t\t\t<mapZone other=\"Volgograd Standard Time\" territory=\"RU\" type=\"Europe/Volgograd\"/>\n\n\t\t\t<!-- (UTC+04:00) Yerevan -->\n\t\t\t<mapZone other=\"Caucasus Standard Time\" territory=\"001\" type=\"Asia/Yerevan\"/>\n\t\t\t<mapZone other=\"Caucasus Standard Time\" territory=\"AM\" type=\"Asia/Yerevan\"/>\n\n\t\t\t<!-- (UTC+04:30) Kabul -->\n\t\t\t<mapZone other=\"Afghanistan Standard Time\" territory=\"001\" type=\"Asia/Kabul\"/>\n\t\t\t<mapZone other=\"Afghanistan Standard Time\" territory=\"AF\" type=\"Asia/Kabul\"/>\n\n\t\t\t<!-- (UTC+05:00) Ashgabat, Tashkent -->\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"001\" type=\"Asia/Tashkent\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"AQ\" type=\"Antarctica/Mawson\"/>\n\t\t\t<!-- Microsoft may create a new zone dedicated for Almaty and Qostanay. -->\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"KZ\" type=\"Asia/Oral Asia/Almaty Asia/Aqtau Asia/Aqtobe Asia/Atyrau Asia/Qostanay\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"MV\" type=\"Indian/Maldives\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"TF\" type=\"Indian/Kerguelen\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"TJ\" type=\"Asia/Dushanbe\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"TM\" type=\"Asia/Ashgabat\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"UZ\" type=\"Asia/Tashkent Asia/Samarkand\"/>\n\t\t\t<mapZone other=\"West Asia Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-5\"/>\n\n\t\t\t<!-- (UTC+05:00) Ekaterinburg -->\n\t\t\t<mapZone other=\"Ekaterinburg Standard Time\" territory=\"001\" type=\"Asia/Yekaterinburg\"/>\n\t\t\t<mapZone other=\"Ekaterinburg Standard Time\" territory=\"RU\" type=\"Asia/Yekaterinburg\"/>\n\n\t\t\t<!-- (UTC+05:00) Islamabad, Karachi -->\n\t\t\t<mapZone other=\"Pakistan Standard Time\" territory=\"001\" type=\"Asia/Karachi\"/>\n\t\t\t<mapZone other=\"Pakistan Standard Time\" territory=\"PK\" type=\"Asia/Karachi\"/>\n\n\t\t\t<!-- (UTC+05:00) Qyzylorda -->\n\t\t\t<mapZone other=\"Qyzylorda Standard Time\" territory=\"001\" type=\"Asia/Qyzylorda\"/>\n\t\t\t<mapZone other=\"Qyzylorda Standard Time\" territory=\"KZ\" type=\"Asia/Qyzylorda\"/>\n\n\t\t\t<!-- (UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi -->\n\t\t\t<mapZone other=\"India Standard Time\" territory=\"001\" type=\"Asia/Calcutta\"/>\n\t\t\t<mapZone other=\"India Standard Time\" territory=\"IN\" type=\"Asia/Calcutta\"/>\n\n\t\t\t<!-- (UTC+05:30) Sri Jayawardenepura -->\n\t\t\t<mapZone other=\"Sri Lanka Standard Time\" territory=\"001\" type=\"Asia/Colombo\"/>\n\t\t\t<mapZone other=\"Sri Lanka Standard Time\" territory=\"LK\" type=\"Asia/Colombo\"/>\n\n\t\t\t<!-- (UTC+05:45) Kathmandu -->\n\t\t\t<mapZone other=\"Nepal Standard Time\" territory=\"001\" type=\"Asia/Katmandu\"/>\n\t\t\t<mapZone other=\"Nepal Standard Time\" territory=\"NP\" type=\"Asia/Katmandu\"/>\n\n\t\t\t<!-- (UTC+06:00) Astana --> <!-- Microsoft probably keeps Central Asia Standard Time, but change Astana to something else. -->\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"001\" type=\"Asia/Bishkek\"/>\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"AQ\" type=\"Antarctica/Vostok\"/>\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"CN\" type=\"Asia/Urumqi\"/>\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"IO\" type=\"Indian/Chagos\"/>\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"KG\" type=\"Asia/Bishkek\"/>\n\t\t\t<mapZone other=\"Central Asia Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-6\"/>\n\n\t\t\t<!-- (UTC+06:00) Dhaka -->\n\t\t\t<mapZone other=\"Bangladesh Standard Time\" territory=\"001\" type=\"Asia/Dhaka\"/>\n\t\t\t<mapZone other=\"Bangladesh Standard Time\" territory=\"BD\" type=\"Asia/Dhaka\"/>\n\t\t\t<mapZone other=\"Bangladesh Standard Time\" territory=\"BT\" type=\"Asia/Thimphu\"/>\n\n\t\t\t<!-- (UTC+06:00) Omsk -->\n\t\t\t<mapZone other=\"Omsk Standard Time\" territory=\"001\" type=\"Asia/Omsk\"/>\n\t\t\t<mapZone other=\"Omsk Standard Time\" territory=\"RU\" type=\"Asia/Omsk\"/>\n\n\t\t\t<!-- (UTC+06:30) Yangon (Rangoon) -->\n\t\t\t<mapZone other=\"Myanmar Standard Time\" territory=\"001\" type=\"Asia/Rangoon\"/>\n\t\t\t<mapZone other=\"Myanmar Standard Time\" territory=\"CC\" type=\"Indian/Cocos\"/>\n\t\t\t<mapZone other=\"Myanmar Standard Time\" territory=\"MM\" type=\"Asia/Rangoon\"/>\n\n\t\t\t<!-- (UTC+07:00) Bangkok, Hanoi, Jakarta -->\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"001\" type=\"Asia/Bangkok\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"AQ\" type=\"Antarctica/Davis\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"CX\" type=\"Indian/Christmas\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"ID\" type=\"Asia/Jakarta Asia/Pontianak\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"KH\" type=\"Asia/Phnom_Penh\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"LA\" type=\"Asia/Vientiane\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"TH\" type=\"Asia/Bangkok\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"VN\" type=\"Asia/Saigon\"/>\n\t\t\t<mapZone other=\"SE Asia Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-7\"/>\n\n\t\t\t<!-- (UTC+07:00) Barnaul, Gorno-Altaysk -->\n\t\t\t<mapZone other=\"Altai Standard Time\" territory=\"001\" type=\"Asia/Barnaul\"/>\n\t\t\t<mapZone other=\"Altai Standard Time\" territory=\"RU\" type=\"Asia/Barnaul\"/>\n\n\t\t\t<!-- (UTC+07:00) Hovd -->\n\t\t\t<mapZone other=\"W. Mongolia Standard Time\" territory=\"001\" type=\"Asia/Hovd\"/>\n\t\t\t<mapZone other=\"W. Mongolia Standard Time\" territory=\"MN\" type=\"Asia/Hovd\"/>\n\n\t\t\t<!-- (UTC+07:00) Krasnoyarsk -->\n\t\t\t<mapZone other=\"North Asia Standard Time\" territory=\"001\" type=\"Asia/Krasnoyarsk\"/>\n\t\t\t<mapZone other=\"North Asia Standard Time\" territory=\"RU\" type=\"Asia/Krasnoyarsk Asia/Novokuznetsk\"/>\n\n\t\t\t<!-- (UTC+07:00) Novosibirsk -->\n\t\t\t<mapZone other=\"N. Central Asia Standard Time\" territory=\"001\" type=\"Asia/Novosibirsk\"/>\n\t\t\t<mapZone other=\"N. Central Asia Standard Time\" territory=\"RU\" type=\"Asia/Novosibirsk\"/>\n\n\t\t\t<!-- (UTC+07:00) Tomsk -->\n\t\t\t<mapZone other=\"Tomsk Standard Time\" territory=\"001\" type=\"Asia/Tomsk\"/>\n\t\t\t<mapZone other=\"Tomsk Standard Time\" territory=\"RU\" type=\"Asia/Tomsk\"/>\n\n\t\t\t<!-- (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi -->\n\t\t\t<mapZone other=\"China Standard Time\" territory=\"001\" type=\"Asia/Shanghai\"/>\n\t\t\t<mapZone other=\"China Standard Time\" territory=\"CN\" type=\"Asia/Shanghai\"/>\n\t\t\t<mapZone other=\"China Standard Time\" territory=\"HK\" type=\"Asia/Hong_Kong\"/>\n\t\t\t<mapZone other=\"China Standard Time\" territory=\"MO\" type=\"Asia/Macau\"/>\n\n\t\t\t<!-- (UTC+08:00) Irkutsk -->\n\t\t\t<mapZone other=\"North Asia East Standard Time\" territory=\"001\" type=\"Asia/Irkutsk\"/>\n\t\t\t<mapZone other=\"North Asia East Standard Time\" territory=\"RU\" type=\"Asia/Irkutsk\"/>\n\n\t\t\t<!-- (UTC+08:00) Kuala Lumpur, Singapore -->\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"001\" type=\"Asia/Singapore\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"BN\" type=\"Asia/Brunei\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"ID\" type=\"Asia/Makassar\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"MY\" type=\"Asia/Kuala_Lumpur Asia/Kuching\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"PH\" type=\"Asia/Manila\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"SG\" type=\"Asia/Singapore\"/>\n\t\t\t<mapZone other=\"Singapore Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-8\"/>\n\n\t\t\t<!-- (UTC+08:00) Perth -->\n\t\t\t<mapZone other=\"W. Australia Standard Time\" territory=\"001\" type=\"Australia/Perth\"/>\n\t\t\t<mapZone other=\"W. Australia Standard Time\" territory=\"AU\" type=\"Australia/Perth\"/>\n\n\t\t\t<!-- (UTC+08:00) Taipei -->\n\t\t\t<mapZone other=\"Taipei Standard Time\" territory=\"001\" type=\"Asia/Taipei\"/>\n\t\t\t<mapZone other=\"Taipei Standard Time\" territory=\"TW\" type=\"Asia/Taipei\"/>\n\n\t\t\t<!-- (UTC+08:00) Ulaanbaatar -->\n\t\t\t<mapZone other=\"Ulaanbaatar Standard Time\" territory=\"001\" type=\"Asia/Ulaanbaatar\"/>\n\t\t\t<mapZone other=\"Ulaanbaatar Standard Time\" territory=\"MN\" type=\"Asia/Ulaanbaatar\"/>\n\n\t\t\t<!-- (UTC+08:45) Eucla -->\n\t\t\t<mapZone other=\"Aus Central W. Standard Time\" territory=\"001\" type=\"Australia/Eucla\"/>\n\t\t\t<mapZone other=\"Aus Central W. Standard Time\" territory=\"AU\" type=\"Australia/Eucla\"/>\n\n\t\t\t<!-- (UTC+09:00) Chita -->\n\t\t\t<mapZone other=\"Transbaikal Standard Time\" territory=\"001\" type=\"Asia/Chita\"/>\n\t\t\t<mapZone other=\"Transbaikal Standard Time\" territory=\"RU\" type=\"Asia/Chita\"/>\n\n\t\t\t<!-- (UTC+09:00) Osaka, Sapporo, Tokyo -->\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"001\" type=\"Asia/Tokyo\"/>\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"ID\" type=\"Asia/Jayapura\"/>\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"JP\" type=\"Asia/Tokyo\"/>\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"PW\" type=\"Pacific/Palau\"/>\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"TL\" type=\"Asia/Dili\"/>\n\t\t\t<mapZone other=\"Tokyo Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-9\"/>\n\n\t\t\t<!-- (UTC+09:00) Pyongyang -->\n\t\t\t<mapZone other=\"North Korea Standard Time\" territory=\"001\" type=\"Asia/Pyongyang\"/>\n\t\t\t<mapZone other=\"North Korea Standard Time\" territory=\"KP\" type=\"Asia/Pyongyang\"/>\n\n\t\t\t<!-- (UTC+09:00) Seoul -->\n\t\t\t<mapZone other=\"Korea Standard Time\" territory=\"001\" type=\"Asia/Seoul\"/>\n\t\t\t<mapZone other=\"Korea Standard Time\" territory=\"KR\" type=\"Asia/Seoul\"/>\n\n\t\t\t<!-- (UTC+09:00) Yakutsk -->\n\t\t\t<mapZone other=\"Yakutsk Standard Time\" territory=\"001\" type=\"Asia/Yakutsk\"/>\n\t\t\t<mapZone other=\"Yakutsk Standard Time\" territory=\"RU\" type=\"Asia/Yakutsk Asia/Khandyga\"/>\n\n\t\t\t<!-- (UTC+09:30) Adelaide -->\n\t\t\t<mapZone other=\"Cen. Australia Standard Time\" territory=\"001\" type=\"Australia/Adelaide\"/>\n\t\t\t<mapZone other=\"Cen. Australia Standard Time\" territory=\"AU\" type=\"Australia/Adelaide Australia/Broken_Hill\"/>\n\n\t\t\t<!-- (UTC+09:30) Darwin -->\n\t\t\t<mapZone other=\"AUS Central Standard Time\" territory=\"001\" type=\"Australia/Darwin\"/>\n\t\t\t<mapZone other=\"AUS Central Standard Time\" territory=\"AU\" type=\"Australia/Darwin\"/>\n\n\t\t\t<!-- (UTC+10:00) Brisbane -->\n\t\t\t<mapZone other=\"E. Australia Standard Time\" territory=\"001\" type=\"Australia/Brisbane\"/>\n\t\t\t<mapZone other=\"E. Australia Standard Time\" territory=\"AU\" type=\"Australia/Brisbane Australia/Lindeman\"/>\n\n\t\t\t<!-- (UTC+10:00) Canberra, Melbourne, Sydney -->\n\t\t\t<mapZone other=\"AUS Eastern Standard Time\" territory=\"001\" type=\"Australia/Sydney\"/>\n\t\t\t<mapZone other=\"AUS Eastern Standard Time\" territory=\"AU\" type=\"Australia/Sydney Australia/Melbourne\"/>\n\n\t\t\t<!-- (UTC+10:00) Guam, Port Moresby -->\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"001\" type=\"Pacific/Port_Moresby\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"AQ\" type=\"Antarctica/DumontDUrville\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"FM\" type=\"Pacific/Truk\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"GU\" type=\"Pacific/Guam\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"MP\" type=\"Pacific/Saipan\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"PG\" type=\"Pacific/Port_Moresby\"/>\n\t\t\t<mapZone other=\"West Pacific Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-10\"/>\n\n\t\t\t<!-- (UTC+10:00) Hobart -->\n\t\t\t<mapZone other=\"Tasmania Standard Time\" territory=\"001\" type=\"Australia/Hobart\"/>\n\t\t\t<mapZone other=\"Tasmania Standard Time\" territory=\"AU\" type=\"Australia/Hobart Antarctica/Macquarie\"/>\n\n\t\t\t<!-- (UTC+10:00) Vladivostok -->\n\t\t\t<mapZone other=\"Vladivostok Standard Time\" territory=\"001\" type=\"Asia/Vladivostok\"/>\n\t\t\t<mapZone other=\"Vladivostok Standard Time\" territory=\"RU\" type=\"Asia/Vladivostok Asia/Ust-Nera\"/>\n\n\t\t\t<!-- (UTC+10:30) Lord Howe Island -->\n\t\t\t<mapZone other=\"Lord Howe Standard Time\" territory=\"001\" type=\"Australia/Lord_Howe\"/>\n\t\t\t<mapZone other=\"Lord Howe Standard Time\" territory=\"AU\" type=\"Australia/Lord_Howe\"/>\n\n\t\t\t<!-- (UTC+11:00) Bougainville Island -->\n\t\t\t<mapZone other=\"Bougainville Standard Time\" territory=\"001\" type=\"Pacific/Bougainville\"/>\n\t\t\t<mapZone other=\"Bougainville Standard Time\" territory=\"PG\" type=\"Pacific/Bougainville\"/>\n\n\t\t\t<!-- (UTC+11:00) Chokurdakh -->\n\t\t\t<mapZone other=\"Russia Time Zone 10\" territory=\"001\" type=\"Asia/Srednekolymsk\"/>\n\t\t\t<mapZone other=\"Russia Time Zone 10\" territory=\"RU\" type=\"Asia/Srednekolymsk\"/>\n\n\t\t\t<!-- (UTC+11:00) Magadan -->\n\t\t\t<mapZone other=\"Magadan Standard Time\" territory=\"001\" type=\"Asia/Magadan\"/>\n\t\t\t<mapZone other=\"Magadan Standard Time\" territory=\"RU\" type=\"Asia/Magadan\"/>\n\n\t\t\t<!-- (UTC+11:00) Norfolk Island -->\n\t\t\t<mapZone other=\"Norfolk Standard Time\" territory=\"001\" type=\"Pacific/Norfolk\"/>\n\t\t\t<mapZone other=\"Norfolk Standard Time\" territory=\"NF\" type=\"Pacific/Norfolk\"/>\n\n\t\t\t<!-- (UTC+11:00) Sakhalin -->\n\t\t\t<mapZone other=\"Sakhalin Standard Time\" territory=\"001\" type=\"Asia/Sakhalin\"/>\n\t\t\t<mapZone other=\"Sakhalin Standard Time\" territory=\"RU\" type=\"Asia/Sakhalin\"/>\n\n\t\t\t<!-- (UTC+11:00) Solomon Is., New Caledonia -->\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"001\" type=\"Pacific/Guadalcanal\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"AQ\" type=\"Antarctica/Casey\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"FM\" type=\"Pacific/Ponape Pacific/Kosrae\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"NC\" type=\"Pacific/Noumea\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"SB\" type=\"Pacific/Guadalcanal\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"VU\" type=\"Pacific/Efate\"/>\n\t\t\t<mapZone other=\"Central Pacific Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-11\"/>\n\n\t\t\t<!-- (UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky -->\n\t\t\t<mapZone other=\"Russia Time Zone 11\" territory=\"001\" type=\"Asia/Kamchatka\"/>\n\t\t\t<mapZone other=\"Russia Time Zone 11\" territory=\"RU\" type=\"Asia/Kamchatka Asia/Anadyr\"/>\n\n\t\t\t<!-- (UTC+12:00) Auckland, Wellington -->\n\t\t\t<mapZone other=\"New Zealand Standard Time\" territory=\"001\" type=\"Pacific/Auckland\"/>\n\t\t\t<mapZone other=\"New Zealand Standard Time\" territory=\"AQ\" type=\"Antarctica/McMurdo\"/>\n\t\t\t<mapZone other=\"New Zealand Standard Time\" territory=\"NZ\" type=\"Pacific/Auckland\"/>\n\n\t\t\t<!-- (UTC+12:00) Coordinated Universal Time+12 -->\n\t\t\t<mapZone other=\"UTC+12\" territory=\"001\" type=\"Etc/GMT-12\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"KI\" type=\"Pacific/Tarawa\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"MH\" type=\"Pacific/Majuro Pacific/Kwajalein\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"NR\" type=\"Pacific/Nauru\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"TV\" type=\"Pacific/Funafuti\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"UM\" type=\"Pacific/Wake\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"WF\" type=\"Pacific/Wallis\"/>\n\t\t\t<mapZone other=\"UTC+12\" territory=\"ZZ\" type=\"Etc/GMT-12\"/>\n\n\t\t\t<!-- (UTC+12:00) Fiji -->\n\t\t\t<mapZone other=\"Fiji Standard Time\" territory=\"001\" type=\"Pacific/Fiji\"/>\n\t\t\t<mapZone other=\"Fiji Standard Time\" territory=\"FJ\" type=\"Pacific/Fiji\"/>\n\n\t\t\t<!-- (UTC+12:45) Chatham Islands -->\n\t\t\t<mapZone other=\"Chatham Islands Standard Time\" territory=\"001\" type=\"Pacific/Chatham\"/>\n\t\t\t<mapZone other=\"Chatham Islands Standard Time\" territory=\"NZ\" type=\"Pacific/Chatham\"/>\n\n\t\t\t<!-- (UTC+13:00) Coordinated Universal Time+13 -->\n\t\t\t<mapZone other=\"UTC+13\" territory=\"001\" type=\"Etc/GMT-13\"/>\n\t\t\t<mapZone other=\"UTC+13\" territory=\"KI\" type=\"Pacific/Enderbury\"/>\n\t\t\t<mapZone other=\"UTC+13\" territory=\"TK\" type=\"Pacific/Fakaofo\"/>\n\t\t\t<mapZone other=\"UTC+13\" territory=\"ZZ\" type=\"Etc/GMT-13\"/>\n\n\t\t\t<!-- (UTC+13:00) Nuku'alofa -->\n\t\t\t<mapZone other=\"Tonga Standard Time\" territory=\"001\" type=\"Pacific/Tongatapu\"/>\n\t\t\t<mapZone other=\"Tonga Standard Time\" territory=\"TO\" type=\"Pacific/Tongatapu\"/>\n\n\t\t\t<!-- (UTC+13:00) Samoa -->\n\t\t\t<mapZone other=\"Samoa Standard Time\" territory=\"001\" type=\"Pacific/Apia\"/>\n\t\t\t<mapZone other=\"Samoa Standard Time\" territory=\"WS\" type=\"Pacific/Apia\"/>\n\n\t\t\t<!-- (UTC+14:00) Kiritimati Island -->\n\t\t\t<mapZone other=\"Line Islands Standard Time\" territory=\"001\" type=\"Pacific/Kiritimati\"/>\n\t\t\t<mapZone other=\"Line Islands Standard Time\" territory=\"KI\" type=\"Pacific/Kiritimati\"/>\n\t\t\t<mapZone other=\"Line Islands Standard Time\" territory=\"ZZ\" type=\"Etc/GMT-14\"/>\n\t\t</mapTimezones>\n\t</windowsZones>\n</supplementalData>\n"
  },
  {
    "path": "src/location.zig",
    "content": "//!This file is generated. Do not edit directly! Run `zig build generate` to update after obtaining\n//!the latest dataset.\n\nconst builtin = @import(\"builtin\");\npub const Location = enum {\n    @\"Africa/Abidjan\",\n    @\"Africa/Accra\",\n    @\"Africa/Addis_Ababa\",\n    @\"Africa/Algiers\",\n    @\"Africa/Asmera\",\n    @\"Africa/Bamako\",\n    @\"Africa/Bangui\",\n    @\"Africa/Banjul\",\n    @\"Africa/Bissau\",\n    @\"Africa/Blantyre\",\n    @\"Africa/Brazzaville\",\n    @\"Africa/Bujumbura\",\n    @\"Africa/Cairo\",\n    @\"Africa/Casablanca\",\n    @\"Africa/Ceuta\",\n    @\"Africa/Conakry\",\n    @\"Africa/Dakar\",\n    @\"Africa/Dar_es_Salaam\",\n    @\"Africa/Djibouti\",\n    @\"Africa/Douala\",\n    @\"Africa/El_Aaiun\",\n    @\"Africa/Freetown\",\n    @\"Africa/Gaborone\",\n    @\"Africa/Harare\",\n    @\"Africa/Johannesburg\",\n    @\"Africa/Juba\",\n    @\"Africa/Kampala\",\n    @\"Africa/Khartoum\",\n    @\"Africa/Kigali\",\n    @\"Africa/Kinshasa\",\n    @\"Africa/Lagos\",\n    @\"Africa/Libreville\",\n    @\"Africa/Lome\",\n    @\"Africa/Luanda\",\n    @\"Africa/Lubumbashi\",\n    @\"Africa/Lusaka\",\n    @\"Africa/Malabo\",\n    @\"Africa/Maputo\",\n    @\"Africa/Maseru\",\n    @\"Africa/Mbabane\",\n    @\"Africa/Mogadishu\",\n    @\"Africa/Monrovia\",\n    @\"Africa/Nairobi\",\n    @\"Africa/Ndjamena\",\n    @\"Africa/Niamey\",\n    @\"Africa/Nouakchott\",\n    @\"Africa/Ouagadougou\",\n    @\"Africa/Porto-Novo\",\n    @\"Africa/Sao_Tome\",\n    @\"Africa/Tripoli\",\n    @\"Africa/Tunis\",\n    @\"Africa/Windhoek\",\n    @\"America/Adak\",\n    @\"America/Anchorage\",\n    @\"America/Anguilla\",\n    @\"America/Antigua\",\n    @\"America/Araguaina\",\n    @\"America/Argentina/La_Rioja\",\n    @\"America/Argentina/Rio_Gallegos\",\n    @\"America/Argentina/Salta\",\n    @\"America/Argentina/San_Juan\",\n    @\"America/Argentina/San_Luis\",\n    @\"America/Argentina/Tucuman\",\n    @\"America/Argentina/Ushuaia\",\n    @\"America/Aruba\",\n    @\"America/Asuncion\",\n    @\"America/Bahia\",\n    @\"America/Bahia_Banderas\",\n    @\"America/Barbados\",\n    @\"America/Belem\",\n    @\"America/Belize\",\n    @\"America/Blanc-Sablon\",\n    @\"America/Boa_Vista\",\n    @\"America/Bogota\",\n    @\"America/Boise\",\n    @\"America/Buenos_Aires\",\n    @\"America/Cambridge_Bay\",\n    @\"America/Campo_Grande\",\n    @\"America/Cancun\",\n    @\"America/Caracas\",\n    @\"America/Catamarca\",\n    @\"America/Cayenne\",\n    @\"America/Cayman\",\n    @\"America/Chicago\",\n    @\"America/Chihuahua\",\n    @\"America/Ciudad_Juarez\",\n    @\"America/Coral_Harbour\",\n    @\"America/Cordoba\",\n    @\"America/Costa_Rica\",\n    @\"America/Creston\",\n    @\"America/Cuiaba\",\n    @\"America/Curacao\",\n    @\"America/Danmarkshavn\",\n    @\"America/Dawson\",\n    @\"America/Dawson_Creek\",\n    @\"America/Denver\",\n    @\"America/Detroit\",\n    @\"America/Dominica\",\n    @\"America/Edmonton\",\n    @\"America/Eirunepe\",\n    @\"America/El_Salvador\",\n    @\"America/Fort_Nelson\",\n    @\"America/Fortaleza\",\n    @\"America/Glace_Bay\",\n    @\"America/Godthab\",\n    @\"America/Goose_Bay\",\n    @\"America/Grand_Turk\",\n    @\"America/Grenada\",\n    @\"America/Guadeloupe\",\n    @\"America/Guatemala\",\n    @\"America/Guayaquil\",\n    @\"America/Guyana\",\n    @\"America/Halifax\",\n    @\"America/Havana\",\n    @\"America/Hermosillo\",\n    @\"America/Indiana/Knox\",\n    @\"America/Indiana/Marengo\",\n    @\"America/Indiana/Petersburg\",\n    @\"America/Indiana/Tell_City\",\n    @\"America/Indiana/Vevay\",\n    @\"America/Indiana/Vincennes\",\n    @\"America/Indiana/Winamac\",\n    @\"America/Indianapolis\",\n    @\"America/Inuvik\",\n    @\"America/Iqaluit\",\n    @\"America/Jamaica\",\n    @\"America/Jujuy\",\n    @\"America/Juneau\",\n    @\"America/Kentucky/Monticello\",\n    @\"America/Kralendijk\",\n    @\"America/La_Paz\",\n    @\"America/Lima\",\n    @\"America/Los_Angeles\",\n    @\"America/Louisville\",\n    @\"America/Lower_Princes\",\n    @\"America/Maceio\",\n    @\"America/Managua\",\n    @\"America/Manaus\",\n    @\"America/Marigot\",\n    @\"America/Martinique\",\n    @\"America/Matamoros\",\n    @\"America/Mazatlan\",\n    @\"America/Mendoza\",\n    @\"America/Menominee\",\n    @\"America/Merida\",\n    @\"America/Metlakatla\",\n    @\"America/Mexico_City\",\n    @\"America/Miquelon\",\n    @\"America/Moncton\",\n    @\"America/Monterrey\",\n    @\"America/Montevideo\",\n    @\"America/Montserrat\",\n    @\"America/Nassau\",\n    @\"America/New_York\",\n    @\"America/Nome\",\n    @\"America/Noronha\",\n    @\"America/North_Dakota/Beulah\",\n    @\"America/North_Dakota/Center\",\n    @\"America/North_Dakota/New_Salem\",\n    @\"America/Ojinaga\",\n    @\"America/Panama\",\n    @\"America/Paramaribo\",\n    @\"America/Phoenix\",\n    @\"America/Port-au-Prince\",\n    @\"America/Port_of_Spain\",\n    @\"America/Porto_Velho\",\n    @\"America/Puerto_Rico\",\n    @\"America/Punta_Arenas\",\n    @\"America/Rankin_Inlet\",\n    @\"America/Recife\",\n    @\"America/Regina\",\n    @\"America/Resolute\",\n    @\"America/Rio_Branco\",\n    @\"America/Santarem\",\n    @\"America/Santiago\",\n    @\"America/Santo_Domingo\",\n    @\"America/Sao_Paulo\",\n    @\"America/Scoresbysund\",\n    @\"America/Sitka\",\n    @\"America/St_Barthelemy\",\n    @\"America/St_Johns\",\n    @\"America/St_Kitts\",\n    @\"America/St_Lucia\",\n    @\"America/St_Thomas\",\n    @\"America/St_Vincent\",\n    @\"America/Swift_Current\",\n    @\"America/Tegucigalpa\",\n    @\"America/Thule\",\n    @\"America/Tijuana\",\n    @\"America/Toronto\",\n    @\"America/Tortola\",\n    @\"America/Vancouver\",\n    @\"America/Whitehorse\",\n    @\"America/Winnipeg\",\n    @\"America/Yakutat\",\n    @\"Antarctica/Casey\",\n    @\"Antarctica/Davis\",\n    @\"Antarctica/DumontDUrville\",\n    @\"Antarctica/Macquarie\",\n    @\"Antarctica/Mawson\",\n    @\"Antarctica/McMurdo\",\n    @\"Antarctica/Palmer\",\n    @\"Antarctica/Rothera\",\n    @\"Antarctica/Syowa\",\n    @\"Antarctica/Vostok\",\n    @\"Arctic/Longyearbyen\",\n    @\"Asia/Aden\",\n    @\"Asia/Almaty\",\n    @\"Asia/Amman\",\n    @\"Asia/Anadyr\",\n    @\"Asia/Aqtau\",\n    @\"Asia/Aqtobe\",\n    @\"Asia/Ashgabat\",\n    @\"Asia/Atyrau\",\n    @\"Asia/Baghdad\",\n    @\"Asia/Bahrain\",\n    @\"Asia/Baku\",\n    @\"Asia/Bangkok\",\n    @\"Asia/Barnaul\",\n    @\"Asia/Beirut\",\n    @\"Asia/Bishkek\",\n    @\"Asia/Brunei\",\n    @\"Asia/Calcutta\",\n    @\"Asia/Chita\",\n    @\"Asia/Colombo\",\n    @\"Asia/Damascus\",\n    @\"Asia/Dhaka\",\n    @\"Asia/Dili\",\n    @\"Asia/Dubai\",\n    @\"Asia/Dushanbe\",\n    @\"Asia/Famagusta\",\n    @\"Asia/Gaza\",\n    @\"Asia/Hebron\",\n    @\"Asia/Hong_Kong\",\n    @\"Asia/Hovd\",\n    @\"Asia/Irkutsk\",\n    @\"Asia/Jakarta\",\n    @\"Asia/Jayapura\",\n    @\"Asia/Jerusalem\",\n    @\"Asia/Kabul\",\n    @\"Asia/Kamchatka\",\n    @\"Asia/Karachi\",\n    @\"Asia/Katmandu\",\n    @\"Asia/Khandyga\",\n    @\"Asia/Krasnoyarsk\",\n    @\"Asia/Kuala_Lumpur\",\n    @\"Asia/Kuching\",\n    @\"Asia/Kuwait\",\n    @\"Asia/Macau\",\n    @\"Asia/Magadan\",\n    @\"Asia/Makassar\",\n    @\"Asia/Manila\",\n    @\"Asia/Muscat\",\n    @\"Asia/Nicosia\",\n    @\"Asia/Novokuznetsk\",\n    @\"Asia/Novosibirsk\",\n    @\"Asia/Omsk\",\n    @\"Asia/Oral\",\n    @\"Asia/Phnom_Penh\",\n    @\"Asia/Pontianak\",\n    @\"Asia/Pyongyang\",\n    @\"Asia/Qatar\",\n    @\"Asia/Qostanay\",\n    @\"Asia/Qyzylorda\",\n    @\"Asia/Rangoon\",\n    @\"Asia/Riyadh\",\n    @\"Asia/Saigon\",\n    @\"Asia/Sakhalin\",\n    @\"Asia/Samarkand\",\n    @\"Asia/Seoul\",\n    @\"Asia/Shanghai\",\n    @\"Asia/Singapore\",\n    @\"Asia/Srednekolymsk\",\n    @\"Asia/Taipei\",\n    @\"Asia/Tashkent\",\n    @\"Asia/Tbilisi\",\n    @\"Asia/Tehran\",\n    @\"Asia/Thimphu\",\n    @\"Asia/Tokyo\",\n    @\"Asia/Tomsk\",\n    @\"Asia/Ulaanbaatar\",\n    @\"Asia/Urumqi\",\n    @\"Asia/Ust-Nera\",\n    @\"Asia/Vientiane\",\n    @\"Asia/Vladivostok\",\n    @\"Asia/Yakutsk\",\n    @\"Asia/Yekaterinburg\",\n    @\"Asia/Yerevan\",\n    @\"Atlantic/Azores\",\n    @\"Atlantic/Bermuda\",\n    @\"Atlantic/Canary\",\n    @\"Atlantic/Cape_Verde\",\n    @\"Atlantic/Faeroe\",\n    @\"Atlantic/Madeira\",\n    @\"Atlantic/Reykjavik\",\n    @\"Atlantic/South_Georgia\",\n    @\"Atlantic/St_Helena\",\n    @\"Atlantic/Stanley\",\n    @\"Australia/Adelaide\",\n    @\"Australia/Brisbane\",\n    @\"Australia/Broken_Hill\",\n    @\"Australia/Darwin\",\n    @\"Australia/Eucla\",\n    @\"Australia/Hobart\",\n    @\"Australia/Lindeman\",\n    @\"Australia/Lord_Howe\",\n    @\"Australia/Melbourne\",\n    @\"Australia/Perth\",\n    @\"Australia/Sydney\",\n    @\"Etc/GMT\",\n    @\"Etc/GMT+1\",\n    @\"Etc/GMT+10\",\n    @\"Etc/GMT+11\",\n    @\"Etc/GMT+12\",\n    @\"Etc/GMT+2\",\n    @\"Etc/GMT+3\",\n    @\"Etc/GMT+4\",\n    @\"Etc/GMT+5\",\n    @\"Etc/GMT+6\",\n    @\"Etc/GMT+7\",\n    @\"Etc/GMT+8\",\n    @\"Etc/GMT+9\",\n    @\"Etc/GMT-1\",\n    @\"Etc/GMT-10\",\n    @\"Etc/GMT-11\",\n    @\"Etc/GMT-12\",\n    @\"Etc/GMT-13\",\n    @\"Etc/GMT-14\",\n    @\"Etc/GMT-2\",\n    @\"Etc/GMT-3\",\n    @\"Etc/GMT-4\",\n    @\"Etc/GMT-5\",\n    @\"Etc/GMT-6\",\n    @\"Etc/GMT-7\",\n    @\"Etc/GMT-8\",\n    @\"Etc/GMT-9\",\n    @\"Etc/UTC\",\n    @\"Europe/Amsterdam\",\n    @\"Europe/Andorra\",\n    @\"Europe/Astrakhan\",\n    @\"Europe/Athens\",\n    @\"Europe/Belgrade\",\n    @\"Europe/Berlin\",\n    @\"Europe/Bratislava\",\n    @\"Europe/Brussels\",\n    @\"Europe/Bucharest\",\n    @\"Europe/Budapest\",\n    @\"Europe/Busingen\",\n    @\"Europe/Chisinau\",\n    @\"Europe/Copenhagen\",\n    @\"Europe/Dublin\",\n    @\"Europe/Gibraltar\",\n    @\"Europe/Guernsey\",\n    @\"Europe/Helsinki\",\n    @\"Europe/Isle_of_Man\",\n    @\"Europe/Istanbul\",\n    @\"Europe/Jersey\",\n    @\"Europe/Kaliningrad\",\n    @\"Europe/Kiev\",\n    @\"Europe/Kirov\",\n    @\"Europe/Lisbon\",\n    @\"Europe/Ljubljana\",\n    @\"Europe/London\",\n    @\"Europe/Luxembourg\",\n    @\"Europe/Madrid\",\n    @\"Europe/Malta\",\n    @\"Europe/Mariehamn\",\n    @\"Europe/Minsk\",\n    @\"Europe/Monaco\",\n    @\"Europe/Moscow\",\n    @\"Europe/Oslo\",\n    @\"Europe/Paris\",\n    @\"Europe/Podgorica\",\n    @\"Europe/Prague\",\n    @\"Europe/Riga\",\n    @\"Europe/Rome\",\n    @\"Europe/Samara\",\n    @\"Europe/San_Marino\",\n    @\"Europe/Sarajevo\",\n    @\"Europe/Saratov\",\n    @\"Europe/Simferopol\",\n    @\"Europe/Skopje\",\n    @\"Europe/Sofia\",\n    @\"Europe/Stockholm\",\n    @\"Europe/Tallinn\",\n    @\"Europe/Tirane\",\n    @\"Europe/Ulyanovsk\",\n    @\"Europe/Vaduz\",\n    @\"Europe/Vatican\",\n    @\"Europe/Vienna\",\n    @\"Europe/Vilnius\",\n    @\"Europe/Volgograd\",\n    @\"Europe/Warsaw\",\n    @\"Europe/Zagreb\",\n    @\"Europe/Zurich\",\n    @\"Indian/Antananarivo\",\n    @\"Indian/Chagos\",\n    @\"Indian/Christmas\",\n    @\"Indian/Cocos\",\n    @\"Indian/Comoro\",\n    @\"Indian/Kerguelen\",\n    @\"Indian/Mahe\",\n    @\"Indian/Maldives\",\n    @\"Indian/Mauritius\",\n    @\"Indian/Mayotte\",\n    @\"Indian/Reunion\",\n    @\"Pacific/Apia\",\n    @\"Pacific/Auckland\",\n    @\"Pacific/Bougainville\",\n    @\"Pacific/Chatham\",\n    @\"Pacific/Easter\",\n    @\"Pacific/Efate\",\n    @\"Pacific/Enderbury\",\n    @\"Pacific/Fakaofo\",\n    @\"Pacific/Fiji\",\n    @\"Pacific/Funafuti\",\n    @\"Pacific/Galapagos\",\n    @\"Pacific/Gambier\",\n    @\"Pacific/Guadalcanal\",\n    @\"Pacific/Guam\",\n    @\"Pacific/Honolulu\",\n    @\"Pacific/Kiritimati\",\n    @\"Pacific/Kosrae\",\n    @\"Pacific/Kwajalein\",\n    @\"Pacific/Majuro\",\n    @\"Pacific/Marquesas\",\n    @\"Pacific/Midway\",\n    @\"Pacific/Nauru\",\n    @\"Pacific/Niue\",\n    @\"Pacific/Norfolk\",\n    @\"Pacific/Noumea\",\n    @\"Pacific/Pago_Pago\",\n    @\"Pacific/Palau\",\n    @\"Pacific/Pitcairn\",\n    @\"Pacific/Ponape\",\n    @\"Pacific/Port_Moresby\",\n    @\"Pacific/Rarotonga\",\n    @\"Pacific/Saipan\",\n    @\"Pacific/Tahiti\",\n    @\"Pacific/Tarawa\",\n    @\"Pacific/Tongatapu\",\n    @\"Pacific/Truk\",\n    @\"Pacific/Wake\",\n    @\"Pacific/Wallis\",\n\n    pub fn asText(self: Location) []const u8 {\n        switch (builtin.os.tag) {\n            .windows => {},\n            else => return @tagName(self),\n        }\n        return switch (self) {\n            .@\"Africa/Abidjan\" => \"Greenwich Standard Time\",\n            .@\"Africa/Accra\" => \"Greenwich Standard Time\",\n            .@\"Africa/Addis_Ababa\" => \"E. Africa Standard Time\",\n            .@\"Africa/Algiers\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Asmera\" => \"E. Africa Standard Time\",\n            .@\"Africa/Bamako\" => \"Greenwich Standard Time\",\n            .@\"Africa/Bangui\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Banjul\" => \"Greenwich Standard Time\",\n            .@\"Africa/Bissau\" => \"Greenwich Standard Time\",\n            .@\"Africa/Blantyre\" => \"South Africa Standard Time\",\n            .@\"Africa/Brazzaville\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Bujumbura\" => \"South Africa Standard Time\",\n            .@\"Africa/Cairo\" => \"Egypt Standard Time\",\n            .@\"Africa/Casablanca\" => \"Morocco Standard Time\",\n            .@\"Africa/Ceuta\" => \"Romance Standard Time\",\n            .@\"Africa/Conakry\" => \"Greenwich Standard Time\",\n            .@\"Africa/Dakar\" => \"Greenwich Standard Time\",\n            .@\"Africa/Dar_es_Salaam\" => \"E. Africa Standard Time\",\n            .@\"Africa/Djibouti\" => \"E. Africa Standard Time\",\n            .@\"Africa/Douala\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/El_Aaiun\" => \"Morocco Standard Time\",\n            .@\"Africa/Freetown\" => \"Greenwich Standard Time\",\n            .@\"Africa/Gaborone\" => \"South Africa Standard Time\",\n            .@\"Africa/Harare\" => \"South Africa Standard Time\",\n            .@\"Africa/Johannesburg\" => \"South Africa Standard Time\",\n            .@\"Africa/Juba\" => \"South Sudan Standard Time\",\n            .@\"Africa/Kampala\" => \"E. Africa Standard Time\",\n            .@\"Africa/Khartoum\" => \"Sudan Standard Time\",\n            .@\"Africa/Kigali\" => \"South Africa Standard Time\",\n            .@\"Africa/Kinshasa\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Lagos\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Libreville\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Lome\" => \"Greenwich Standard Time\",\n            .@\"Africa/Luanda\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Lubumbashi\" => \"South Africa Standard Time\",\n            .@\"Africa/Lusaka\" => \"South Africa Standard Time\",\n            .@\"Africa/Malabo\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Maputo\" => \"South Africa Standard Time\",\n            .@\"Africa/Maseru\" => \"South Africa Standard Time\",\n            .@\"Africa/Mbabane\" => \"South Africa Standard Time\",\n            .@\"Africa/Mogadishu\" => \"E. Africa Standard Time\",\n            .@\"Africa/Monrovia\" => \"Greenwich Standard Time\",\n            .@\"Africa/Nairobi\" => \"E. Africa Standard Time\",\n            .@\"Africa/Ndjamena\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Niamey\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Nouakchott\" => \"Greenwich Standard Time\",\n            .@\"Africa/Ouagadougou\" => \"Greenwich Standard Time\",\n            .@\"Africa/Porto-Novo\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Sao_Tome\" => \"Sao Tome Standard Time\",\n            .@\"Africa/Tripoli\" => \"Libya Standard Time\",\n            .@\"Africa/Tunis\" => \"W. Central Africa Standard Time\",\n            .@\"Africa/Windhoek\" => \"Namibia Standard Time\",\n            .@\"America/Adak\" => \"Aleutian Standard Time\",\n            .@\"America/Anchorage\" => \"Alaskan Standard Time\",\n            .@\"America/Anguilla\" => \"SA Western Standard Time\",\n            .@\"America/Antigua\" => \"SA Western Standard Time\",\n            .@\"America/Araguaina\" => \"Tocantins Standard Time\",\n            .@\"America/Argentina/La_Rioja\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/Rio_Gallegos\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/Salta\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/San_Juan\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/San_Luis\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/Tucuman\" => \"Argentina Standard Time\",\n            .@\"America/Argentina/Ushuaia\" => \"Argentina Standard Time\",\n            .@\"America/Aruba\" => \"SA Western Standard Time\",\n            .@\"America/Asuncion\" => \"Paraguay Standard Time\",\n            .@\"America/Bahia\" => \"Bahia Standard Time\",\n            .@\"America/Bahia_Banderas\" => \"Central Standard Time (Mexico)\",\n            .@\"America/Barbados\" => \"SA Western Standard Time\",\n            .@\"America/Belem\" => \"SA Eastern Standard Time\",\n            .@\"America/Belize\" => \"Central America Standard Time\",\n            .@\"America/Blanc-Sablon\" => \"SA Western Standard Time\",\n            .@\"America/Boa_Vista\" => \"SA Western Standard Time\",\n            .@\"America/Bogota\" => \"SA Pacific Standard Time\",\n            .@\"America/Boise\" => \"Mountain Standard Time\",\n            .@\"America/Buenos_Aires\" => \"Argentina Standard Time\",\n            .@\"America/Cambridge_Bay\" => \"Mountain Standard Time\",\n            .@\"America/Campo_Grande\" => \"Central Brazilian Standard Time\",\n            .@\"America/Cancun\" => \"Eastern Standard Time (Mexico)\",\n            .@\"America/Caracas\" => \"Venezuela Standard Time\",\n            .@\"America/Catamarca\" => \"Argentina Standard Time\",\n            .@\"America/Cayenne\" => \"SA Eastern Standard Time\",\n            .@\"America/Cayman\" => \"SA Pacific Standard Time\",\n            .@\"America/Chicago\" => \"Central Standard Time\",\n            .@\"America/Chihuahua\" => \"Central Standard Time (Mexico)\",\n            .@\"America/Ciudad_Juarez\" => \"Mountain Standard Time\",\n            .@\"America/Coral_Harbour\" => \"SA Pacific Standard Time\",\n            .@\"America/Cordoba\" => \"Argentina Standard Time\",\n            .@\"America/Costa_Rica\" => \"Central America Standard Time\",\n            .@\"America/Creston\" => \"US Mountain Standard Time\",\n            .@\"America/Cuiaba\" => \"Central Brazilian Standard Time\",\n            .@\"America/Curacao\" => \"SA Western Standard Time\",\n            .@\"America/Danmarkshavn\" => \"Greenwich Standard Time\",\n            .@\"America/Dawson\" => \"Yukon Standard Time\",\n            .@\"America/Dawson_Creek\" => \"US Mountain Standard Time\",\n            .@\"America/Denver\" => \"Mountain Standard Time\",\n            .@\"America/Detroit\" => \"Eastern Standard Time\",\n            .@\"America/Dominica\" => \"SA Western Standard Time\",\n            .@\"America/Edmonton\" => \"Mountain Standard Time\",\n            .@\"America/Eirunepe\" => \"SA Pacific Standard Time\",\n            .@\"America/El_Salvador\" => \"Central America Standard Time\",\n            .@\"America/Fort_Nelson\" => \"US Mountain Standard Time\",\n            .@\"America/Fortaleza\" => \"SA Eastern Standard Time\",\n            .@\"America/Glace_Bay\" => \"Atlantic Standard Time\",\n            .@\"America/Godthab\" => \"Greenland Standard Time\",\n            .@\"America/Goose_Bay\" => \"Atlantic Standard Time\",\n            .@\"America/Grand_Turk\" => \"Turks And Caicos Standard Time\",\n            .@\"America/Grenada\" => \"SA Western Standard Time\",\n            .@\"America/Guadeloupe\" => \"SA Western Standard Time\",\n            .@\"America/Guatemala\" => \"Central America Standard Time\",\n            .@\"America/Guayaquil\" => \"SA Pacific Standard Time\",\n            .@\"America/Guyana\" => \"SA Western Standard Time\",\n            .@\"America/Halifax\" => \"Atlantic Standard Time\",\n            .@\"America/Havana\" => \"Cuba Standard Time\",\n            .@\"America/Hermosillo\" => \"US Mountain Standard Time\",\n            .@\"America/Indiana/Knox\" => \"Central Standard Time\",\n            .@\"America/Indiana/Marengo\" => \"US Eastern Standard Time\",\n            .@\"America/Indiana/Petersburg\" => \"Eastern Standard Time\",\n            .@\"America/Indiana/Tell_City\" => \"Central Standard Time\",\n            .@\"America/Indiana/Vevay\" => \"US Eastern Standard Time\",\n            .@\"America/Indiana/Vincennes\" => \"Eastern Standard Time\",\n            .@\"America/Indiana/Winamac\" => \"Eastern Standard Time\",\n            .@\"America/Indianapolis\" => \"US Eastern Standard Time\",\n            .@\"America/Inuvik\" => \"Mountain Standard Time\",\n            .@\"America/Iqaluit\" => \"Eastern Standard Time\",\n            .@\"America/Jamaica\" => \"SA Pacific Standard Time\",\n            .@\"America/Jujuy\" => \"Argentina Standard Time\",\n            .@\"America/Juneau\" => \"Alaskan Standard Time\",\n            .@\"America/Kentucky/Monticello\" => \"Eastern Standard Time\",\n            .@\"America/Kralendijk\" => \"SA Western Standard Time\",\n            .@\"America/La_Paz\" => \"SA Western Standard Time\",\n            .@\"America/Lima\" => \"SA Pacific Standard Time\",\n            .@\"America/Los_Angeles\" => \"Pacific Standard Time\",\n            .@\"America/Louisville\" => \"Eastern Standard Time\",\n            .@\"America/Lower_Princes\" => \"SA Western Standard Time\",\n            .@\"America/Maceio\" => \"SA Eastern Standard Time\",\n            .@\"America/Managua\" => \"Central America Standard Time\",\n            .@\"America/Manaus\" => \"SA Western Standard Time\",\n            .@\"America/Marigot\" => \"SA Western Standard Time\",\n            .@\"America/Martinique\" => \"SA Western Standard Time\",\n            .@\"America/Matamoros\" => \"Central Standard Time\",\n            .@\"America/Mazatlan\" => \"Mountain Standard Time (Mexico)\",\n            .@\"America/Mendoza\" => \"Argentina Standard Time\",\n            .@\"America/Menominee\" => \"Central Standard Time\",\n            .@\"America/Merida\" => \"Central Standard Time (Mexico)\",\n            .@\"America/Metlakatla\" => \"Alaskan Standard Time\",\n            .@\"America/Mexico_City\" => \"Central Standard Time (Mexico)\",\n            .@\"America/Miquelon\" => \"Saint Pierre Standard Time\",\n            .@\"America/Moncton\" => \"Atlantic Standard Time\",\n            .@\"America/Monterrey\" => \"Central Standard Time (Mexico)\",\n            .@\"America/Montevideo\" => \"Montevideo Standard Time\",\n            .@\"America/Montserrat\" => \"SA Western Standard Time\",\n            .@\"America/Nassau\" => \"Eastern Standard Time\",\n            .@\"America/New_York\" => \"Eastern Standard Time\",\n            .@\"America/Nome\" => \"Alaskan Standard Time\",\n            .@\"America/Noronha\" => \"UTC-02\",\n            .@\"America/North_Dakota/Beulah\" => \"Central Standard Time\",\n            .@\"America/North_Dakota/Center\" => \"Central Standard Time\",\n            .@\"America/North_Dakota/New_Salem\" => \"Central Standard Time\",\n            .@\"America/Ojinaga\" => \"Central Standard Time\",\n            .@\"America/Panama\" => \"SA Pacific Standard Time\",\n            .@\"America/Paramaribo\" => \"SA Eastern Standard Time\",\n            .@\"America/Phoenix\" => \"US Mountain Standard Time\",\n            .@\"America/Port-au-Prince\" => \"Haiti Standard Time\",\n            .@\"America/Port_of_Spain\" => \"SA Western Standard Time\",\n            .@\"America/Porto_Velho\" => \"SA Western Standard Time\",\n            .@\"America/Puerto_Rico\" => \"SA Western Standard Time\",\n            .@\"America/Punta_Arenas\" => \"Magallanes Standard Time\",\n            .@\"America/Rankin_Inlet\" => \"Central Standard Time\",\n            .@\"America/Recife\" => \"SA Eastern Standard Time\",\n            .@\"America/Regina\" => \"Canada Central Standard Time\",\n            .@\"America/Resolute\" => \"Central Standard Time\",\n            .@\"America/Rio_Branco\" => \"SA Pacific Standard Time\",\n            .@\"America/Santarem\" => \"SA Eastern Standard Time\",\n            .@\"America/Santiago\" => \"Pacific SA Standard Time\",\n            .@\"America/Santo_Domingo\" => \"SA Western Standard Time\",\n            .@\"America/Sao_Paulo\" => \"E. South America Standard Time\",\n            .@\"America/Scoresbysund\" => \"Azores Standard Time\",\n            .@\"America/Sitka\" => \"Alaskan Standard Time\",\n            .@\"America/St_Barthelemy\" => \"SA Western Standard Time\",\n            .@\"America/St_Johns\" => \"Newfoundland Standard Time\",\n            .@\"America/St_Kitts\" => \"SA Western Standard Time\",\n            .@\"America/St_Lucia\" => \"SA Western Standard Time\",\n            .@\"America/St_Thomas\" => \"SA Western Standard Time\",\n            .@\"America/St_Vincent\" => \"SA Western Standard Time\",\n            .@\"America/Swift_Current\" => \"Canada Central Standard Time\",\n            .@\"America/Tegucigalpa\" => \"Central America Standard Time\",\n            .@\"America/Thule\" => \"Atlantic Standard Time\",\n            .@\"America/Tijuana\" => \"Pacific Standard Time (Mexico)\",\n            .@\"America/Toronto\" => \"Eastern Standard Time\",\n            .@\"America/Tortola\" => \"SA Western Standard Time\",\n            .@\"America/Vancouver\" => \"Pacific Standard Time\",\n            .@\"America/Whitehorse\" => \"Yukon Standard Time\",\n            .@\"America/Winnipeg\" => \"Central Standard Time\",\n            .@\"America/Yakutat\" => \"Alaskan Standard Time\",\n            .@\"Antarctica/Casey\" => \"Central Pacific Standard Time\",\n            .@\"Antarctica/Davis\" => \"SE Asia Standard Time\",\n            .@\"Antarctica/DumontDUrville\" => \"West Pacific Standard Time\",\n            .@\"Antarctica/Macquarie\" => \"Tasmania Standard Time\",\n            .@\"Antarctica/Mawson\" => \"West Asia Standard Time\",\n            .@\"Antarctica/McMurdo\" => \"New Zealand Standard Time\",\n            .@\"Antarctica/Palmer\" => \"SA Eastern Standard Time\",\n            .@\"Antarctica/Rothera\" => \"SA Eastern Standard Time\",\n            .@\"Antarctica/Syowa\" => \"E. Africa Standard Time\",\n            .@\"Antarctica/Vostok\" => \"Central Asia Standard Time\",\n            .@\"Arctic/Longyearbyen\" => \"W. Europe Standard Time\",\n            .@\"Asia/Aden\" => \"Arab Standard Time\",\n            .@\"Asia/Almaty\" => \"West Asia Standard Time\",\n            .@\"Asia/Amman\" => \"Jordan Standard Time\",\n            .@\"Asia/Anadyr\" => \"Russia Time Zone 11\",\n            .@\"Asia/Aqtau\" => \"West Asia Standard Time\",\n            .@\"Asia/Aqtobe\" => \"West Asia Standard Time\",\n            .@\"Asia/Ashgabat\" => \"West Asia Standard Time\",\n            .@\"Asia/Atyrau\" => \"West Asia Standard Time\",\n            .@\"Asia/Baghdad\" => \"Arabic Standard Time\",\n            .@\"Asia/Bahrain\" => \"Arab Standard Time\",\n            .@\"Asia/Baku\" => \"Azerbaijan Standard Time\",\n            .@\"Asia/Bangkok\" => \"SE Asia Standard Time\",\n            .@\"Asia/Barnaul\" => \"Altai Standard Time\",\n            .@\"Asia/Beirut\" => \"Middle East Standard Time\",\n            .@\"Asia/Bishkek\" => \"Central Asia Standard Time\",\n            .@\"Asia/Brunei\" => \"Singapore Standard Time\",\n            .@\"Asia/Calcutta\" => \"India Standard Time\",\n            .@\"Asia/Chita\" => \"Transbaikal Standard Time\",\n            .@\"Asia/Colombo\" => \"Sri Lanka Standard Time\",\n            .@\"Asia/Damascus\" => \"Syria Standard Time\",\n            .@\"Asia/Dhaka\" => \"Bangladesh Standard Time\",\n            .@\"Asia/Dili\" => \"Tokyo Standard Time\",\n            .@\"Asia/Dubai\" => \"Arabian Standard Time\",\n            .@\"Asia/Dushanbe\" => \"West Asia Standard Time\",\n            .@\"Asia/Famagusta\" => \"GTB Standard Time\",\n            .@\"Asia/Gaza\" => \"West Bank Standard Time\",\n            .@\"Asia/Hebron\" => \"West Bank Standard Time\",\n            .@\"Asia/Hong_Kong\" => \"China Standard Time\",\n            .@\"Asia/Hovd\" => \"W. Mongolia Standard Time\",\n            .@\"Asia/Irkutsk\" => \"North Asia East Standard Time\",\n            .@\"Asia/Jakarta\" => \"SE Asia Standard Time\",\n            .@\"Asia/Jayapura\" => \"Tokyo Standard Time\",\n            .@\"Asia/Jerusalem\" => \"Israel Standard Time\",\n            .@\"Asia/Kabul\" => \"Afghanistan Standard Time\",\n            .@\"Asia/Kamchatka\" => \"Russia Time Zone 11\",\n            .@\"Asia/Karachi\" => \"Pakistan Standard Time\",\n            .@\"Asia/Katmandu\" => \"Nepal Standard Time\",\n            .@\"Asia/Khandyga\" => \"Yakutsk Standard Time\",\n            .@\"Asia/Krasnoyarsk\" => \"North Asia Standard Time\",\n            .@\"Asia/Kuala_Lumpur\" => \"Singapore Standard Time\",\n            .@\"Asia/Kuching\" => \"Singapore Standard Time\",\n            .@\"Asia/Kuwait\" => \"Arab Standard Time\",\n            .@\"Asia/Macau\" => \"China Standard Time\",\n            .@\"Asia/Magadan\" => \"Magadan Standard Time\",\n            .@\"Asia/Makassar\" => \"Singapore Standard Time\",\n            .@\"Asia/Manila\" => \"Singapore Standard Time\",\n            .@\"Asia/Muscat\" => \"Arabian Standard Time\",\n            .@\"Asia/Nicosia\" => \"GTB Standard Time\",\n            .@\"Asia/Novokuznetsk\" => \"North Asia Standard Time\",\n            .@\"Asia/Novosibirsk\" => \"N. Central Asia Standard Time\",\n            .@\"Asia/Omsk\" => \"Omsk Standard Time\",\n            .@\"Asia/Oral\" => \"West Asia Standard Time\",\n            .@\"Asia/Phnom_Penh\" => \"SE Asia Standard Time\",\n            .@\"Asia/Pontianak\" => \"SE Asia Standard Time\",\n            .@\"Asia/Pyongyang\" => \"North Korea Standard Time\",\n            .@\"Asia/Qatar\" => \"Arab Standard Time\",\n            .@\"Asia/Qostanay\" => \"West Asia Standard Time\",\n            .@\"Asia/Qyzylorda\" => \"Qyzylorda Standard Time\",\n            .@\"Asia/Rangoon\" => \"Myanmar Standard Time\",\n            .@\"Asia/Riyadh\" => \"Arab Standard Time\",\n            .@\"Asia/Saigon\" => \"SE Asia Standard Time\",\n            .@\"Asia/Sakhalin\" => \"Sakhalin Standard Time\",\n            .@\"Asia/Samarkand\" => \"West Asia Standard Time\",\n            .@\"Asia/Seoul\" => \"Korea Standard Time\",\n            .@\"Asia/Shanghai\" => \"China Standard Time\",\n            .@\"Asia/Singapore\" => \"Singapore Standard Time\",\n            .@\"Asia/Srednekolymsk\" => \"Russia Time Zone 10\",\n            .@\"Asia/Taipei\" => \"Taipei Standard Time\",\n            .@\"Asia/Tashkent\" => \"West Asia Standard Time\",\n            .@\"Asia/Tbilisi\" => \"Georgian Standard Time\",\n            .@\"Asia/Tehran\" => \"Iran Standard Time\",\n            .@\"Asia/Thimphu\" => \"Bangladesh Standard Time\",\n            .@\"Asia/Tokyo\" => \"Tokyo Standard Time\",\n            .@\"Asia/Tomsk\" => \"Tomsk Standard Time\",\n            .@\"Asia/Ulaanbaatar\" => \"Ulaanbaatar Standard Time\",\n            .@\"Asia/Urumqi\" => \"Central Asia Standard Time\",\n            .@\"Asia/Ust-Nera\" => \"Vladivostok Standard Time\",\n            .@\"Asia/Vientiane\" => \"SE Asia Standard Time\",\n            .@\"Asia/Vladivostok\" => \"Vladivostok Standard Time\",\n            .@\"Asia/Yakutsk\" => \"Yakutsk Standard Time\",\n            .@\"Asia/Yekaterinburg\" => \"Ekaterinburg Standard Time\",\n            .@\"Asia/Yerevan\" => \"Caucasus Standard Time\",\n            .@\"Atlantic/Azores\" => \"Azores Standard Time\",\n            .@\"Atlantic/Bermuda\" => \"Atlantic Standard Time\",\n            .@\"Atlantic/Canary\" => \"GMT Standard Time\",\n            .@\"Atlantic/Cape_Verde\" => \"Cape Verde Standard Time\",\n            .@\"Atlantic/Faeroe\" => \"GMT Standard Time\",\n            .@\"Atlantic/Madeira\" => \"GMT Standard Time\",\n            .@\"Atlantic/Reykjavik\" => \"Greenwich Standard Time\",\n            .@\"Atlantic/South_Georgia\" => \"UTC-02\",\n            .@\"Atlantic/St_Helena\" => \"Greenwich Standard Time\",\n            .@\"Atlantic/Stanley\" => \"SA Eastern Standard Time\",\n            .@\"Australia/Adelaide\" => \"Cen. Australia Standard Time\",\n            .@\"Australia/Brisbane\" => \"E. Australia Standard Time\",\n            .@\"Australia/Broken_Hill\" => \"Cen. Australia Standard Time\",\n            .@\"Australia/Darwin\" => \"AUS Central Standard Time\",\n            .@\"Australia/Eucla\" => \"Aus Central W. Standard Time\",\n            .@\"Australia/Hobart\" => \"Tasmania Standard Time\",\n            .@\"Australia/Lindeman\" => \"E. Australia Standard Time\",\n            .@\"Australia/Lord_Howe\" => \"Lord Howe Standard Time\",\n            .@\"Australia/Melbourne\" => \"AUS Eastern Standard Time\",\n            .@\"Australia/Perth\" => \"W. Australia Standard Time\",\n            .@\"Australia/Sydney\" => \"AUS Eastern Standard Time\",\n            .@\"Etc/GMT\" => \"UTC\",\n            .@\"Etc/GMT+1\" => \"Cape Verde Standard Time\",\n            .@\"Etc/GMT+10\" => \"Hawaiian Standard Time\",\n            .@\"Etc/GMT+11\" => \"UTC-11\",\n            .@\"Etc/GMT+12\" => \"Dateline Standard Time\",\n            .@\"Etc/GMT+2\" => \"UTC-02\",\n            .@\"Etc/GMT+3\" => \"SA Eastern Standard Time\",\n            .@\"Etc/GMT+4\" => \"SA Western Standard Time\",\n            .@\"Etc/GMT+5\" => \"SA Pacific Standard Time\",\n            .@\"Etc/GMT+6\" => \"Central America Standard Time\",\n            .@\"Etc/GMT+7\" => \"US Mountain Standard Time\",\n            .@\"Etc/GMT+8\" => \"UTC-08\",\n            .@\"Etc/GMT+9\" => \"UTC-09\",\n            .@\"Etc/GMT-1\" => \"W. Central Africa Standard Time\",\n            .@\"Etc/GMT-10\" => \"West Pacific Standard Time\",\n            .@\"Etc/GMT-11\" => \"Central Pacific Standard Time\",\n            .@\"Etc/GMT-12\" => \"UTC+12\",\n            .@\"Etc/GMT-13\" => \"UTC+13\",\n            .@\"Etc/GMT-14\" => \"Line Islands Standard Time\",\n            .@\"Etc/GMT-2\" => \"South Africa Standard Time\",\n            .@\"Etc/GMT-3\" => \"E. Africa Standard Time\",\n            .@\"Etc/GMT-4\" => \"Arabian Standard Time\",\n            .@\"Etc/GMT-5\" => \"West Asia Standard Time\",\n            .@\"Etc/GMT-6\" => \"Central Asia Standard Time\",\n            .@\"Etc/GMT-7\" => \"SE Asia Standard Time\",\n            .@\"Etc/GMT-8\" => \"Singapore Standard Time\",\n            .@\"Etc/GMT-9\" => \"Tokyo Standard Time\",\n            .@\"Etc/UTC\" => \"UTC\",\n            .@\"Europe/Amsterdam\" => \"W. Europe Standard Time\",\n            .@\"Europe/Andorra\" => \"W. Europe Standard Time\",\n            .@\"Europe/Astrakhan\" => \"Astrakhan Standard Time\",\n            .@\"Europe/Athens\" => \"GTB Standard Time\",\n            .@\"Europe/Belgrade\" => \"Central Europe Standard Time\",\n            .@\"Europe/Berlin\" => \"W. Europe Standard Time\",\n            .@\"Europe/Bratislava\" => \"Central Europe Standard Time\",\n            .@\"Europe/Brussels\" => \"Romance Standard Time\",\n            .@\"Europe/Bucharest\" => \"GTB Standard Time\",\n            .@\"Europe/Budapest\" => \"Central Europe Standard Time\",\n            .@\"Europe/Busingen\" => \"W. Europe Standard Time\",\n            .@\"Europe/Chisinau\" => \"E. Europe Standard Time\",\n            .@\"Europe/Copenhagen\" => \"Romance Standard Time\",\n            .@\"Europe/Dublin\" => \"GMT Standard Time\",\n            .@\"Europe/Gibraltar\" => \"W. Europe Standard Time\",\n            .@\"Europe/Guernsey\" => \"GMT Standard Time\",\n            .@\"Europe/Helsinki\" => \"FLE Standard Time\",\n            .@\"Europe/Isle_of_Man\" => \"GMT Standard Time\",\n            .@\"Europe/Istanbul\" => \"Turkey Standard Time\",\n            .@\"Europe/Jersey\" => \"GMT Standard Time\",\n            .@\"Europe/Kaliningrad\" => \"Kaliningrad Standard Time\",\n            .@\"Europe/Kiev\" => \"FLE Standard Time\",\n            .@\"Europe/Kirov\" => \"Russian Standard Time\",\n            .@\"Europe/Lisbon\" => \"GMT Standard Time\",\n            .@\"Europe/Ljubljana\" => \"Central Europe Standard Time\",\n            .@\"Europe/London\" => \"GMT Standard Time\",\n            .@\"Europe/Luxembourg\" => \"W. Europe Standard Time\",\n            .@\"Europe/Madrid\" => \"Romance Standard Time\",\n            .@\"Europe/Malta\" => \"W. Europe Standard Time\",\n            .@\"Europe/Mariehamn\" => \"FLE Standard Time\",\n            .@\"Europe/Minsk\" => \"Belarus Standard Time\",\n            .@\"Europe/Monaco\" => \"W. Europe Standard Time\",\n            .@\"Europe/Moscow\" => \"Russian Standard Time\",\n            .@\"Europe/Oslo\" => \"W. Europe Standard Time\",\n            .@\"Europe/Paris\" => \"Romance Standard Time\",\n            .@\"Europe/Podgorica\" => \"Central Europe Standard Time\",\n            .@\"Europe/Prague\" => \"Central Europe Standard Time\",\n            .@\"Europe/Riga\" => \"FLE Standard Time\",\n            .@\"Europe/Rome\" => \"W. Europe Standard Time\",\n            .@\"Europe/Samara\" => \"Russia Time Zone 3\",\n            .@\"Europe/San_Marino\" => \"W. Europe Standard Time\",\n            .@\"Europe/Sarajevo\" => \"Central European Standard Time\",\n            .@\"Europe/Saratov\" => \"Saratov Standard Time\",\n            .@\"Europe/Simferopol\" => \"Russian Standard Time\",\n            .@\"Europe/Skopje\" => \"Central European Standard Time\",\n            .@\"Europe/Sofia\" => \"FLE Standard Time\",\n            .@\"Europe/Stockholm\" => \"W. Europe Standard Time\",\n            .@\"Europe/Tallinn\" => \"FLE Standard Time\",\n            .@\"Europe/Tirane\" => \"Central Europe Standard Time\",\n            .@\"Europe/Ulyanovsk\" => \"Astrakhan Standard Time\",\n            .@\"Europe/Vaduz\" => \"W. Europe Standard Time\",\n            .@\"Europe/Vatican\" => \"W. Europe Standard Time\",\n            .@\"Europe/Vienna\" => \"W. Europe Standard Time\",\n            .@\"Europe/Vilnius\" => \"FLE Standard Time\",\n            .@\"Europe/Volgograd\" => \"Volgograd Standard Time\",\n            .@\"Europe/Warsaw\" => \"Central European Standard Time\",\n            .@\"Europe/Zagreb\" => \"Central European Standard Time\",\n            .@\"Europe/Zurich\" => \"W. Europe Standard Time\",\n            .@\"Indian/Antananarivo\" => \"E. Africa Standard Time\",\n            .@\"Indian/Chagos\" => \"Central Asia Standard Time\",\n            .@\"Indian/Christmas\" => \"SE Asia Standard Time\",\n            .@\"Indian/Cocos\" => \"Myanmar Standard Time\",\n            .@\"Indian/Comoro\" => \"E. Africa Standard Time\",\n            .@\"Indian/Kerguelen\" => \"West Asia Standard Time\",\n            .@\"Indian/Mahe\" => \"Mauritius Standard Time\",\n            .@\"Indian/Maldives\" => \"West Asia Standard Time\",\n            .@\"Indian/Mauritius\" => \"Mauritius Standard Time\",\n            .@\"Indian/Mayotte\" => \"E. Africa Standard Time\",\n            .@\"Indian/Reunion\" => \"Mauritius Standard Time\",\n            .@\"Pacific/Apia\" => \"Samoa Standard Time\",\n            .@\"Pacific/Auckland\" => \"New Zealand Standard Time\",\n            .@\"Pacific/Bougainville\" => \"Bougainville Standard Time\",\n            .@\"Pacific/Chatham\" => \"Chatham Islands Standard Time\",\n            .@\"Pacific/Easter\" => \"Easter Island Standard Time\",\n            .@\"Pacific/Efate\" => \"Central Pacific Standard Time\",\n            .@\"Pacific/Enderbury\" => \"UTC+13\",\n            .@\"Pacific/Fakaofo\" => \"UTC+13\",\n            .@\"Pacific/Fiji\" => \"Fiji Standard Time\",\n            .@\"Pacific/Funafuti\" => \"UTC+12\",\n            .@\"Pacific/Galapagos\" => \"Central America Standard Time\",\n            .@\"Pacific/Gambier\" => \"UTC-09\",\n            .@\"Pacific/Guadalcanal\" => \"Central Pacific Standard Time\",\n            .@\"Pacific/Guam\" => \"West Pacific Standard Time\",\n            .@\"Pacific/Honolulu\" => \"Hawaiian Standard Time\",\n            .@\"Pacific/Kiritimati\" => \"Line Islands Standard Time\",\n            .@\"Pacific/Kosrae\" => \"Central Pacific Standard Time\",\n            .@\"Pacific/Kwajalein\" => \"UTC+12\",\n            .@\"Pacific/Majuro\" => \"UTC+12\",\n            .@\"Pacific/Marquesas\" => \"Marquesas Standard Time\",\n            .@\"Pacific/Midway\" => \"UTC-11\",\n            .@\"Pacific/Nauru\" => \"UTC+12\",\n            .@\"Pacific/Niue\" => \"UTC-11\",\n            .@\"Pacific/Norfolk\" => \"Norfolk Standard Time\",\n            .@\"Pacific/Noumea\" => \"Central Pacific Standard Time\",\n            .@\"Pacific/Pago_Pago\" => \"UTC-11\",\n            .@\"Pacific/Palau\" => \"Tokyo Standard Time\",\n            .@\"Pacific/Pitcairn\" => \"UTC-08\",\n            .@\"Pacific/Ponape\" => \"Central Pacific Standard Time\",\n            .@\"Pacific/Port_Moresby\" => \"West Pacific Standard Time\",\n            .@\"Pacific/Rarotonga\" => \"Hawaiian Standard Time\",\n            .@\"Pacific/Saipan\" => \"West Pacific Standard Time\",\n            .@\"Pacific/Tahiti\" => \"Hawaiian Standard Time\",\n            .@\"Pacific/Tarawa\" => \"UTC+12\",\n            .@\"Pacific/Tongatapu\" => \"Tonga Standard Time\",\n            .@\"Pacific/Truk\" => \"West Pacific Standard Time\",\n            .@\"Pacific/Wake\" => \"UTC+12\",\n            .@\"Pacific/Wallis\" => \"UTC+12\",\n        };\n    }\n};\n"
  },
  {
    "path": "src/timezone.zig",
    "content": "const std = @import(\"std\");\nconst builtin = @import(\"builtin\");\nconst zeit = @import(\"zeit.zig\");\n\nconst assert = std.debug.assert;\n\nconst Month = zeit.Month;\nconst Seconds = zeit.Seconds;\nconst Weekday = zeit.Weekday;\n\nconst s_per_min = std.time.s_per_min;\nconst s_per_hour = std.time.s_per_hour;\nconst s_per_day = std.time.s_per_day;\n\npub const TimeZone = union(enum) {\n    fixed: Fixed,\n    posix: Posix,\n    tzinfo: TZInfo,\n    windows: switch (builtin.os.tag) {\n        .windows => Windows,\n        else => Noop,\n    },\n\n    pub fn adjust(self: TimeZone, timestamp: Seconds) AdjustedTime {\n        return switch (self) {\n            inline else => |tz| tz.adjust(timestamp),\n        };\n    }\n\n    pub fn deinit(self: TimeZone) void {\n        return switch (self) {\n            .fixed => {},\n            .posix => {},\n            .tzinfo => |tz| tz.deinit(),\n            .windows => |tz| tz.deinit(),\n        };\n    }\n};\n\npub const AdjustedTime = struct {\n    designation: []const u8,\n    timestamp: Seconds,\n    is_dst: bool,\n};\n\n/// A Noop timezone we use for the windows struct when not on windows\npub const Noop = struct {\n    pub fn adjust(_: Noop, timestamp: Seconds) AdjustedTime {\n        return .{\n            .designation = \"noop\",\n            .timestamp = timestamp,\n            .is_dst = false,\n        };\n    }\n\n    pub fn deinit(_: Noop) void {}\n};\n\n/// A fixed timezone\npub const Fixed = struct {\n    name: []const u8,\n    offset: Seconds,\n    is_dst: bool,\n\n    pub fn adjust(self: Fixed, timestamp: Seconds) AdjustedTime {\n        return .{\n            .designation = self.name,\n            .timestamp = timestamp + self.offset,\n            .is_dst = self.is_dst,\n        };\n    }\n};\n\n/// A parsed representation of a Posix TZ string\n/// std offset dst [offset],start[/time],end[/time]\n/// std and dst can be quoted with <>\n/// offsets and times can be [+-]hh[:mm[:ss]]\n/// start and end are of the form J<n>, <n> or M<m>.<w>.<d>\npub const Posix = struct {\n    /// abbreviation for standard time\n    std: []const u8,\n    /// standard time offset in seconds\n    std_offset: Seconds,\n    /// abbreviation for daylight saving time\n    dst: ?[]const u8 = null,\n    /// offset when in dst, defaults to one hour less than std_offset if not present\n    dst_offset: ?Seconds = null,\n\n    start: ?DSTSpec = null,\n    end: ?DSTSpec = null,\n\n    const DSTSpec = union(enum) {\n        /// J<n>: julian day between 1 and 365, Leap day is never counted even in leap\n        /// years\n        julian: struct {\n            day: u9,\n            time: Seconds = 7200,\n        },\n        /// <n>: julian day between 0 and 365. Leap day counts\n        julian_leap: struct {\n            day: u9,\n            time: Seconds = 7200,\n        },\n        /// M<m>.<w>.<d>: day d of week w of month m. Day is 0 (sunday) to 6. week\n        /// is 1 to 5, where 5 would mean last d day of the month.\n        mwd: struct {\n            month: Month,\n            week: u6,\n            day: Weekday,\n            time: Seconds = 7200,\n        },\n\n        fn parse(str: []const u8) !DSTSpec {\n            assert(str.len > 0);\n            switch (str[0]) {\n                'J' => {\n                    const julian = try std.fmt.parseInt(u9, str[1..], 10);\n                    return .{ .julian = .{ .day = julian } };\n                },\n                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {\n                    const julian = try std.fmt.parseInt(u9, str, 10);\n                    return .{ .julian_leap = .{ .day = julian } };\n                },\n                'M' => {\n                    var i: usize = 1;\n                    const m_end = std.mem.indexOfScalarPos(u8, str, i, '.') orelse return error.InvalidPosix;\n                    const month = try std.fmt.parseInt(u4, str[i..m_end], 10);\n                    i = m_end + 1;\n                    const w_end = std.mem.indexOfScalarPos(u8, str, i, '.') orelse return error.InvalidPosix;\n                    const week = try std.fmt.parseInt(u6, str[i..w_end], 10);\n                    i = w_end + 1;\n                    const day = try std.fmt.parseInt(u3, str[i..], 10);\n                    return .{\n                        .mwd = .{\n                            .month = @enumFromInt(month),\n                            .week = week,\n                            .day = @enumFromInt(day),\n                        },\n                    };\n                },\n                else => {},\n            }\n            return error.InvalidPosix;\n        }\n    };\n\n    pub fn parse(str: []const u8) !Posix {\n        var std_: []const u8 = \"\";\n        var std_offset: Seconds = 0;\n        var dst: ?[]const u8 = null;\n        var dst_offset: ?Seconds = null;\n        var start: ?DSTSpec = null;\n        var end: ?DSTSpec = null;\n\n        const State = enum {\n            std,\n            std_offset,\n            dst,\n            dst_offset,\n            start,\n            end,\n        };\n\n        var state: State = .std;\n        var i: usize = 0;\n        while (i < str.len) : (i += 1) {\n            switch (state) {\n                .std => {\n                    switch (str[i]) {\n                        '<' => {\n                            // quoted. Consume until >\n                            const end_qt = std.mem.indexOfScalar(u8, str[i..], '>') orelse return error.InvalidPosix;\n                            std_ = str[i + 1 .. end_qt + i];\n                            i = end_qt;\n                            state = .std_offset;\n                        },\n                        else => {\n                            i = std.mem.indexOfAnyPos(u8, str, i, \"+-0123456789\") orelse return error.InvalidPosix;\n                            std_ = str[0..i];\n                            // backup one so this gets parsed as an offset\n                            i -= 1;\n                            state = .std_offset;\n                        },\n                    }\n                },\n                .std_offset => {\n                    const offset_start = i;\n                    while (i < str.len) : (i += 1) {\n                        switch (str[i]) {\n                            '+',\n                            '-',\n                            ':',\n                            '0',\n                            '1',\n                            '2',\n                            '3',\n                            '4',\n                            '5',\n                            '6',\n                            '7',\n                            '8',\n                            '9',\n                            => {\n                                if (i == str.len - 1)\n                                    std_offset = parseTime(str[offset_start..]);\n                            },\n                            else => {\n                                std_offset = parseTime(str[offset_start..i]);\n                                i -= 1;\n                                state = .dst;\n                                break;\n                            },\n                        }\n                    }\n                },\n                .dst => {\n                    switch (str[i]) {\n                        '<' => {\n                            // quoted. Consume until >\n                            const dst_start = i + 1;\n                            i = std.mem.indexOfScalarPos(u8, str, i, '>') orelse return error.InvalidPosix;\n                            dst = str[dst_start..i];\n                        },\n                        else => {\n                            const dst_start = i;\n                            i += 1;\n                            while (i < str.len) : (i += 1) {\n                                switch (str[i]) {\n                                    ',' => {\n                                        dst = str[dst_start..i];\n                                        state = .start;\n                                        break;\n                                    },\n                                    '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => {\n                                        dst = str[dst_start..i];\n                                        // backup one so this gets parsed as an offset\n                                        i -= 1;\n                                        state = .dst_offset;\n                                        break;\n                                    },\n                                    else => {\n                                        if (i == str.len - 1)\n                                            dst = str[dst_start..];\n                                    },\n                                }\n                            }\n                        },\n                    }\n                },\n                .dst_offset => {\n                    const offset_start = i;\n                    while (i < str.len) : (i += 1) {\n                        switch (str[i]) {\n                            '+',\n                            '-',\n                            ':',\n                            '0',\n                            '1',\n                            '2',\n                            '3',\n                            '4',\n                            '5',\n                            '6',\n                            '7',\n                            '8',\n                            '9',\n                            => {\n                                if (i == str.len - 1)\n                                    std_offset = parseTime(str[offset_start..]);\n                            },\n                            ',' => {\n                                dst_offset = parseTime(str[offset_start..i]);\n                                state = .start;\n                                break;\n                            },\n                            else => {},\n                        }\n                    }\n                },\n                .start => {\n                    const comma_idx = std.mem.indexOfScalarPos(u8, str, i, ',') orelse return error.InvalidPosix;\n                    if (std.mem.indexOfScalarPos(u8, str[0..comma_idx], i, '/')) |idx| {\n                        start = try DSTSpec.parse(str[i..idx]);\n                        switch (start.?) {\n                            .julian => |*j| j.time = parseTime(str[idx + 1 .. comma_idx]),\n                            .julian_leap => |*j| j.time = parseTime(str[idx + 1 .. comma_idx]),\n                            .mwd => |*m| m.time = parseTime(str[idx + 1 .. comma_idx]),\n                        }\n                    } else {\n                        start = try DSTSpec.parse(str[i..comma_idx]);\n                    }\n                    state = .end;\n                    i = comma_idx;\n                },\n                .end => {\n                    if (std.mem.indexOfScalarPos(u8, str, i, '/')) |idx| {\n                        end = try DSTSpec.parse(str[i..idx]);\n                        switch (end.?) {\n                            .julian => |*j| j.time = parseTime(str[idx + 1 ..]),\n                            .julian_leap => |*j| j.time = parseTime(str[idx + 1 ..]),\n                            .mwd => |*m| m.time = parseTime(str[idx + 1 ..]),\n                        }\n                    } else {\n                        end = try DSTSpec.parse(str[i..]);\n                    }\n                    break;\n                },\n            }\n        }\n        return .{\n            .std = std_,\n            .std_offset = std_offset,\n            .dst = dst,\n            .dst_offset = dst_offset,\n            .start = start,\n            .end = end,\n        };\n    }\n\n    fn parseTime(str: []const u8) Seconds {\n        const State = enum {\n            hour,\n            minute,\n            second,\n        };\n        var is_neg = false;\n        var state: State = .hour;\n        var offset_h: i64 = 0;\n        var offset_m: i64 = 0;\n        var offset_s: i64 = 0;\n        var i: usize = 0;\n        while (i < str.len) : (i += 1) {\n            switch (state) {\n                .hour => {\n                    switch (str[i]) {\n                        '-' => is_neg = true,\n                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => |d| {\n                            offset_h = offset_h * 10 + @as(i64, d - '0');\n                        },\n                        ':' => state = .minute,\n                        else => {},\n                    }\n                },\n                .minute => {\n                    switch (str[i]) {\n                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => |d| {\n                            offset_m = offset_m * 10 + @as(i64, d - '0');\n                        },\n                        ':' => state = .second,\n                        else => {},\n                    }\n                },\n                .second => {\n                    switch (str[i]) {\n                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => |d| {\n                            offset_s = offset_s * 10 + @as(i64, d - '0');\n                        },\n                        else => {},\n                    }\n                },\n            }\n        }\n        const offset = offset_h * s_per_hour + offset_m * s_per_min + offset_s;\n        return if (is_neg) -offset else offset;\n    }\n\n    /// reports true if the unix timestamp occurs when DST is in effect\n    fn isDST(self: Posix, timestamp: Seconds) bool {\n        const start = self.start orelse return false;\n        const end = self.end orelse return false;\n        const days_from_epoch: zeit.Days = @intCast(@divFloor(timestamp, s_per_day));\n        const civil = zeit.civilFromDays(days_from_epoch);\n        const civil_month = @intFromEnum(civil.month);\n\n        const start_s: Seconds = switch (start) {\n            .julian => |rule| blk: {\n                const days = days_from_epoch - civil.month.daysBefore(civil.year) - civil.day + rule.day + 1;\n                var s = (@as(i64, days - 1)) * s_per_day + rule.time;\n                if (zeit.isLeapYear(civil.year) and rule.day >= 60) {\n                    s += s_per_day;\n                }\n                break :blk s + self.std_offset;\n            },\n            .julian_leap => |rule| blk: {\n                const days = days_from_epoch - civil.month.daysBefore(civil.year) - civil.day + rule.day;\n                break :blk @as(i64, days) * s_per_day + rule.time + self.std_offset;\n            },\n            .mwd => |rule| blk: {\n                const rule_month = @intFromEnum(rule.month);\n                if (civil_month < rule_month) return false;\n                // bail early if we are greater than this month. we know we only\n                // rely on the end time. We yield a value that is before the\n                // timestamp\n                if (civil_month > rule_month) break :blk timestamp - 1;\n                // we are in the same month\n                // first_of_month is the weekday on the first of the month\n                const first_of_month = zeit.weekdayFromDays(days_from_epoch - civil.day + 1);\n                // days is the first \"rule day\" of the month (ie the first\n                // Sunday of the month)\n                var days: u9 = first_of_month.daysUntil(rule.day) + 1;\n                var i: usize = 1;\n                while (i < rule.week) : (i += 1) {\n                    if (days + 7 >= rule.month.lastDay(civil.year)) break;\n                    days += 7;\n                }\n                // days_from_epoch is the number of days to the DST day from the\n                // epoch\n                const dst_days_from_epoch: i64 = days_from_epoch - civil.day + days;\n\n                break :blk @as(i64, dst_days_from_epoch) * s_per_day + rule.time + self.std_offset;\n            },\n        };\n\n        const end_s: Seconds = switch (end) {\n            .julian => |rule| blk: {\n                const days = days_from_epoch - civil.month.daysBefore(civil.year) - civil.day + rule.day + 1;\n                var s = (@as(i64, days) - 1) * s_per_day + rule.time;\n                if (zeit.isLeapYear(civil.year) and rule.day >= 60) {\n                    s += s_per_day;\n                }\n                break :blk s + self.std_offset;\n            },\n            .julian_leap => |rule| blk: {\n                const days = days_from_epoch - civil.month.daysBefore(civil.year) - civil.day + rule.day + 1;\n                break :blk @as(i64, days) * s_per_day + rule.time + self.std_offset;\n            },\n            .mwd => |rule| blk: {\n                const rule_month = @intFromEnum(rule.month);\n                if (civil_month > rule_month) return false;\n                // bail early if we are less than this month. we know we only\n                // rely on the start time. We yield a value that is after the\n                // timestamp\n                if (civil_month < rule_month) break :blk timestamp + 1;\n                // first_of_month is the weekday on the first of the month\n                const first_of_month = zeit.weekdayFromDays(days_from_epoch - civil.day + 1);\n                // days is the first \"rule day\" of the month (ie the first\n                // Sunday of the month)\n                var days: u9 = first_of_month.daysUntil(rule.day) + 1;\n                var i: usize = 1;\n                while (i < rule.week) : (i += 1) {\n                    if (days + 7 >= rule.month.lastDay(civil.year)) break;\n                    days += 7;\n                }\n                // days_from_epoch is the number of days to the DST day from the\n                // epoch\n                const dst_days_from_epoch: i64 = days_from_epoch - civil.day + days;\n\n                break :blk @as(i64, dst_days_from_epoch) * s_per_day + rule.time + self.std_offset;\n            },\n        };\n\n        return timestamp >= start_s and timestamp < end_s;\n    }\n\n    pub fn adjust(self: Posix, timestamp: Seconds) AdjustedTime {\n        if (self.isDST(timestamp)) {\n            return .{\n                .designation = self.dst orelse self.std,\n                .timestamp = timestamp - (self.dst_offset orelse self.std_offset - s_per_hour),\n                .is_dst = true,\n            };\n        }\n        return .{\n            .designation = self.std,\n            .timestamp = timestamp - self.std_offset,\n            .is_dst = false,\n        };\n    }\n};\n\npub const TZInfo = struct {\n    allocator: std.mem.Allocator,\n    transitions: []const Transition,\n    timetypes: []const Timetype,\n    leapseconds: []const Leapsecond,\n    footer: ?[]const u8,\n    posix_tz: ?Posix,\n\n    const Leapsecond = struct {\n        occurrence: i48,\n        correction: i16,\n    };\n\n    const Timetype = struct {\n        offset: i32,\n        flags: u8,\n        name_data: [6:0]u8,\n\n        pub fn name(self: *const Timetype) [:0]const u8 {\n            return std.mem.sliceTo(self.name_data[0..], 0);\n        }\n\n        pub fn isDst(self: Timetype) bool {\n            return (self.flags & 0x01) > 0;\n        }\n\n        pub fn standardTimeIndicator(self: Timetype) bool {\n            return (self.flags & 0x02) > 0;\n        }\n\n        pub fn utIndicator(self: Timetype) bool {\n            return (self.flags & 0x04) > 0;\n        }\n    };\n\n    const Transition = struct {\n        ts: Seconds,\n        timetype: *Timetype,\n    };\n\n    const Header = extern struct {\n        magic: [4]u8,\n        version: u8,\n        reserved: [15]u8,\n        counts: extern struct {\n            isutcnt: u32,\n            isstdcnt: u32,\n            leapcnt: u32,\n            timecnt: u32,\n            typecnt: u32,\n            charcnt: u32,\n        },\n    };\n\n    pub fn parse(allocator: std.mem.Allocator, reader: *std.Io.Reader) !TZInfo {\n        var legacy_header = try reader.takeStruct(Header, .big); // handles endianness for us\n        if (!std.mem.eql(u8, &legacy_header.magic, \"TZif\")) return error.BadHeader;\n        if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3') return error.BadVersion;\n\n        if (legacy_header.version == 0) {\n            return parseBlock(allocator, reader, legacy_header, true);\n        } else {\n            // If the format is modern, just skip over the legacy data\n            const skipv = legacy_header.counts.timecnt * 5 + legacy_header.counts.typecnt * 6 + legacy_header.counts.charcnt + legacy_header.counts.leapcnt * 8 + legacy_header.counts.isstdcnt + legacy_header.counts.isutcnt;\n\n            const skipped = try reader.discard(.limited(skipv));\n            // this should be unreachable, as discard above handles EndOfStream and ReadFailed:\n            if (skipped != skipv) return error.BadHeader;\n\n            var header = try reader.takeStruct(Header, .big); // handles endianness for us\n            if (!std.mem.eql(u8, &header.magic, \"TZif\")) return error.BadHeader;\n            if (header.version != '2' and header.version != '3') return error.BadVersion;\n\n            return parseBlock(allocator, reader, header, false);\n        }\n    }\n\n    fn parseBlock(allocator: std.mem.Allocator, reader: *std.Io.Reader, header: Header, legacy: bool) !TZInfo {\n        if (header.counts.isstdcnt != 0 and header.counts.isstdcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isstdcnt [...] MUST either be zero or equal to \"typecnt\"\n        if (header.counts.isutcnt != 0 and header.counts.isutcnt != header.counts.typecnt) return error.Malformed; // rfc8536: isutcnt [...] MUST either be zero or equal to \"typecnt\"\n        if (header.counts.typecnt == 0) return error.Malformed; // rfc8536: typecnt [...] MUST NOT be zero\n        if (header.counts.charcnt == 0) return error.Malformed; // rfc8536: charcnt [...] MUST NOT be zero\n        if (header.counts.charcnt > 256 + 6) return error.Malformed; // Not explicitly banned by rfc8536 but nonsensical\n\n        var leapseconds = try allocator.alloc(Leapsecond, header.counts.leapcnt);\n        errdefer allocator.free(leapseconds);\n        var transitions = try allocator.alloc(Transition, header.counts.timecnt);\n        errdefer allocator.free(transitions);\n        var timetypes = try allocator.alloc(Timetype, header.counts.typecnt);\n        errdefer allocator.free(timetypes);\n\n        // Parse transition types\n        var i: usize = 0;\n        while (i < header.counts.timecnt) : (i += 1) {\n            transitions[i].ts = if (legacy) try reader.takeInt(i32, .big) else try reader.takeInt(i64, .big);\n        }\n\n        i = 0;\n        while (i < header.counts.timecnt) : (i += 1) {\n            const tt = try reader.takeByte();\n            if (tt >= timetypes.len) return error.Malformed; // rfc8536: Each type index MUST be in the range [0, \"typecnt\" - 1]\n            transitions[i].timetype = &timetypes[tt];\n        }\n\n        // Parse time types\n        i = 0;\n        while (i < header.counts.typecnt) : (i += 1) {\n            const offset = try reader.takeInt(i32, .big);\n            if (offset < -2147483648) return error.Malformed; // rfc8536: utoff [...] MUST NOT be -2**31\n            const dst = try reader.takeByte();\n            if (dst != 0 and dst != 1) return error.Malformed; // rfc8536: (is)dst [...] The value MUST be 0 or 1.\n            const idx = try reader.takeByte();\n            if (idx > header.counts.charcnt - 1) return error.Malformed; // rfc8536: (desig)idx [...] Each index MUST be in the range [0, \"charcnt\" - 1]\n            timetypes[i] = .{\n                .offset = offset,\n                .flags = dst,\n                .name_data = undefined,\n            };\n\n            // Temporarily cache idx in name_data to be processed after we've read the designator names below\n            timetypes[i].name_data[0] = idx;\n        }\n\n        var designators_data: [256 + 6]u8 = undefined;\n        try reader.readSliceAll(designators_data[0..header.counts.charcnt]);\n        const designators = designators_data[0..header.counts.charcnt];\n        if (designators[designators.len - 1] != 0) return error.Malformed; // rfc8536: charcnt [...] includes the trailing NUL (0x00) octet\n\n        // Iterate through the timetypes again, setting the designator names\n        for (timetypes) |*tt| {\n            const name = std.mem.sliceTo(designators[tt.name_data[0]..], 0);\n            // We are mandating the \"SHOULD\" 6-character limit so we can pack the struct better, and to conform to POSIX.\n            if (name.len > 6) return error.Malformed; // rfc8536: Time zone designations SHOULD consist of at least three (3) and no more than six (6) ASCII characters.\n            @memcpy(tt.name_data[0..name.len], name);\n            tt.name_data[name.len] = 0;\n        }\n\n        // Parse leap seconds\n        i = 0;\n        while (i < header.counts.leapcnt) : (i += 1) {\n            const occur: i64 = if (legacy) try reader.takeInt(i32, .big) else try reader.takeInt(i64, .big);\n            if (occur < 0) return error.Malformed; // rfc8536: occur [...] MUST be nonnegative\n            if (i > 0 and leapseconds[i - 1].occurrence + 2419199 > occur) return error.Malformed; // rfc8536: occur [...] each later value MUST be at least 2419199 greater than the previous value\n            if (occur > std.math.maxInt(i48)) return error.Malformed; // Unreasonably far into the future\n\n            const corr = try reader.takeInt(i32, .big);\n            if (i == 0 and corr != -1 and corr != 1) return error.Malformed; // rfc8536: The correction value in the first leap-second record, if present, MUST be either one (1) or minus one (-1)\n            if (i > 0 and leapseconds[i - 1].correction != corr + 1 and leapseconds[i - 1].correction != corr - 1) return error.Malformed; // rfc8536: The correction values in adjacent leap-second records MUST differ by exactly one (1)\n            if (corr > std.math.maxInt(i16)) return error.Malformed; // Unreasonably large correction\n\n            leapseconds[i] = .{\n                .occurrence = @as(i48, @intCast(occur)),\n                .correction = @as(i16, @intCast(corr)),\n            };\n        }\n\n        // Parse standard/wall indicators\n        i = 0;\n        while (i < header.counts.isstdcnt) : (i += 1) {\n            const stdtime = try reader.takeByte();\n            if (stdtime == 1) {\n                timetypes[i].flags |= 0x02;\n            }\n        }\n\n        // Parse UT/local indicators\n        i = 0;\n        while (i < header.counts.isutcnt) : (i += 1) {\n            const ut = try reader.takeByte();\n            if (ut == 1) {\n                timetypes[i].flags |= 0x04;\n                if (!timetypes[i].standardTimeIndicator()) return error.Malformed; // rfc8536: standard/wall value MUST be one (1) if the UT/local value is one (1)\n            }\n        }\n\n        // Footer\n        var footer: ?[]const u8 = null;\n        var posix: ?Posix = null;\n        if (!legacy) {\n            if ((try reader.takeByte()) != '\\n') return error.Malformed; // An rfc8536 footer must start with a newline\n            const footer_mem = reader.takeDelimiterExclusive('\\n') catch |err| switch (err) {\n                error.StreamTooLong => return error.OverlargeFooter, // Read more than reader buffer bytes, much larger than any reasonable POSIX TZ string\n                else => return err,\n            };\n            if (footer_mem.len != 0) {\n                footer = try allocator.dupe(u8, footer_mem);\n                posix = try Posix.parse(footer.?);\n            }\n        }\n        errdefer if (footer) |ft| allocator.free(ft);\n\n        return .{\n            .allocator = allocator,\n            .transitions = transitions,\n            .timetypes = timetypes,\n            .leapseconds = leapseconds,\n            .footer = footer,\n            .posix_tz = posix,\n        };\n    }\n\n    pub fn deinit(self: TZInfo) void {\n        if (self.footer) |footer| {\n            self.allocator.free(footer);\n        }\n        self.allocator.free(self.leapseconds);\n        self.allocator.free(self.transitions);\n        self.allocator.free(self.timetypes);\n    }\n\n    /// adjust a unix timestamp to the timezone\n    pub fn adjust(self: TZInfo, timestamp: Seconds) AdjustedTime {\n        // if we are past the last transition and have a footer, we use the\n        // footer data\n        if ((self.transitions.len == 0 or self.transitions[self.transitions.len - 1].ts <= timestamp) and\n            self.posix_tz != null)\n        {\n            const posix = self.posix_tz.?;\n            return posix.adjust(timestamp);\n        }\n\n        const transition: Transition = blk: for (self.transitions, 0..) |transition, i| {\n            // TODO: implement what go does, which is a copy of c for how to\n            // handle times before the first transition how to handle this\n            if (i == 0 and transition.ts > timestamp) @panic(\"unimplemented. please complain to tim\");\n            if (transition.ts <= timestamp) continue;\n            // we use the latest transition before ts, which is one less than\n            // our current iter\n            break :blk self.transitions[i - 1];\n        } else self.transitions[self.transitions.len - 1];\n        return .{\n            .designation = transition.timetype.name(),\n            .timestamp = timestamp + transition.timetype.offset,\n            .is_dst = transition.timetype.isDst(),\n        };\n    }\n};\n\npub const Windows = struct {\n    const windows = struct {\n        const BOOL = std.os.windows.BOOL;\n        const BOOLEAN = std.os.windows.BOOLEAN;\n        const DWORD = std.os.windows.DWORD;\n        const FILETIME = std.os.windows.FILETIME;\n        const LONG = std.os.windows.LONG;\n        const USHORT = std.os.windows.USHORT;\n        const WCHAR = std.os.windows.WCHAR;\n        const WORD = std.os.windows.WORD;\n\n        const epoch = std.time.epoch.windows;\n        const ERROR_SUCCESS = 0x00;\n        const ERROR_NO_MORE_ITEMS = 0x103;\n        pub const TIME_ZONE_ID_INVALID = @as(DWORD, std.math.maxInt(DWORD));\n\n        const DYNAMIC_TIME_ZONE_INFORMATION = extern struct {\n            Bias: LONG,\n            StandardName: [32]WCHAR,\n            StandardDate: SYSTEMTIME,\n            StandardBias: LONG,\n            DaylightName: [32]WCHAR,\n            DaylightDate: SYSTEMTIME,\n            DaylightBias: LONG,\n            TimeZoneKeyName: [128]WCHAR,\n            DynamicDaylightTimeDisabled: BOOLEAN,\n        };\n\n        const SYSTEMTIME = extern struct {\n            wYear: WORD,\n            wMonth: WORD,\n            wDayOfWeek: WORD,\n            wDay: WORD,\n            wHour: WORD,\n            wMinute: WORD,\n            wSecond: WORD,\n            wMilliseconds: WORD,\n        };\n\n        const TIME_ZONE_INFORMATION = extern struct {\n            Bias: LONG,\n            StandardName: [32]WCHAR,\n            StandardDate: SYSTEMTIME,\n            StandardBias: LONG,\n            DaylightName: [32]WCHAR,\n            DaylightDate: SYSTEMTIME,\n            DaylightBias: LONG,\n        };\n\n        pub extern \"advapi32\" fn EnumDynamicTimeZoneInformation(dwIndex: DWORD, lpTimeZoneInformation: *DYNAMIC_TIME_ZONE_INFORMATION) callconv(.winapi) DWORD;\n        pub extern \"kernel32\" fn GetDynamicTimeZoneInformation(pTimeZoneInformation: *DYNAMIC_TIME_ZONE_INFORMATION) callconv(.winapi) DWORD;\n        pub extern \"kernel32\" fn GetTimeZoneInformationForYear(wYear: USHORT, pdtzi: ?*const DYNAMIC_TIME_ZONE_INFORMATION, ptzi: *TIME_ZONE_INFORMATION) callconv(.winapi) BOOL;\n        pub extern \"kernel32\" fn SystemTimeToTzSpecificLocalTimeEx(lpTimeZoneInfo: ?*const DYNAMIC_TIME_ZONE_INFORMATION, lpUniversalTime: *const SYSTEMTIME, lpLocalTime: *SYSTEMTIME) callconv(.winapi) BOOL;\n    };\n\n    zoneinfo: windows.DYNAMIC_TIME_ZONE_INFORMATION,\n    allocator: std.mem.Allocator,\n    standard_name: []const u8,\n    dst_name: []const u8,\n\n    /// retrieves the local timezone settings for this machine\n    pub fn local(allocator: std.mem.Allocator) !Windows {\n        var info: windows.DYNAMIC_TIME_ZONE_INFORMATION = undefined;\n        const result = windows.GetDynamicTimeZoneInformation(&info);\n        if (result == windows.TIME_ZONE_ID_INVALID) return error.TimeZoneIdInvalid;\n        const std_idx = std.mem.indexOfScalar(u16, &info.StandardName, 0x00) orelse info.StandardName.len;\n        const dst_idx = std.mem.indexOfScalar(u16, &info.DaylightName, 0x00) orelse info.DaylightName.len;\n        const standard_name = try std.unicode.utf16LeToUtf8Alloc(allocator, info.StandardName[0..std_idx]);\n        const dst_name = try std.unicode.utf16LeToUtf8Alloc(allocator, info.DaylightName[0..dst_idx]);\n        return .{\n            .zoneinfo = info,\n            .allocator = allocator,\n            .standard_name = standard_name,\n            .dst_name = dst_name,\n        };\n    }\n\n    pub fn deinit(self: Windows) void {\n        self.allocator.free(self.standard_name);\n        self.allocator.free(self.dst_name);\n    }\n\n    /// Adjusts the time to the timezone\n    /// 1. Convert timestamp to windows.SYSTEMTIME using internal methods\n    /// 2. Convert SYSTEMTIME to target timezone using windows api\n    /// 3. Get the relevant TIME_ZONE_INFORMATION for the year\n    /// 4. Determine if we are in DST or not\n    /// 5. Return result\n    pub fn adjust(self: Windows, timestamp: Seconds) AdjustedTime {\n        const instant = zeit.instant(.{ .unix_timestamp = timestamp }, &zeit.utc);\n        const time = instant.time();\n\n        const systemtime: windows.SYSTEMTIME = .{\n            .wYear = @intCast(time.year),\n            .wMonth = @intFromEnum(time.month),\n            .wDayOfWeek = 0, // not used in calculation\n            .wDay = time.day,\n            .wHour = time.hour,\n            .wMinute = time.minute,\n            .wSecond = time.second,\n            .wMilliseconds = time.millisecond,\n        };\n\n        var localtime: windows.SYSTEMTIME = undefined;\n        if (windows.SystemTimeToTzSpecificLocalTimeEx(&self.zoneinfo, &systemtime, &localtime) == .FALSE) {\n            const err = std.os.windows.GetLastError();\n            std.log.err(\"{}\", .{err});\n            @panic(\"TODO\");\n        }\n        var tzi: windows.TIME_ZONE_INFORMATION = undefined;\n        if (windows.GetTimeZoneInformationForYear(localtime.wYear, &self.zoneinfo, &tzi) == .FALSE) {\n            const err = std.os.windows.GetLastError();\n            std.log.err(\"{}\", .{err});\n            @panic(\"TODO\");\n        }\n        const is_dst = isDST(timestamp, &tzi, &localtime);\n        return .{\n            .designation = if (is_dst) self.dst_name else self.standard_name,\n            .timestamp = systemtimeToUnixTimestamp(localtime),\n            .is_dst = is_dst,\n        };\n    }\n\n    fn systemtimeToUnixTimestamp(sys: windows.SYSTEMTIME) Seconds {\n        const lzt = systemtimetoZeitTime(sys);\n        return lzt.instant().unixTimestamp();\n    }\n\n    fn systemtimetoZeitTime(sys: windows.SYSTEMTIME) zeit.Time {\n        return .{\n            .year = sys.wYear,\n            .month = @enumFromInt(sys.wMonth),\n            .day = @intCast(sys.wDay),\n            .hour = @intCast(sys.wHour),\n            .minute = @intCast(sys.wMinute),\n            .second = @intCast(sys.wSecond),\n            .millisecond = @intCast(sys.wMilliseconds),\n        };\n    }\n\n    fn isDST(timestamp: Seconds, tzi: *const windows.TIME_ZONE_INFORMATION, time: *const windows.SYSTEMTIME) bool {\n        // If wMonth on StandardDate is 0, the timezone doesn't have DST\n        if (tzi.StandardDate.wMonth == 0) return false;\n        const start = tzi.DaylightDate;\n        const end = tzi.StandardDate;\n\n        // Before DST starts\n        if (time.wMonth < start.wMonth) return false;\n        // After DST ends\n        if (time.wMonth > end.wMonth) return false;\n        // In the months between\n        if (time.wMonth > start.wMonth and time.wMonth < end.wMonth) return true;\n\n        const days_from_epoch: zeit.Days = @intCast(@divFloor(timestamp, s_per_day));\n        // first_of_month is the weekday on the first of the month\n        const first_of_month = zeit.weekdayFromDays(\n            days_from_epoch - @as(zeit.Days, @intCast(time.wDay)) + 1,\n        );\n\n        // In the start transition month\n        if (time.wMonth == start.wMonth) {\n            // days is the first \"rule day\" of the month (ie the first\n            // Sunday of the month)\n            var days: u9 = first_of_month.daysUntil(@enumFromInt(start.wDayOfWeek)) + 1;\n            var i: usize = 1;\n            while (i < start.wDay) : (i += 1) {\n                const month: zeit.Month = @enumFromInt(start.wMonth);\n                if (days + 7 >= month.lastDay(time.wYear)) break;\n                days += 7;\n            }\n            if (time.wDay == days) {\n                if (time.wHour == start.wHour) {\n                    return time.wMinute >= start.wMinute;\n                }\n                return time.wHour >= start.wHour;\n            }\n            return time.wDay >= days;\n        }\n        // In the end transition month\n        if (time.wMonth == end.wMonth) {\n            // days is the first \"rule day\" of the month (ie the first\n            // Sunday of the month)\n            var days: u9 = first_of_month.daysUntil(@enumFromInt(end.wDayOfWeek)) + 1;\n            var i: usize = 1;\n            while (i < end.wDay) : (i += 1) {\n                const month: zeit.Month = @enumFromInt(end.wMonth);\n                if (days + 7 >= month.lastDay(time.wYear)) break;\n                days += 7;\n            }\n            if (time.wDay == days) {\n                if (time.wHour == end.wHour) {\n                    return time.wMinute < end.wMinute;\n                }\n                return time.wHour < end.wHour;\n            }\n            return time.wDay < days;\n        }\n        return false;\n    }\n\n    pub fn loadFromName(allocator: std.mem.Allocator, name: []const u8) !Windows {\n        var buf: [128]u16 = undefined;\n        const n = try std.unicode.utf8ToUtf16Le(&buf, name);\n        const target = buf[0..n];\n\n        var result: windows.DWORD = windows.ERROR_SUCCESS;\n        var i: windows.DWORD = 0;\n        var dtzi: windows.DYNAMIC_TIME_ZONE_INFORMATION = undefined;\n        while (result == windows.ERROR_SUCCESS) : (i += 1) {\n            result = windows.EnumDynamicTimeZoneInformation(i, &dtzi);\n            const name_idx = std.mem.indexOfScalar(u16, &dtzi.TimeZoneKeyName, 0x00) orelse dtzi.TimeZoneKeyName.len;\n            if (std.mem.eql(u16, target, dtzi.TimeZoneKeyName[0..name_idx])) break;\n        } else return error.TimezoneNotFound;\n\n        const std_idx = std.mem.indexOfScalar(u16, &dtzi.StandardName, 0x00) orelse dtzi.StandardName.len;\n        const dst_idx = std.mem.indexOfScalar(u16, &dtzi.DaylightName, 0x00) orelse dtzi.DaylightName.len;\n        const standard_name = try std.unicode.utf16LeToUtf8Alloc(allocator, dtzi.StandardName[0..std_idx]);\n        const dst_name = try std.unicode.utf16LeToUtf8Alloc(allocator, dtzi.DaylightName[0..dst_idx]);\n        return .{\n            .zoneinfo = dtzi,\n            .allocator = allocator,\n            .standard_name = standard_name,\n            .dst_name = dst_name,\n        };\n    }\n};\n\ntest \"timezone.zig: test Fixed\" {\n    const fixed: Fixed = .{\n        .name = \"test\",\n        .offset = -600,\n        .is_dst = false,\n    };\n    const adjusted = fixed.adjust(0);\n    try std.testing.expectEqual(-600, adjusted.timestamp);\n}\n\ntest \"timezone.zig: Posix.isDST\" {\n    const t = try Posix.parse(\"CST6CDT,M3.2.0,M11.1.0\");\n    try std.testing.expectEqual(false, t.isDST(1704088800)); // Jan 1 2024 00:00:00 CST\n    try std.testing.expectEqual(false, t.isDST(1733032800)); // Dec 1 2024 00:00:00 CST\n    try std.testing.expectEqual(true, t.isDST(1717218000)); // Jun 1 2024 00:00:00 CST\n    // One second after DST starts\n    try std.testing.expectEqual(true, t.isDST(1710057601));\n    // One second before DST starts\n    try std.testing.expectEqual(false, t.isDST(1710057599));\n    // One second before DST ends\n    try std.testing.expectEqual(true, t.isDST(1730620799));\n    // One second after DST ends\n    try std.testing.expectEqual(false, t.isDST(1730620801));\n\n    const j = try Posix.parse(\"CST6CDT,J1,J4\");\n    try std.testing.expectEqual(true, j.isDST(1704268800));\n}\n\ntest \"timezone.zig: Posix.parseTime\" {\n    try std.testing.expectEqual(0, Posix.parseTime(\"00:00:00\"));\n    try std.testing.expectEqual(-3600, Posix.parseTime(\"-1\"));\n    try std.testing.expectEqual(-7200, Posix.parseTime(\"-02:00:00\"));\n    try std.testing.expectEqual(3660, Posix.parseTime(\"+1:01\"));\n}\n\ntest \"timezone.zig: Posix.parse\" {\n    {\n        const t = try Posix.parse(\"<UTC>-1\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(-3600, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"<UTC>1\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"<UTC>+1\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"UTC+1\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"UTC+1:01\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(3660, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"UTC-1:01:01\");\n        try std.testing.expectEqualStrings(\"UTC\", t.std);\n        try std.testing.expectEqual(-3661, t.std_offset);\n    }\n    {\n        const t = try Posix.parse(\"CST1CDT\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n    }\n    {\n        const t = try Posix.parse(\"CST1<CDT>\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n    }\n    {\n        const t = try Posix.parse(\"CST1CDT,J100,J200\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n        try std.testing.expectEqual(100, t.start.?.julian.day);\n        try std.testing.expectEqual(200, t.end.?.julian.day);\n    }\n    {\n        const t = try Posix.parse(\"CST1CDT,100,200\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n        try std.testing.expectEqual(100, t.start.?.julian_leap.day);\n        try std.testing.expectEqual(200, t.end.?.julian_leap.day);\n    }\n    {\n        const t = try Posix.parse(\"CST1CDT,M3.5.1,M11.3.0\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n        try std.testing.expectEqual(.mar, t.start.?.mwd.month);\n        try std.testing.expectEqual(5, t.start.?.mwd.week);\n        try std.testing.expectEqual(.mon, t.start.?.mwd.day);\n        try std.testing.expectEqual(.nov, t.end.?.mwd.month);\n        try std.testing.expectEqual(3, t.end.?.mwd.week);\n        try std.testing.expectEqual(.sun, t.end.?.mwd.day);\n    }\n    {\n        const t = try Posix.parse(\"CST1CDT,M3.5.1/02:00:00,M11.3.0/1\");\n        try std.testing.expectEqualStrings(\"CST\", t.std);\n        try std.testing.expectEqual(3600, t.std_offset);\n        try std.testing.expectEqualStrings(\"CDT\", t.dst.?);\n        try std.testing.expectEqual(.mar, t.start.?.mwd.month);\n        try std.testing.expectEqual(5, t.start.?.mwd.week);\n        try std.testing.expectEqual(.mon, t.start.?.mwd.day);\n        try std.testing.expectEqual(7200, t.start.?.mwd.time);\n        try std.testing.expectEqual(.nov, t.end.?.mwd.month);\n        try std.testing.expectEqual(3, t.end.?.mwd.week);\n        try std.testing.expectEqual(.sun, t.end.?.mwd.day);\n        try std.testing.expectEqual(3600, t.end.?.mwd.time);\n    }\n}\n\ntest \"timezone.zig: Posix.adjust\" {\n    {\n        const t = try Posix.parse(\"UTC+1\");\n        const adjusted = t.adjust(0);\n        try std.testing.expectEqual(-3600, adjusted.timestamp);\n    }\n\n    {\n        const t = try Posix.parse(\"CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00\");\n        const adjusted = t.adjust(1704088800);\n        try std.testing.expectEqual(1704067200, adjusted.timestamp);\n        try std.testing.expectEqualStrings(\"CST\", adjusted.designation);\n\n        const adjusted_dst = t.adjust(1710057600);\n        try std.testing.expectEqual(1710039600, adjusted_dst.timestamp);\n        try std.testing.expectEqualStrings(\"CDT\", adjusted_dst.designation);\n    }\n}\n\ntest \"timezone.zig: Posix.DSTSpec.parse\" {\n    {\n        const spec = try Posix.DSTSpec.parse(\"J365\");\n        try std.testing.expectEqual(365, spec.julian.day);\n    }\n    {\n        const spec = try Posix.DSTSpec.parse(\"365\");\n        try std.testing.expectEqual(365, spec.julian_leap.day);\n    }\n    {\n        const spec = try Posix.DSTSpec.parse(\"M3.5.1\");\n        try std.testing.expectEqual(.mar, spec.mwd.month);\n        try std.testing.expectEqual(5, spec.mwd.week);\n        try std.testing.expectEqual(.mon, spec.mwd.day);\n    }\n    {\n        const spec = try Posix.DSTSpec.parse(\"M11.3.0\");\n        try std.testing.expectEqual(.nov, spec.mwd.month);\n        try std.testing.expectEqual(3, spec.mwd.week);\n        try std.testing.expectEqual(.sun, spec.mwd.day);\n    }\n}\n"
  },
  {
    "path": "src/zeit.zig",
    "content": "const std = @import(\"std\");\nconst builtin = @import(\"builtin\");\nconst location = @import(\"location.zig\");\npub const timezone = @import(\"timezone.zig\");\n\nconst assert = std.debug.assert;\n\npub const TimeZone = timezone.TimeZone;\npub const Location = location.Location;\n\npub const Days = i32;\npub const Nanoseconds = i128;\npub const Milliseconds = i128;\npub const Seconds = i64;\n\npub const EnvConfig = struct {\n    tz: ?[]const u8 = null,\n    tzdir: ?[]const u8 = null,\n};\n\nconst ns_per_us = std.time.ns_per_us;\nconst ns_per_ms = std.time.ns_per_ms;\nconst ns_per_s = std.time.ns_per_s;\nconst ns_per_min = std.time.ns_per_min;\nconst ns_per_hour = std.time.ns_per_hour;\nconst ns_per_day = std.time.ns_per_day;\nconst s_per_min = std.time.s_per_min;\nconst s_per_hour = std.time.s_per_hour;\nconst s_per_day = std.time.s_per_day;\nconst days_per_era = 365 * 400 + 97;\n\npub const utc: TimeZone = .{ .fixed = .{\n    .name = \"UTC\",\n    .offset = 0,\n    .is_dst = false,\n} };\n\npub fn local(alloc: std.mem.Allocator, io: std.Io, env: EnvConfig) !TimeZone {\n    switch (builtin.os.tag) {\n        .windows => {\n            const win = try timezone.Windows.local(alloc);\n            return .{ .windows = win };\n        },\n        else => {\n            if (env.tz) |tz| {\n                return localFromEnv(alloc, io, tz, env);\n            }\n\n            const f = try std.Io.Dir.cwd().openFile(io, \"/etc/localtime\", .{});\n            defer f.close(io);\n            var io_buffer: [2048]u8 = undefined;\n            var reader = f.reader(io, &io_buffer);\n            return .{ .tzinfo = try timezone.TZInfo.parse(alloc, &reader.interface) };\n        },\n    }\n}\n\n// Returns the local time zone from the given TZ environment variable\n// TZ can be one of three things:\n// 1. A POSIX TZ string (TZ=CST6CDT,M3.2.0,M11.1.0)\n// 2. An absolute path, prefixed with ':' (TZ=:/etc/localtime)\n// 3. A relative path, prefixed with ':'\nfn localFromEnv(\n    alloc: std.mem.Allocator,\n    io: std.Io,\n    tz: []const u8,\n    env: EnvConfig,\n) !TimeZone {\n    assert(tz.len != 0); // TZ is empty string\n\n    // Return early we we are a posix TZ string\n    if (tz[0] != ':') return .{ .posix = try timezone.Posix.parse(tz) };\n\n    assert(tz.len > 1); // TZ not long enough\n    if (tz[1] == '/') {\n        const f = try std.Io.Dir.cwd().openFile(io, tz[1..], .{});\n        defer f.close(io);\n        var io_buffer: [1024]u8 = undefined;\n        var reader = f.reader(io, &io_buffer);\n        return .{ .tzinfo = try timezone.TZInfo.parse(alloc, &reader.interface) };\n    }\n\n    if (std.meta.stringToEnum(Location, tz[1..])) |loc|\n        return loadTimeZone(alloc, io, loc, env)\n    else\n        return error.UnknownLocation;\n}\n\npub fn loadTimeZone(\n    alloc: std.mem.Allocator,\n    io: std.Io,\n    loc: Location,\n    env: EnvConfig,\n) !TimeZone {\n    switch (builtin.os.tag) {\n        .windows => {\n            const tz = try timezone.Windows.loadFromName(alloc, loc.asText());\n            return .{ .windows = tz };\n        },\n        else => {},\n    }\n\n    var dir: std.Io.Dir = blk: {\n        // If we have an env and a TZDIR, use that\n        if (env.tzdir) |tzdir| {\n            const d = try std.Io.Dir.cwd().openDir(io, tzdir, .{});\n            break :blk d;\n        }\n        // Otherwise check well-known locations\n        const zone_dirs = [_][]const u8{\n            \"/usr/share/zoneinfo/\",\n            \"/usr/share/lib/zoneinfo/\",\n            \"/usr/lib/locale/TZ/\",\n            \"/share/zoneinfo/\",\n            \"/etc/zoneinfo/\",\n        };\n        for (zone_dirs) |zone_dir| {\n            const d = std.Io.Dir.cwd().openDir(io, zone_dir, .{}) catch continue;\n            break :blk d;\n        } else return error.FileNotFound;\n    };\n\n    defer dir.close(io);\n    const f = try dir.openFile(io, loc.asText(), .{});\n    defer f.close(io);\n    var io_buffer: [2048]u8 = undefined;\n    var reader = f.reader(io, &io_buffer);\n    return .{ .tzinfo = try timezone.TZInfo.parse(alloc, &reader.interface) };\n}\n\n/// An Instant in time. Instants occur at a precise time and place, thus must\n/// always carry with them a timezone.\npub const Instant = struct {\n    /// the instant of time, in nanoseconds\n    timestamp: Nanoseconds = 0,\n    /// every instant occurs in a timezone. This is the timezone\n    timezone: *const TimeZone,\n\n    /// possible sources to create an Instant\n    pub const Source = union(enum) {\n        /// current wall clock determined using std.Io\n        now: std.Io,\n\n        /// a specific unix timestamp (in seconds)\n        unix_timestamp: Seconds,\n\n        /// a specific unix timestamp (in nanoseconds)\n        unix_nano: Nanoseconds,\n\n        /// create an Instant from a calendar date and time\n        time: Time,\n    };\n\n    /// text time format for parsing\n    pub const TextFormat = enum {\n        /// parse a datetime from an ISO8601 string\n        /// Supports most ISO8601 formats, _except_:\n        /// - Week numbers (ie YYYY-Www)\n        /// - Fractional minutes (ie YYYY-MM-DDTHH:MM.mmm)\n        ///\n        /// Strings can be in the extended or compact format and use ' ' or \"T\"\n        /// as the time delimiter\n        /// Examples of paresable strings:\n        /// YYYY-MM-DD\n        /// YYYY-MM-DDTHH\n        /// YYYY-MM-DDTHH:MM\n        /// YYYY-MM-DDTHH:MM:SS\n        /// YYYY-MM-DDTHH:MM:SS.sss\n        /// YYYY-MM-DDTHH:MM:SS.ssssss\n        /// YYYY-MM-DDTHH:MM:SSZ\n        /// YYYY-MM-DDTHH:MM:SS+hh:mm\n        /// YYYYMMDDTHHMMSSZ\n        iso8601,\n\n        /// Parse a datetime from an RFC3339 string. RFC3339 is similar to\n        /// ISO8601 but is more strict, and allows for arbitrary fractional\n        /// seconds. Using this field will use the same parser `iso8601`, but is\n        /// provided for clarity\n        /// has nanoseconds precision (9 digits after period), same as rfc3339Nano could be\n        /// Format: YYYY-MM-DDTHH:MM:SS.s{,9}+hh:mm\n        rfc3339,\n\n        /// Parse a datetime from an RFC5322 date-time spec\n        rfc5322,\n\n        /// Parse a datetime from an RFC2822 date-time spec. This is an alias for RFC5322\n        rfc2822,\n\n        /// Parse a datetime from an RFC1123 date-time spec\n        rfc1123,\n    };\n\n    /// convert this Instant to another timezone\n    pub fn in(self: Instant, zone: *const TimeZone) Instant {\n        return .{\n            .timestamp = self.timestamp,\n            .timezone = zone,\n        };\n    }\n\n    // convert the nanosecond timestamp into a unix timestamp (in seconds)\n    pub fn unixTimestamp(self: Instant) Seconds {\n        return @intCast(@divFloor(self.timestamp, ns_per_s));\n    }\n\n    pub fn milliTimestamp(self: Instant) Milliseconds {\n        return @intCast(@divFloor(self.timestamp, ns_per_ms));\n    }\n\n    // generate a calendar date and time for this instant\n    pub fn time(self: Instant) Time {\n        const adjusted = self.timezone.adjust(self.unixTimestamp());\n        const days = daysSinceEpoch(adjusted.timestamp);\n        const date = civilFromDays(days);\n\n        var seconds = @mod(adjusted.timestamp, s_per_day);\n        const hours = @divFloor(seconds, s_per_hour);\n        seconds -= hours * s_per_hour;\n        const minutes = @divFloor(seconds, s_per_min);\n        seconds -= minutes * s_per_min;\n\n        // get the nanoseconds from the original timestamp\n        var nanos = @mod(self.timestamp, ns_per_s);\n        const millis = @divFloor(nanos, ns_per_ms);\n        nanos -= millis * ns_per_ms;\n        const micros = @divFloor(nanos, ns_per_us);\n        nanos -= micros * ns_per_us;\n\n        return .{\n            .year = date.year,\n            .month = date.month,\n            .day = date.day,\n            .hour = @intCast(hours),\n            .minute = @intCast(minutes),\n            .second = @intCast(seconds),\n            .millisecond = @intCast(millis),\n            .microsecond = @intCast(micros),\n            .nanosecond = @intCast(nanos),\n            .offset = @intCast(adjusted.timestamp - self.unixTimestamp()),\n            .designation = adjusted.designation,\n        };\n    }\n\n    /// add the duration to the Instant\n    pub fn add(self: Instant, duration: Duration) error{Overflow}!Instant {\n        const ns = try duration.inNanoseconds();\n\n        // check for addition with overflow\n        const timestamp = @addWithOverflow(self.timestamp, ns);\n        if (timestamp[1] == 1) return error.Overflow;\n\n        return .{\n            .timestamp = timestamp[0],\n            .timezone = self.timezone,\n        };\n    }\n\n    /// subtract the duration from the Instant\n    pub fn subtract(self: Instant, duration: Duration) error{Overflow}!Instant {\n        const ns = try duration.inNanoseconds();\n\n        // check for subtraction with overflow\n        const timestamp = @subWithOverflow(self.timestamp, ns);\n        if (timestamp[1] == 1) return error.Overflow;\n\n        return .{\n            .timestamp = timestamp[0],\n            .timezone = self.timezone,\n        };\n    }\n};\n\n/// Creates a new Instant from time value specified by *source*.\n///\n/// See also .instantFromText().\npub fn instant(source: Instant.Source, tz: *const TimeZone) Instant {\n    const ts: Nanoseconds = switch (source) {\n        .now => |io| std.Io.Clock.now(.real, io).nanoseconds,\n        .unix_timestamp => |unix| @as(i128, unix) * ns_per_s,\n        .unix_nano => |nano| nano,\n        .time => |time| time.instant().timestamp,\n    };\n    return .{\n        .timestamp = ts,\n        .timezone = tz,\n    };\n}\n\ntest \"instant\" {\n    const original = instant(.{ .time = .{} }, &utc);\n    const time = original.time();\n    const round_trip = time.instant();\n    try std.testing.expectEqual(original.timestamp, round_trip.timestamp);\n}\n\n/// Creates a new Instant by parsing text.\n///\n/// See also .instant()\npub fn instantFromText(format: Instant.TextFormat, text: []const u8, tz: *const TimeZone) !Instant {\n    const ts: Nanoseconds = switch (format) {\n        .iso8601,\n        .rfc3339,\n        => blk: {\n            const t = try Time.fromISO8601(text);\n            break :blk t.instant().timestamp;\n        },\n        .rfc2822,\n        .rfc5322,\n        => blk: {\n            const t = try Time.fromRFC5322(text);\n            break :blk t.instant().timestamp;\n        },\n        .rfc1123 => blk: {\n            const t = try Time.fromRFC1123(text);\n            break :blk t.instant().timestamp;\n        },\n    };\n    return .{\n        .timestamp = ts,\n        .timezone = tz,\n    };\n}\n\ntest \"instantFromText\" {\n    const original_text = \"2001-09-09T03:46:40+0200\";\n    const original_tz: TimeZone = .{ .fixed = .{\n        .name = \"foo\",\n        .offset = 2 * std.time.s_per_hour,\n        .is_dst = true,\n    } };\n    // ^ not a real TZ but close enough (only offset matters here)\n    const round_trip_instant = try instantFromText(.iso8601, original_text, &original_tz);\n    const round_trip_text = try std.fmt.allocPrint(\n        std.testing.allocator,\n        \"{f}\",\n        .{round_trip_instant.time().timeFmt(.strftime, \"%Y-%m-%dT%H:%M:%S%z\")},\n    );\n    defer std.testing.allocator.free(round_trip_text);\n    try std.testing.expectEqualStrings(original_text, round_trip_text);\n}\n\npub const Month = enum(u4) {\n    jan = 1,\n    feb,\n    mar,\n    apr,\n    may,\n    jun,\n    jul,\n    aug,\n    sep,\n    oct,\n    nov,\n    dec,\n\n    /// returns the last day of the month\n    /// Neri/Schneider algorithm\n    pub fn lastDay(self: Month, year: i32) u5 {\n        const m: u5 = @intFromEnum(self);\n        if (m == 2) return if (isLeapYear(year)) 29 else 28;\n        return 30 | (m ^ (m >> 3));\n    }\n\n    /// returns the full name of the month, eg \"January\"\n    pub fn name(self: Month) []const u8 {\n        return switch (self) {\n            .jan => \"January\",\n            .feb => \"February\",\n            .mar => \"March\",\n            .apr => \"April\",\n            .may => \"May\",\n            .jun => \"June\",\n            .jul => \"July\",\n            .aug => \"August\",\n            .sep => \"September\",\n            .oct => \"October\",\n            .nov => \"November\",\n            .dec => \"December\",\n        };\n    }\n\n    /// returns the short name of the month, eg \"Jan\"\n    pub fn shortName(self: Month) []const u8 {\n        return self.name()[0..3];\n    }\n\n    test \"lastDayOfMonth\" {\n        try std.testing.expectEqual(29, Month.feb.lastDay(2000));\n\n        try std.testing.expectEqual(31, Month.jan.lastDay(2001));\n        try std.testing.expectEqual(28, Month.feb.lastDay(2001));\n        try std.testing.expectEqual(31, Month.mar.lastDay(2001));\n        try std.testing.expectEqual(30, Month.apr.lastDay(2001));\n        try std.testing.expectEqual(31, Month.may.lastDay(2001));\n        try std.testing.expectEqual(30, Month.jun.lastDay(2001));\n        try std.testing.expectEqual(31, Month.jul.lastDay(2001));\n        try std.testing.expectEqual(31, Month.aug.lastDay(2001));\n        try std.testing.expectEqual(30, Month.sep.lastDay(2001));\n        try std.testing.expectEqual(31, Month.oct.lastDay(2001));\n        try std.testing.expectEqual(30, Month.nov.lastDay(2001));\n        try std.testing.expectEqual(31, Month.dec.lastDay(2001));\n    }\n\n    /// the number of days in a year before this month\n    pub fn daysBefore(self: Month, year: i32) u9 {\n        var m = @intFromEnum(self) - 1;\n        var result: u9 = 0;\n        while (m > 0) : (m -= 1) {\n            const month: Month = @enumFromInt(m);\n            result += month.lastDay(year);\n        }\n        return result;\n    }\n\n    test \"daysBefore\" {\n        try std.testing.expectEqual(60, Month.mar.daysBefore(2000));\n        try std.testing.expectEqual(0, Month.jan.daysBefore(2001));\n        try std.testing.expectEqual(31, Month.feb.daysBefore(2001));\n        try std.testing.expectEqual(59, Month.mar.daysBefore(2001));\n    }\n};\n\npub const Duration = struct {\n    days: usize = 0,\n    hours: usize = 0,\n    minutes: usize = 0,\n    seconds: usize = 0,\n    milliseconds: usize = 0,\n    microseconds: usize = 0,\n    nanoseconds: usize = 0,\n\n    /// duration expressed as the total number of nanoseconds\n    pub fn inNanoseconds(self: Duration) error{Overflow}!u64 {\n        // check for multiplication with overflow\n        const days_in_ns = @mulWithOverflow(self.days, ns_per_day);\n        const hours_in_ns = @mulWithOverflow(self.hours, ns_per_hour);\n        const minutes_in_ns = @mulWithOverflow(self.minutes, ns_per_min);\n        const seconds_in_ns = @mulWithOverflow(self.seconds, ns_per_s);\n        const milliseconds_in_ns = @mulWithOverflow(self.milliseconds, ns_per_ms);\n        const microseconds_in_ns = @mulWithOverflow(self.microseconds, ns_per_us);\n        if (days_in_ns[1] == 1 or\n            hours_in_ns[1] == 1 or\n            minutes_in_ns[1] == 1 or\n            seconds_in_ns[1] == 1 or\n            milliseconds_in_ns[1] == 1 or\n            microseconds_in_ns[1] == 1) return error.Overflow;\n\n        // check for addition with overflow\n        var ns = days_in_ns[0];\n        const components = [_]usize{\n            hours_in_ns[0],\n            minutes_in_ns[0],\n            seconds_in_ns[0],\n            milliseconds_in_ns[0],\n            microseconds_in_ns[0],\n            self.nanoseconds,\n        };\n        for (components) |value| {\n            const sum_with_overflow = @addWithOverflow(ns, value);\n            if (sum_with_overflow[1] == 1) return error.Overflow;\n            ns = sum_with_overflow[0];\n        }\n\n        return ns;\n    }\n};\n\npub const Weekday = enum(u3) {\n    sun = 0,\n    mon,\n    tue,\n    wed,\n    thu,\n    fri,\n    sat,\n\n    /// number of days from self until other. Returns 0 when self == other\n    pub fn daysUntil(self: Weekday, other: Weekday) u3 {\n        const d: u8 = @as(u8, @intFromEnum(other)) -% @as(u8, @intFromEnum(self));\n        return if (d <= 6) @intCast(d) else @intCast(d +% 7);\n    }\n\n    /// returns the full name of the day, eg \"Tuesday\"\n    pub fn name(self: Weekday) []const u8 {\n        return switch (self) {\n            .sun => \"Sunday\",\n            .mon => \"Monday\",\n            .tue => \"Tuesday\",\n            .wed => \"Wednesday\",\n            .thu => \"Thursday\",\n            .fri => \"Friday\",\n            .sat => \"Saturday\",\n        };\n    }\n\n    /// returns the short name of the day, eg \"Tue\"\n    pub fn shortName(self: Weekday) []const u8 {\n        return self.name()[0..3];\n    }\n\n    test \"daysUntil\" {\n        const wed: Weekday = .wed;\n        try std.testing.expectEqual(0, wed.daysUntil(.wed));\n        try std.testing.expectEqual(6, wed.daysUntil(.tue));\n        try std.testing.expectEqual(5, wed.daysUntil(.mon));\n        try std.testing.expectEqual(4, wed.daysUntil(.sun));\n    }\n};\n\npub const Date = struct {\n    year: i32,\n    month: Month,\n    day: u5, // 1-31\n\n    /// Checks for equality of two dates\n    pub fn eql(date1: Date, date2: Date) bool {\n        return date1.year == date2.year and\n            date1.month == date2.month and\n            date1.day == date2.day;\n    }\n\n    test \"Date-Equality\" {\n        const date: Date = .{\n            .year = 2025,\n            .month = Month.sep,\n            .day = 13,\n        };\n        try std.testing.expect(date.eql(Date{ .year = 2025, .month = Month.sep, .day = 13 }));\n        try std.testing.expect(!date.eql(Date{ .year = 2025, .month = Month.sep, .day = 12 }));\n        try std.testing.expect(!date.eql(Date{ .year = 2025, .month = Month.aug, .day = 13 }));\n        try std.testing.expect(!date.eql(Date{ .year = 2024, .month = Month.sep, .day = 13 }));\n    }\n\n    /// Compares two dates with another. If `date2` happens after `date1`, then the `TimeComparison.after` is returned.\n    /// If `date2` happens before `date1`, then `TimeComparison.before` is returned. If both represent the same date, `TimeComparison.equal` is returned;\n    pub fn compare(date1: Date, date2: Date) TimeComparison {\n        if (date1.year > date2.year) {\n            return .before;\n        } else if (date1.year < date2.year) {\n            return .after;\n        }\n\n        if (@intFromEnum(date1.month) > @intFromEnum(date2.month)) {\n            return .before;\n        } else if (@intFromEnum(date1.month) < @intFromEnum(date2.month)) {\n            return .after;\n        }\n\n        if (date1.day > date2.day) {\n            return .before;\n        } else if (date1.day < date2.day) {\n            return .after;\n        }\n\n        return .equal;\n    }\n\n    test \"Date-Comparison\" {\n        const date: Date = .{\n            .year = 2025,\n            .month = Month.sep,\n            .day = 13,\n        };\n\n        try std.testing.expectEqual(TimeComparison.before, date.compare(Date{ .year = 2025, .month = Month.sep, .day = 12 }));\n        try std.testing.expectEqual(TimeComparison.before, date.compare(Date{ .year = 2025, .month = Month.aug, .day = 13 }));\n        try std.testing.expectEqual(TimeComparison.before, date.compare(Date{ .year = 2024, .month = Month.sep, .day = 13 }));\n        try std.testing.expectEqual(TimeComparison.before, date.compare(Date{ .year = 2024, .month = Month.dec, .day = 31 }));\n        try std.testing.expectEqual(TimeComparison.before, date.compare(Date{ .year = 2025, .month = Month.aug, .day = 31 }));\n\n        try std.testing.expectEqual(TimeComparison.after, date.compare(Date{ .year = 2025, .month = Month.sep, .day = 14 }));\n        try std.testing.expectEqual(TimeComparison.after, date.compare(Date{ .year = 2025, .month = Month.oct, .day = 13 }));\n        try std.testing.expectEqual(TimeComparison.after, date.compare(Date{ .year = 2026, .month = Month.sep, .day = 13 }));\n        try std.testing.expectEqual(TimeComparison.after, date.compare(Date{ .year = 2026, .month = Month.jan, .day = 1 }));\n        try std.testing.expectEqual(TimeComparison.after, date.compare(Date{ .year = 2025, .month = Month.oct, .day = 1 }));\n\n        try std.testing.expectEqual(TimeComparison.equal, date.compare(Date{ .year = 2025, .month = Month.sep, .day = 13 }));\n    }\n};\n\npub const TimeComparison = enum(u2) {\n    after,\n    before,\n    equal,\n};\n\npub const Time = struct {\n    year: i32 = 1970,\n    month: Month = .jan,\n    day: u5 = 1, // 1-31\n    hour: u5 = 0, // 0-23\n    minute: u6 = 0, // 0-59\n    second: u6 = 0, // 0-60\n    millisecond: u10 = 0, // 0-999\n    microsecond: u10 = 0, // 0-999\n    nanosecond: u10 = 0, // 0-999\n    offset: i32 = 0, // offset from UTC in seconds\n    designation: []const u8 = \"\",\n\n    /// Creates a UTC Instant for this time\n    pub fn instant(self: Time) Instant {\n        const days = daysFromCivil(.{\n            .year = self.year,\n            .month = self.month,\n            .day = self.day,\n        });\n        return .{\n            .timestamp = @as(i128, days) * ns_per_day +\n                @as(i128, self.hour) * ns_per_hour +\n                @as(i128, self.minute) * ns_per_min +\n                @as(i128, self.second) * ns_per_s +\n                @as(i128, self.millisecond) * ns_per_ms +\n                @as(i128, self.microsecond) * ns_per_us +\n                @as(i128, self.nanosecond) -\n                @as(i128, self.offset) * ns_per_s,\n\n            .timezone = &utc,\n        };\n    }\n\n    pub fn fromISO8601(iso: []const u8) !Time {\n        const parseInt = std.fmt.parseInt;\n        var time: Time = .{};\n        const State = enum {\n            year,\n            month_or_ordinal,\n            day,\n            hour,\n            minute,\n            minute_fraction_or_second,\n            second_fraction_or_offset,\n        };\n        var state: State = .year;\n        var i: usize = 0;\n        while (i < iso.len) {\n            switch (state) {\n                .year => {\n                    if (iso.len <= 4) {\n                        // year only data\n                        const int = try parseInt(i32, iso, 10);\n                        time.year = int * std.math.pow(i32, 10, @as(i32, @intCast(4 - iso.len)));\n                        break;\n                    } else {\n                        time.year = try parseInt(i32, iso[0..4], 10);\n                        state = .month_or_ordinal;\n                        i += 4;\n                        if (iso[i] == '-') i += 1;\n                    }\n                },\n                .month_or_ordinal => {\n                    const token_end = std.mem.indexOfAnyPos(u8, iso, i, \"- T\") orelse iso.len;\n                    switch (token_end - i) {\n                        2 => {\n                            const m: u4 = try parseInt(u4, iso[i..token_end], 10);\n                            time.month = @enumFromInt(m);\n                            state = .day;\n                        },\n                        3 => { // ordinal\n                            const doy = try parseInt(u9, iso[i..token_end], 10);\n                            var m: u4 = 1;\n                            var days: u9 = 0;\n                            while (m <= 12) : (m += 1) {\n                                const month: Month = @enumFromInt(m);\n\n                                if (days + month.lastDay(time.year) < doy) {\n                                    days += month.lastDay(time.year);\n                                    continue;\n                                }\n                                time.month = month;\n                                time.day = @intCast(doy - days);\n                                break;\n                            }\n                            state = .hour;\n                        },\n                        4 => { // MMDD\n                            const m: u4 = try parseInt(u4, iso[i .. i + 2], 10);\n                            time.month = @enumFromInt(m);\n                            time.day = try parseInt(u5, iso[i + 2 .. token_end], 10);\n                            state = .hour;\n                        },\n                        else => return error.InvalidISO8601,\n                    }\n                    i = token_end + 1;\n                },\n                .day => {\n                    time.day = try parseInt(u5, iso[i .. i + 2], 10);\n                    // add 3 instead of 2 because we either have a trailing ' ',\n                    // 'T', or EOF\n                    i += 3;\n                    state = .hour;\n                },\n                .hour => {\n                    time.hour = try parseInt(u5, iso[i .. i + 2], 10);\n                    i += 2;\n                    state = .minute;\n                },\n                .minute => {\n                    if (iso[i] == ':') i += 1;\n                    time.minute = try parseInt(u6, iso[i .. i + 2], 10);\n                    i += 2;\n                    state = .minute_fraction_or_second;\n                },\n                .minute_fraction_or_second => {\n                    const b = iso[i];\n                    if (b == '.') return error.UnhandledFormat; // TODO:\n                    if (b == ':') i += 1;\n                    if (std.ascii.isDigit(iso[i])) {\n                        time.second = try parseInt(u6, iso[i .. i + 2], 10);\n                        i += 2;\n                    }\n                    state = .second_fraction_or_offset;\n                },\n                .second_fraction_or_offset => {\n                    switch (iso[i]) {\n                        'Z' => break,\n                        '+', '-' => {\n                            const sign: i32 = if (iso[i] == '-') -1 else 1;\n                            i += 1;\n                            const hour = try parseInt(u5, iso[i .. i + 2], 10);\n                            i += 2;\n                            time.offset = sign * hour * s_per_hour;\n                            if (i >= iso.len - 1) break;\n                            if (iso[i] == ':') i += 1;\n                            const minute = try parseInt(u6, iso[i .. i + 2], 10);\n                            time.offset += sign * minute * s_per_min;\n                            i += 2;\n                            break;\n                        },\n                        '.' => {\n                            i += 1;\n                            const frac_end = std.mem.indexOfAnyPos(u8, iso, i, \"Z+-\") orelse iso.len;\n                            const rhs = try parseInt(u64, iso[i..frac_end], 10);\n                            const sigs = frac_end - i;\n                            // convert sigs to nanoseconds\n                            const pow = std.math.pow(u64, 10, @as(u64, @intCast(9 - sigs)));\n                            var nanos = rhs * pow;\n                            time.millisecond = @intCast(@divFloor(nanos, ns_per_ms));\n                            nanos -= @as(u64, time.millisecond) * ns_per_ms;\n                            time.microsecond = @intCast(@divFloor(nanos, ns_per_us));\n                            nanos -= @as(u64, time.microsecond) * ns_per_us;\n                            time.nanosecond = @intCast(nanos);\n                            i = frac_end;\n                        },\n                        else => return error.InvalidISO8601,\n                    }\n                },\n            }\n        }\n        return time;\n    }\n\n    test \"fromISO8601\" {\n        {\n            const year = try Time.fromISO8601(\"2000\");\n            try std.testing.expectEqual(2000, year.year);\n        }\n        {\n            const ym = try Time.fromISO8601(\"200002\");\n            try std.testing.expectEqual(2000, ym.year);\n            try std.testing.expectEqual(.feb, ym.month);\n\n            const ym_ext = try Time.fromISO8601(\"2000-02\");\n            try std.testing.expectEqual(2000, ym_ext.year);\n            try std.testing.expectEqual(.feb, ym_ext.month);\n        }\n        {\n            const ymd = try Time.fromISO8601(\"20000212\");\n            try std.testing.expectEqual(2000, ymd.year);\n            try std.testing.expectEqual(.feb, ymd.month);\n            try std.testing.expectEqual(12, ymd.day);\n\n            const ymd_ext = try Time.fromISO8601(\"2000-02-12\");\n            try std.testing.expectEqual(2000, ymd_ext.year);\n            try std.testing.expectEqual(.feb, ymd_ext.month);\n            try std.testing.expectEqual(12, ymd_ext.day);\n        }\n        {\n            const ordinal = try Time.fromISO8601(\"2000031\");\n            try std.testing.expectEqual(2000, ordinal.year);\n            try std.testing.expectEqual(.jan, ordinal.month);\n            try std.testing.expectEqual(31, ordinal.day);\n\n            const ordinal_ext = try Time.fromISO8601(\"2000-043\");\n            try std.testing.expectEqual(2000, ordinal_ext.year);\n            try std.testing.expectEqual(.feb, ordinal_ext.month);\n            try std.testing.expectEqual(12, ordinal_ext.day);\n        }\n        {\n            const ymdh = try Time.fromISO8601(\"20000212 11\");\n            try std.testing.expectEqual(2000, ymdh.year);\n            try std.testing.expectEqual(.feb, ymdh.month);\n            try std.testing.expectEqual(12, ymdh.day);\n            try std.testing.expectEqual(11, ymdh.hour);\n\n            const ymdh_ext = try Time.fromISO8601(\"2000-02-12T11\");\n            try std.testing.expectEqual(2000, ymdh_ext.year);\n            try std.testing.expectEqual(.feb, ymdh_ext.month);\n            try std.testing.expectEqual(12, ymdh_ext.day);\n            try std.testing.expectEqual(11, ymdh_ext.hour);\n        }\n        {\n            const ymdhm = try Time.fromISO8601(\"2025-05-19T11:23\");\n            try std.testing.expectEqual(2025, ymdhm.year);\n            try std.testing.expectEqual(.may, ymdhm.month);\n            try std.testing.expectEqual(19, ymdhm.day);\n            try std.testing.expectEqual(11, ymdhm.hour);\n            try std.testing.expectEqual(23, ymdhm.minute);\n        }\n        {\n            const full = try Time.fromISO8601(\"20000212 111213Z\");\n            try std.testing.expectEqual(2000, full.year);\n            try std.testing.expectEqual(.feb, full.month);\n            try std.testing.expectEqual(12, full.day);\n            try std.testing.expectEqual(11, full.hour);\n            try std.testing.expectEqual(12, full.minute);\n            try std.testing.expectEqual(13, full.second);\n\n            const full_ext = try Time.fromISO8601(\"2000-02-12T11:12:13Z\");\n            try std.testing.expectEqual(2000, full_ext.year);\n            try std.testing.expectEqual(.feb, full_ext.month);\n            try std.testing.expectEqual(12, full_ext.day);\n            try std.testing.expectEqual(11, full_ext.hour);\n            try std.testing.expectEqual(12, full_ext.minute);\n            try std.testing.expectEqual(13, full_ext.second);\n        }\n        {\n            const s_frac = try Time.fromISO8601(\"2000-02-12T11:12:13.123Z\");\n            try std.testing.expectEqual(123, s_frac.millisecond);\n            try std.testing.expectEqual(0, s_frac.microsecond);\n            try std.testing.expectEqual(0, s_frac.nanosecond);\n        }\n        {\n            const offset = try Time.fromISO8601(\"2000-02-12T11:12:13.123-12:00\");\n            try std.testing.expectEqual(-12 * s_per_hour, offset.offset);\n        }\n        {\n            const offset = try Time.fromISO8601(\"2000-02-12T11:12:13+12:30\");\n            try std.testing.expectEqual(12 * s_per_hour + 30 * s_per_min, offset.offset);\n        }\n        {\n            const offset = try Time.fromISO8601(\"2025-05-19T11:23+0200\");\n            try std.testing.expectEqual(2 * s_per_hour, offset.offset);\n        }\n        {\n            const offset = try Time.fromISO8601(\"20000212T111213+1230\");\n            try std.testing.expectEqual(12 * s_per_hour + 30 * s_per_min, offset.offset);\n        }\n        {\n            const basic = try Time.fromISO8601(\"20240224T154944\");\n            try std.testing.expectEqual(2024, basic.year);\n            try std.testing.expectEqual(Month.feb, basic.month);\n            try std.testing.expectEqual(24, basic.day);\n            try std.testing.expectEqual(15, basic.hour);\n            try std.testing.expectEqual(49, basic.minute);\n            try std.testing.expectEqual(44, basic.second);\n            try std.testing.expectEqual(0, basic.offset);\n        }\n        {\n            const basic = try Time.fromISO8601(\"20240224T154944Z\");\n            try std.testing.expectEqual(2024, basic.year);\n            try std.testing.expectEqual(Month.feb, basic.month);\n            try std.testing.expectEqual(24, basic.day);\n            try std.testing.expectEqual(15, basic.hour);\n            try std.testing.expectEqual(49, basic.minute);\n            try std.testing.expectEqual(44, basic.second);\n            try std.testing.expectEqual(0, basic.offset);\n        }\n    }\n\n    /// Parse an RFC 5322 date-time string (e.g., \"Thu, 13 Feb 1969 23:32:54 -0330\").\n    ///\n    /// Supports obsolete timezone names from RFC 5322 section 4.3:\n    /// - UT, GMT: UTC (+0000)\n    /// - US timezones: EST/EDT, CST/CDT, MST/MDT, PST/PDT\n    /// - Single-letter military timezones (A-I, K-M, N-Y, Z)\n    ///\n    /// Note: Military timezones use conventional offsets (A=+1, N=-1, etc.) rather than\n    /// RFC 5322's recommendation to treat them as \"-0000\" (unknown offset).\n    pub fn fromRFC5322(eml: []const u8) !Time {\n        const parseInt = std.fmt.parseInt;\n        var time: Time = .{};\n        var i: usize = 0;\n        // day\n        {\n            // consume until a digit\n            while (i < eml.len and !std.ascii.isDigit(eml[i])) : (i += 1) {}\n            const end = std.mem.indexOfScalarPos(u8, eml, i, ' ') orelse return error.InvalidFormat;\n            time.day = try parseInt(u5, eml[i..end], 10);\n            i = end + 1;\n        }\n\n        // month\n        {\n            // consume until an alpha\n            while (i < eml.len and !std.ascii.isAlphabetic(eml[i])) : (i += 1) {}\n            assert(eml.len >= i + 3);\n            var buf: [3]u8 = undefined;\n            buf[0] = std.ascii.toLower(eml[i]);\n            buf[1] = std.ascii.toLower(eml[i + 1]);\n            buf[2] = std.ascii.toLower(eml[i + 2]);\n            time.month = std.meta.stringToEnum(Month, &buf) orelse return error.InvalidFormat;\n            i += 3;\n        }\n\n        // year\n        {\n            // consume until a digit\n            while (i < eml.len and !std.ascii.isDigit(eml[i])) : (i += 1) {}\n            assert(eml.len >= i + 4);\n            time.year = try parseInt(i32, eml[i .. i + 4], 10);\n            i += 4;\n        }\n\n        // hour\n        {\n            // consume until a digit\n            while (i < eml.len and !std.ascii.isDigit(eml[i])) : (i += 1) {}\n            const end = std.mem.indexOfScalarPos(u8, eml, i, ':') orelse return error.InvalidFormat;\n            time.hour = try parseInt(u5, eml[i..end], 10);\n            i = end + 1;\n        }\n        // minute\n        {\n            // consume until a digit\n            while (i < eml.len and !std.ascii.isDigit(eml[i])) : (i += 1) {}\n            assert(i + 2 < eml.len);\n            time.minute = try parseInt(u6, eml[i .. i + 2], 10);\n            i += 2;\n        }\n        // second and zone\n        {\n            assert(i < eml.len);\n            // seconds are optional\n            if (eml[i] == ':') {\n                i += 1;\n                assert(i + 2 < eml.len);\n                time.second = try parseInt(u6, eml[i .. i + 2], 10);\n                i += 2;\n            }\n            // consume whitespace\n            while (i < eml.len and std.ascii.isWhitespace(eml[i])) : (i += 1) {}\n            switch (eml.len - i) {\n                else => {\n                    const hours = try parseInt(i32, eml[i .. i + 3], 10);\n                    const minutes = try parseInt(i32, eml[i + 3 .. i + 5], 10);\n                    const offset_minutes: i32 = if (hours > 0)\n                        hours * 60 + minutes\n                    else\n                        hours * 60 - minutes;\n                    time.offset = offset_minutes * 60;\n                },\n                4 => return error.InvalidFormat, // No formats should have a 4 character zone\n                3 => {\n                    const ObsoleteZoneParseState = enum {\n                        start,\n                        g,\n                        gm,\n                        e,\n                        ed,\n                        es,\n                        c,\n                        cs,\n                        cd,\n                        m,\n                        ms,\n                        md,\n                        p,\n                        ps,\n                        pd,\n                        invalid,\n                    };\n                    const first = std.ascii.toUpper(eml[i]);\n                    const second = std.ascii.toUpper(eml[i + 1]);\n                    const third = std.ascii.toUpper(eml[i + 2]);\n                    // The last of all should be 'T'\n                    if (third != 'T') return error.InvalidFormat;\n                    parse: switch (ObsoleteZoneParseState.start) {\n                        .start => switch (first) {\n                            'G' => continue :parse .g,\n                            'E' => continue :parse .e,\n                            'C' => continue :parse .c,\n                            'M' => continue :parse .m,\n                            'P' => continue :parse .p,\n                            else => return error.InvalidFormat,\n                        },\n                        .g => if (second == 'M') continue :parse .gm else continue :parse .invalid,\n                        .e => if (second == 'D') continue :parse .ed else if (second == 'S') continue :parse .es else continue :parse .invalid,\n                        .c => if (second == 'D') continue :parse .cd else if (second == 'S') continue :parse .cs else continue :parse .invalid,\n                        .m => if (second == 'D') continue :parse .md else if (second == 'S') continue :parse .ms else continue :parse .invalid,\n                        .p => if (second == 'D') continue :parse .pd else if (second == 'S') continue :parse .ps else continue :parse .invalid,\n                        .gm => {\n                            time.offset = 0;\n                        },\n                        .ed => {\n                            time.offset = -4 * 3600;\n                        },\n                        .es, .cd => {\n                            time.offset = -5 * 3600;\n                        },\n                        .cs, .md => {\n                            time.offset = -6 * 3600;\n                        },\n                        .ms, .pd => {\n                            time.offset = -7 * 3600;\n                        },\n                        .ps => {\n                            time.offset = -8 * 3600;\n                        },\n                        .invalid => return error.InvalidFormat,\n                    }\n                },\n                2 => {\n                    if (std.ascii.toUpper(eml[i]) == 'U' and std.ascii.toUpper(eml[i + 1]) == 'T') {\n                        time.offset = 0;\n                    } else {\n                        return error.InvalidFormat;\n                    }\n                },\n                1 => {\n                    switch (eml[i]) {\n                        'Z', 'z' => time.offset = 0,\n                        'A'...'I' => time.offset = (@as(i32, eml[i] - 'A') + 1) * 3600,\n                        'a'...'i' => time.offset = (@as(i32, eml[i] - 'a') + 1) * 3600,\n                        'K'...'M' => time.offset = (@as(i32, eml[i] - 'A')) * 3600, // J is skipped, already offset by 1\n                        'k'...'m' => time.offset = (@as(i32, eml[i] - 'a')) * 3600, // j is skipped, already offset by 1\n                        'N'...'Y' => time.offset = -((@as(i32, eml[i] - 'N') + 1) * 3600),\n                        'n'...'y' => time.offset = -((@as(i32, eml[i] - 'n') + 1) * 3600),\n                        else => return error.InvalidFormat,\n                    }\n                },\n            }\n        }\n        return time;\n    }\n\n    test \"fromRFC5322\" {\n        {\n            const time = try Time.fromRFC5322(\"Thu, 13 Feb 1969 23:32:54 -0330\");\n            try std.testing.expectEqual(1969, time.year);\n            try std.testing.expectEqual(.feb, time.month);\n            try std.testing.expectEqual(13, time.day);\n            try std.testing.expectEqual(23, time.hour);\n            try std.testing.expectEqual(32, time.minute);\n            try std.testing.expectEqual(54, time.second);\n            try std.testing.expectEqual(-12_600, time.offset);\n        }\n        {\n            // FWS everywhere\n            const time = try Time.fromRFC5322(\"  Thu,    13 \\tFeb 1969\\t\\r\\n 23:32:54    -0330\");\n            try std.testing.expectEqual(1969, time.year);\n            try std.testing.expectEqual(.feb, time.month);\n            try std.testing.expectEqual(13, time.day);\n            try std.testing.expectEqual(23, time.hour);\n            try std.testing.expectEqual(32, time.minute);\n            try std.testing.expectEqual(54, time.second);\n            try std.testing.expectEqual(-12_600, time.offset);\n        }\n        {\n            const Test = struct {\n                name: []const u8,\n                value: i32,\n            };\n            const tests = [_]Test{\n                .{ .name = \"UT\", .value = 0 },\n                .{ .name = \"ut\", .value = 0 },\n                .{ .name = \"GMT\", .value = 0 },\n                .{ .name = \"gmt\", .value = 0 },\n                .{ .name = \"EDT\", .value = -4 * 3600 },\n                .{ .name = \"edt\", .value = -4 * 3600 },\n                .{ .name = \"EST\", .value = -5 * 3600 },\n                .{ .name = \"est\", .value = -5 * 3600 },\n                .{ .name = \"CDT\", .value = -5 * 3600 },\n                .{ .name = \"cdt\", .value = -5 * 3600 },\n                .{ .name = \"CST\", .value = -6 * 3600 },\n                .{ .name = \"cst\", .value = -6 * 3600 },\n                .{ .name = \"MDT\", .value = -6 * 3600 },\n                .{ .name = \"mdt\", .value = -6 * 3600 },\n                .{ .name = \"MST\", .value = -7 * 3600 },\n                .{ .name = \"mst\", .value = -7 * 3600 },\n                .{ .name = \"PDT\", .value = -7 * 3600 },\n                .{ .name = \"pdt\", .value = -7 * 3600 },\n                .{ .name = \"PST\", .value = -8 * 3600 },\n                .{ .name = \"pst\", .value = -8 * 3600 },\n                .{ .name = \"I\", .value = 9 * 3600 },\n                .{ .name = \"K\", .value = 10 * 3600 },\n                .{ .name = \"M\", .value = 12 * 3600 },\n                .{ .name = \"n\", .value = -1 * 3600 },\n                .{ .name = \"y\", .value = -12 * 3600 },\n                .{ .name = \"z\", .value = 0 },\n                .{ .name = \"Z\", .value = 0 },\n            };\n            for (tests) |t| {\n                var buf: [64]u8 = undefined;\n                const rfc5322_str = std.fmt.bufPrint(&buf, \"Thu, 13 Feb 1969 23:32:54 {s}\", .{t.name}) catch unreachable;\n                const time = try Time.fromRFC5322(rfc5322_str);\n                try std.testing.expectEqual(1969, time.year);\n                try std.testing.expectEqual(.feb, time.month);\n                try std.testing.expectEqual(13, time.day);\n                try std.testing.expectEqual(23, time.hour);\n                try std.testing.expectEqual(32, time.minute);\n                try std.testing.expectEqual(54, time.second);\n                try std.testing.expectEqual(t.value, time.offset);\n            }\n\n            try std.testing.expectError(\n                error.InvalidFormat,\n                Time.fromRFC5322(\"Thu, 13 Feb 1969 23:32:54 XYZ\"),\n            );\n            try std.testing.expectError(\n                error.InvalidFormat,\n                Time.fromRFC5322(\"Thu, 13 Feb 1969 23:32:54 J\"), // J is not allowed in Military timezones\n            );\n        }\n    }\n\n    pub fn fromRFC1123(http_date: []const u8) !Time {\n        const parseInt = std.fmt.parseInt;\n        var time: Time = .{};\n        var i: usize = 0;\n\n        // day\n        {\n            // consume until a digit\n            while (i < http_date.len and !std.ascii.isDigit(http_date[i])) : (i += 1) {}\n            const end = std.mem.indexOfScalarPos(u8, http_date, i, ' ') orelse return error.InvalidFormat;\n            time.day = try parseInt(u5, http_date[i..end], 10);\n            i = end + 1;\n        }\n\n        // month\n        {\n            // consume until an alpha\n            while (i < http_date.len and !std.ascii.isAlphabetic(http_date[i])) : (i += 1) {}\n            assert(http_date.len >= i + 3);\n            var buf: [3]u8 = undefined;\n            buf[0] = std.ascii.toLower(http_date[i]);\n            buf[1] = std.ascii.toLower(http_date[i + 1]);\n            buf[2] = std.ascii.toLower(http_date[i + 2]);\n            time.month = std.meta.stringToEnum(Month, &buf) orelse return error.InvalidFormat;\n            i += 3;\n        }\n\n        // year\n        {\n            // consume until a digit\n            while (i < http_date.len and !std.ascii.isDigit(http_date[i])) : (i += 1) {}\n            assert(http_date.len >= i + 4);\n            time.year = try parseInt(i32, http_date[i .. i + 4], 10);\n            i += 4;\n        }\n\n        // hour\n        {\n            // consume until a digit\n            while (i < http_date.len and !std.ascii.isDigit(http_date[i])) : (i += 1) {}\n            const end = std.mem.indexOfScalarPos(u8, http_date, i, ':') orelse return error.InvalidFormat;\n            time.hour = try parseInt(u5, http_date[i..end], 10);\n            i = end + 1;\n        }\n        // minute\n        {\n            // consume until a digit\n            while (i < http_date.len and !std.ascii.isDigit(http_date[i])) : (i += 1) {}\n            assert(i + 2 < http_date.len);\n            time.minute = try parseInt(u6, http_date[i .. i + 2], 10);\n            i += 2;\n        }\n        // second\n        {\n            assert(i < http_date.len);\n            i += 1;\n            assert(i + 2 < http_date.len);\n            time.second = try parseInt(u6, http_date[i .. i + 2], 10);\n            i += 2;\n        }\n        // zone\n        {\n            // consume whitespace\n            while (i < http_date.len and std.ascii.isWhitespace(http_date[i])) : (i += 1) {}\n            assert(std.mem.eql(u8, http_date[i..], \"GMT\"));\n            time.offset = 0;\n        }\n        return time;\n    }\n\n    test \"fromRFC1123\" {\n        {\n            const time = try Time.fromRFC1123(\"Sun, 06 Nov 1994 08:49:37 GMT\");\n            try std.testing.expectEqual(1994, time.year);\n            try std.testing.expectEqual(.nov, time.month);\n            try std.testing.expectEqual(6, time.day);\n            try std.testing.expectEqual(8, time.hour);\n            try std.testing.expectEqual(49, time.minute);\n            try std.testing.expectEqual(37, time.second);\n            try std.testing.expectEqual(0, time.offset);\n        }\n    }\n\n    pub const Format = union(enum) {\n        rfc3339, // YYYY-MM-DD-THH:MM:SS.sss+00:00\n        rfc3339Nano, // YYYY-MM-DD-THH:MM:SS.sssssssss+00:00, has 9 digits after period, nanos precision\n    };\n\n    pub fn bufPrint(self: Time, buf: []u8, fmt: Format) ![]u8 {\n        switch (fmt) {\n            .rfc3339 => {\n                if (self.year < 0) return error.InvalidTime;\n                if (self.offset == 0)\n                    return std.fmt.bufPrint(\n                        buf,\n                        \"{d:0>4}-{d:0>2}-{d:0>2}T{d:0>2}:{d:0>2}:{d:0>2}.{d:0>3}Z\",\n                        .{\n                            @as(u32, @intCast(self.year)),\n                            @intFromEnum(self.month),\n                            self.day,\n                            self.hour,\n                            self.minute,\n                            self.second,\n                            self.millisecond,\n                        },\n                    )\n                else {\n                    const h = @divFloor(@abs(self.offset), s_per_hour);\n                    const min = @divFloor(@abs(self.offset) - h * s_per_hour, s_per_min);\n                    const sign: u8 = if (self.offset > 0) '+' else '-';\n                    return std.fmt.bufPrint(\n                        buf,\n                        \"{d:0>4}-{d:0>2}-{d:0>2}T{d:0>2}:{d:0>2}:{d:0>2}.{d:0>3}{c}{d:0>2}:{d:0>2}\",\n                        .{\n                            @as(u32, @intCast(self.year)),\n                            @intFromEnum(self.month),\n                            self.day,\n                            self.hour,\n                            self.minute,\n                            self.second,\n                            self.millisecond,\n                            sign,\n                            h,\n                            min,\n                        },\n                    );\n                }\n            },\n            .rfc3339Nano => {\n                if (self.year < 0) return error.InvalidTime;\n                if (self.offset == 0)\n                    return std.fmt.bufPrint(\n                        buf,\n                        \"{d:0>4}-{d:0>2}-{d:0>2}T{d:0>2}:{d:0>2}:{d:0>2}.{d:0>3}{d:0>3}{d:0>3}Z\",\n                        .{\n                            @as(u32, @intCast(self.year)),\n                            @intFromEnum(self.month),\n                            self.day,\n                            self.hour,\n                            self.minute,\n                            self.second,\n                            self.millisecond,\n                            self.microsecond,\n                            self.nanosecond,\n                        },\n                    )\n                else {\n                    const h = @divFloor(@abs(self.offset), s_per_hour);\n                    const min = @divFloor(@abs(self.offset) - h * s_per_hour, s_per_min);\n                    const sign: u8 = if (self.offset > 0) '+' else '-';\n                    return std.fmt.bufPrint(\n                        buf,\n                        \"{d:0>4}-{d:0>2}-{d:0>2}T{d:0>2}:{d:0>2}:{d:0>2}.{d:0>3}{d:0>3}{d:0>3}{c}{d:0>2}:{d:0>2}\",\n                        .{\n                            @as(u32, @intCast(self.year)),\n                            @intFromEnum(self.month),\n                            self.day,\n                            self.hour,\n                            self.minute,\n                            self.second,\n                            self.millisecond,\n                            self.microsecond,\n                            self.nanosecond,\n                            sign,\n                            h,\n                            min,\n                        },\n                    );\n                }\n            },\n        }\n    }\n\n    pub const FmtKind = enum { gofmt, strftime };\n    pub fn timeFmt(self: Time, kind: FmtKind, fmt_str: []const u8) TimeFmt {\n        return .{\n            .time = self,\n            .kind = kind,\n            .str = fmt_str,\n        };\n    }\n\n    const TimeFmt = struct {\n        time: Time,\n        kind: FmtKind,\n        str: []const u8,\n\n        pub fn format(self: TimeFmt, writer: *std.Io.Writer) !void {\n            switch (self.kind) {\n                .gofmt => self.time.gofmt(writer, self.str) catch return error.WriteFailed,\n                .strftime => self.time.strftime(writer, self.str) catch return error.WriteFailed,\n            }\n        }\n    };\n\n    /// Format time using strftime(3) specified, eg %Y-%m-%dT%H:%M:%S\n    pub fn strftime(self: Time, writer: *std.Io.Writer, fmt: []const u8) !void {\n        const inst = self.instant();\n        var i: usize = 0;\n        while (i < fmt.len) {\n            const last = i;\n            i = std.mem.indexOfScalarPos(u8, fmt, i, '%') orelse {\n                try writer.writeAll(fmt[i..]);\n                i = fmt.len;\n                break;\n            };\n            if (i + 1 >= fmt.len) return error.InvalidFormat;\n\n            try writer.writeAll(fmt[last..i]);\n            defer i = i + 2;\n            const b = fmt[i + 1];\n            switch (b) {\n                '%' => try writer.writeByte('%'),\n                'a' => {\n                    const days = daysFromCivil(\n                        .{ .year = self.year, .month = self.month, .day = self.day },\n                    );\n                    const weekday = weekdayFromDays(days);\n                    try writer.writeAll(weekday.shortName());\n                },\n                'A' => {\n                    const days = daysFromCivil(\n                        .{ .year = self.year, .month = self.month, .day = self.day },\n                    );\n                    const weekday = weekdayFromDays(days);\n                    try writer.writeAll(weekday.name());\n                },\n                'b', 'h' => try writer.writeAll(self.month.shortName()),\n                'B' => try writer.writeAll(self.month.name()),\n                'c' => try self.strftime(writer, \"%a %b %e %H:%M:%S %Y\"), // locale specific\n                'C' => {\n                    if (self.year > 9999 or self.year < -9999) return error.Overflow;\n                    var buf: [5]u8 = undefined;\n                    // year is an i64, which gets printed with a + or a -\n                    _ = try std.fmt.bufPrint(&buf, \"{d:0>4}\", .{self.year});\n                    try writer.writeAll(buf[1..3]);\n                },\n                'd' => try writer.print(\"{d:0>2}\", .{self.day}),\n                'D' => try self.strftime(writer, \"%m/%d/%y\"),\n                'e' => try writer.print(\"{d: >2}\", .{self.day}),\n                'f' => try writer.print(\"{d:0>3}{d:0>3}\", .{ self.millisecond, self.microsecond }),\n                'F' => try self.strftime(writer, \"%Y-%m-%d\"),\n                'G' => return error.UnsupportedSpecifier,\n                'g' => return error.UnsupportedSpecifier,\n                'H' => try writer.print(\"{d:0>2}\", .{self.hour}),\n                'I' => {\n                    switch (self.hour) {\n                        0 => try writer.writeAll(\"12\"),\n                        1...12 => try writer.print(\"{d:0>2}\", .{self.hour}),\n                        else => try writer.print(\"{d:0>2}\", .{self.hour - 12}),\n                    }\n                },\n                'j' => {\n                    const before_month = self.month.daysBefore(self.year);\n                    try writer.print(\"{d:0>3}\", .{self.day + before_month});\n                },\n                'k' => try writer.print(\"{d}\", .{self.hour}),\n                'l' => {\n                    switch (self.hour) {\n                        0 => try writer.writeAll(\"12\"),\n                        1...12 => try writer.print(\"{d}\", .{self.hour}),\n                        else => try writer.print(\"{d}\", .{self.hour - 12}),\n                    }\n                },\n                'm' => try writer.print(\"{d:0>2}\", .{@intFromEnum(self.month)}),\n                'M' => try writer.print(\"{d:0>2}\", .{self.minute}),\n                'n' => try writer.writeByte('\\n'),\n                'O' => return error.UnsupportedSpecifier,\n                'p' => {\n                    if (self.hour >= 12)\n                        try writer.writeAll(\"PM\")\n                    else\n                        try writer.writeAll(\"AM\");\n                },\n                'P' => {\n                    if (self.hour >= 12)\n                        try writer.writeAll(\"pm\")\n                    else\n                        try writer.writeAll(\"am\");\n                },\n                'r' => try self.strftime(writer, \"%I:%M:%S %p\"),\n                'R' => try self.strftime(writer, \"%H:%M\"),\n                's' => try writer.print(\"{d}\", .{inst.unixTimestamp()}),\n                'S' => try writer.print(\"{d:0>2}\", .{self.second}),\n                't' => try writer.writeByte('\\t'),\n                'T' => try self.strftime(writer, \"%H:%M:%S\"),\n                'u' => {\n                    const days = daysFromCivil(\n                        .{ .year = self.year, .month = self.month, .day = self.day },\n                    );\n                    const weekday = weekdayFromDays(days);\n                    switch (weekday) {\n                        .sun => try writer.writeByte('7'),\n                        else => try writer.writeByte(@as(u8, @intFromEnum(weekday)) + 0x30),\n                    }\n                },\n                'U' => {\n                    const day_of_year = self.day + self.month.daysBefore(self.year);\n                    // find the date of the first sunday\n                    const weekd_jan_1 = blk: {\n                        const jan_1: Date = .{ .year = self.year, .month = .jan, .day = 1 };\n                        const days = daysFromCivil(jan_1);\n                        break :blk weekdayFromDays(days);\n                    };\n                    // Day of year of first sunday. This represents the start of week 1\n                    const first_sunday = switch (weekd_jan_1) {\n                        .sun => 1,\n                        else => 7 - @intFromEnum(weekd_jan_1) + 1,\n                    };\n                    if (day_of_year < first_sunday)\n                        try writer.writeAll(\"00\")\n                    else\n                        try writer.print(\"{d:0>2}\", .{(day_of_year + 7 - first_sunday) / 7});\n                },\n                'V' => return error.UnsupportedSpecifier,\n                'w' => {\n                    const days = daysFromCivil(\n                        .{ .year = self.year, .month = self.month, .day = self.day },\n                    );\n                    const weekday = weekdayFromDays(days);\n                    try writer.writeByte(@as(u8, @intFromEnum(weekday)) + 0x30);\n                },\n                'W' => {\n                    const day_of_year = self.day + self.month.daysBefore(self.year);\n                    // find the date of the first sunday\n                    const weekd_jan_1 = blk: {\n                        const jan_1: Date = .{ .year = self.year, .month = .jan, .day = 1 };\n                        const days = daysFromCivil(jan_1);\n                        break :blk weekdayFromDays(days);\n                    };\n                    // Day of year of first sunday. This represents the start of week 1\n                    const first_monday = switch (weekd_jan_1) {\n                        .sun => 2,\n                        .mon => 1,\n                        else => 7 - @intFromEnum(weekd_jan_1) + 2,\n                    };\n                    if (day_of_year < first_monday)\n                        try writer.writeAll(\"00\")\n                    else\n                        try writer.print(\"{d:0>2}\", .{(day_of_year + 7 - first_monday) / 7});\n                },\n                'x' => try self.strftime(writer, \"%m/%d/%y\"),\n                'X' => try self.strftime(writer, \"%H:%M:%S\"),\n                'y' => {\n                    var buf: [16]u8 = undefined;\n                    _ = try std.fmt.bufPrint(&buf, \"{d:0>16}\", .{self.year});\n                    try writer.writeAll(buf[14..16]);\n                },\n                'Y' => try writer.print(\"{d}\", .{self.year}),\n                'z' => {\n                    const hours = absHoursFromSeconds(self.offset);\n                    const minutes = absMinutesFromSeconds(self.offset);\n                    if (self.offset < 0)\n                        try writer.print(\"-{d:0>2}{d:0>2}\", .{ hours, minutes })\n                    else\n                        try writer.print(\"+{d:0>2}{d:0>2}\", .{ hours, minutes });\n                },\n                'Z' => try writer.writeAll(self.designation),\n                else => return error.UnknownSpecifier,\n            }\n        }\n    }\n\n    /// Format using golang magic date format.\n    pub fn gofmt(self: Time, writer: *std.Io.Writer, fmt: []const u8) !void {\n        var i: usize = 0;\n        while (i < fmt.len) : (i += 1) {\n            const b = fmt[i];\n            switch (b) {\n                'J' => { // Jan, January\n                    if (std.mem.startsWith(u8, fmt[i..], \"January\")) {\n                        try writer.writeAll(self.month.name());\n                        i += 6;\n                    } else if (std.mem.startsWith(u8, fmt[i..], \"Jan\")) {\n                        try writer.writeAll(self.month.shortName());\n                        i += 2;\n                    } else try writer.writeByte(b);\n                },\n                'M' => { // Monday, Mon, MST\n                    if (std.mem.startsWith(u8, fmt[i..], \"Monday\")) {\n                        const days = daysFromCivil(\n                            .{ .year = self.year, .month = self.month, .day = self.day },\n                        );\n                        const weekday = weekdayFromDays(days);\n                        try writer.writeAll(weekday.name());\n                        i += 5;\n                    } else if (std.mem.startsWith(u8, fmt[i..], \"Mon\")) {\n                        if (i + 3 >= fmt.len) {\n                            const days = daysFromCivil(\n                                .{ .year = self.year, .month = self.month, .day = self.day },\n                            );\n                            const weekday = weekdayFromDays(days);\n                            try writer.writeAll(weekday.shortName());\n                            i += 2;\n                        } else if (!std.ascii.isLower(fmt[i + 3])) {\n                            // We only write \"Mon\" if the next char is *not* a lowercase\n                            const days = daysFromCivil(\n                                .{ .year = self.year, .month = self.month, .day = self.day },\n                            );\n                            const weekday = weekdayFromDays(days);\n                            try writer.writeAll(weekday.shortName());\n                            i += 2;\n                        }\n                    } else if (std.mem.startsWith(u8, fmt[i..], \"MST\")) {\n                        try writer.writeAll(self.designation);\n                        i += 2;\n                    } else try writer.writeByte(b);\n                },\n                '0' => { // 01, 02, 03, 04, 05, 06, 002\n                    if (i == fmt.len - 1) {\n                        try writer.writeByte(b);\n                        continue;\n                    }\n                    i += 1;\n                    const b2 = fmt[i];\n                    switch (b2) {\n                        '1' => try writer.print(\"{d:0>2}\", .{@intFromEnum(self.month)}),\n                        '2' => try writer.print(\"{d:0>2}\", .{self.day}),\n                        '3' => {\n                            if (self.hour == 0)\n                                try writer.writeAll(\"12\")\n                            else if (self.hour > 12)\n                                try writer.print(\"{d:0>2}\", .{self.hour - 12})\n                            else\n                                try writer.print(\"{d:0>2}\", .{self.hour});\n                        },\n                        '4' => try writer.print(\"{d:0>2}\", .{self.minute}),\n                        '5' => try writer.print(\"{d:0>2}\", .{self.second}),\n                        '6' => {\n                            var buf: [16]u8 = undefined;\n                            _ = try std.fmt.bufPrint(&buf, \"{d:0>16}\", .{self.year});\n                            try writer.writeAll(buf[14..16]);\n                        },\n                        else => {\n                            if (std.mem.startsWith(u8, fmt[i..], \"02\")) {\n                                i += 1;\n                                const before_month = self.month.daysBefore(self.year);\n                                try writer.print(\"{d:0>3}\", .{self.day + before_month});\n                            } else {\n                                try writer.writeByte(b);\n                                try writer.writeByte(b2);\n                            }\n                        },\n                    }\n                },\n                '1' => { // 15, 1\n                    if (std.mem.startsWith(u8, fmt[i..], \"15\")) {\n                        i += 1;\n                        try writer.print(\"{d:0>2}\", .{self.hour});\n                    } else {\n                        try writer.print(\"{d}\", .{@intFromEnum(self.month)});\n                    }\n                },\n                '2' => { // 2006, 2\n                    if (std.mem.startsWith(u8, fmt[i..], \"2006\")) {\n                        i += 3;\n                        if (self.year < 0)\n                            try writer.print(\"{d}\", .{self.year})\n                        else\n                            try writer.print(\"{d}\", .{@as(u32, @intCast(self.year))});\n                    } else try writer.print(\"{d}\", .{self.day});\n                },\n                '_' => { // _2, __2\n                    if (std.mem.startsWith(u8, fmt[i..], \"_2\")) {\n                        i += 1;\n                        try writer.print(\"{d: >2}\", .{self.day});\n                    } else if (std.mem.startsWith(u8, fmt[i..], \"__2\")) {\n                        i += 2;\n                        const before_month = self.month.daysBefore(self.year);\n                        try writer.print(\"{d: >3}\", .{self.day + before_month});\n                    } else try writer.writeByte(b);\n                },\n                '3' => {\n                    if (self.hour == 0)\n                        try writer.writeAll(\"12\")\n                    else if (self.hour > 12)\n                        try writer.print(\"{d}\", .{self.hour - 12})\n                    else\n                        try writer.print(\"{d}\", .{self.hour});\n                },\n                '4' => try writer.print(\"{d}\", .{self.minute}),\n                '5' => try writer.print(\"{d}\", .{self.second}),\n                'P' => {\n                    if (i + 1 < fmt.len and fmt[i + 1] == 'M') {\n                        i += 1;\n                        if (self.hour >= 12)\n                            try writer.writeAll(\"PM\")\n                        else\n                            try writer.writeAll(\"AM\");\n                    } else try writer.writeByte(b);\n                },\n                'p' => {\n                    if (i + 1 < fmt.len and fmt[i + 1] == 'm') {\n                        i += 1;\n                        if (self.hour >= 12)\n                            try writer.writeAll(\"pm\")\n                        else\n                            try writer.writeAll(\"am\");\n                    } else try writer.writeByte(b);\n                },\n                '-', 'Z' => { // -070000, -07:00:00, -0700, -07:00, -07\n                    if (i == fmt.len - 1) {\n                        try writer.writeByte(b);\n                        continue;\n                    }\n                    if (std.mem.startsWith(u8, fmt[i + 1 ..], \"070000\")) {\n                        i += 6;\n                        if (self.offset == 0 and b == 'Z') {\n                            try writer.writeByte('Z');\n                            continue;\n                        }\n                        const hours = absHoursFromSeconds(self.offset);\n                        const minutes = absMinutesFromSeconds(self.offset);\n                        const seconds = absSecondsFromSeconds(self.offset);\n                        const sign: u8 = if (self.offset < 0) '-' else '+';\n                        try writer.print(\"{c}{d:0>2}{d:0>2}{d:0>2}\", .{ sign, hours, minutes, seconds });\n                    } else if (std.mem.startsWith(u8, fmt[i + 1 ..], \"07:00:00\")) {\n                        i += 8;\n                        if (self.offset == 0 and b == 'Z') {\n                            try writer.writeByte('Z');\n                            continue;\n                        }\n                        const hours = absHoursFromSeconds(self.offset);\n                        const minutes = absMinutesFromSeconds(self.offset);\n                        const seconds = absSecondsFromSeconds(self.offset);\n                        const sign: u8 = if (self.offset < 0) '-' else '+';\n                        try writer.print(\"{c}{d:0>2}:{d:0>2}:{d:0>2}\", .{ sign, hours, minutes, seconds });\n                    } else if (std.mem.startsWith(u8, fmt[i + 1 ..], \"0700\")) {\n                        i += 4;\n                        if (self.offset == 0 and b == 'Z') {\n                            try writer.writeByte('Z');\n                            continue;\n                        }\n                        const hours = absHoursFromSeconds(self.offset);\n                        const minutes = absMinutesFromSeconds(self.offset);\n                        const sign: u8 = if (self.offset < 0) '-' else '+';\n                        try writer.print(\"{c}{d:0>2}{d:0>2}\", .{ sign, hours, minutes });\n                    } else if (std.mem.startsWith(u8, fmt[i + 1 ..], \"07:00\")) {\n                        i += 5;\n                        if (self.offset == 0 and b == 'Z') {\n                            try writer.writeByte('Z');\n                            continue;\n                        }\n                        const hours = absHoursFromSeconds(self.offset);\n                        const minutes = absMinutesFromSeconds(self.offset);\n                        const sign: u8 = if (self.offset < 0) '-' else '+';\n                        try writer.print(\"{c}{d:0>2}:{d:0>2}\", .{ sign, hours, minutes });\n                    } else if (std.mem.startsWith(u8, fmt[i + 1 ..], \"07\")) {\n                        i += 2;\n                        if (self.offset == 0 and b == 'Z') {\n                            try writer.writeByte('Z');\n                            continue;\n                        }\n                        const hours = absHoursFromSeconds(self.offset);\n                        const sign: u8 = if (self.offset < 0) '-' else '+';\n                        try writer.print(\"{c}{d:0>2}\", .{ sign, hours });\n                    } else try writer.writeByte(b);\n                },\n                '.', ',' => { // ,000, or .000, or ,999, or .999 - repeated digits for fractional seconds.\n                    try writer.writeByte(b);\n\n                    if (i == fmt.len - 1) continue;\n\n                    const c = fmt[i + 1];\n                    switch (c) {\n                        '0' => {\n                            var n: usize = 0;\n                            const j: usize = i + 1;\n                            while (j + n < fmt.len and fmt[j + n] == '0') : (n += 1) {}\n\n                            // If we ended on a digit, it wasn't a 0. That means this was not a\n                            // valid fractional second\n                            if (j + n < fmt.len and std.ascii.isDigit(fmt[j + n])) continue;\n                            i += j + n;\n\n                            var buf: [9]u8 = undefined;\n                            const str = try std.fmt.bufPrint(\n                                &buf,\n                                \"{d:0>3}{d:0>3}{d:0>3}\",\n                                .{ self.millisecond, self.microsecond, self.nanosecond },\n                            );\n                            try writer.writeAll(str[0..@min(n, str.len)]);\n                            if (n > str.len)\n                                try writer.splatByteAll('0', n - str.len);\n                        },\n                        '9' => {\n                            var n: usize = 0;\n                            const j: usize = i + 1;\n                            while (j + n < fmt.len and fmt[j + n] == '9') : (n += 1) {}\n\n                            // If we ended on a digit, it wasn't a 0. That means this was not a\n                            // valid fractional second\n                            if (j + n < fmt.len and std.ascii.isDigit(fmt[j + n])) continue;\n                            i += j + n;\n\n                            var buf: [9]u8 = undefined;\n                            const str = try std.fmt.bufPrint(\n                                &buf,\n                                \"{d:0>3}{d:0>3}{d:0>3}\",\n                                .{ self.millisecond, self.microsecond, self.nanosecond },\n                            );\n\n                            var iter = std.mem.reverseIterator(str[0..@min(n, str.len)]);\n                            var last_non_zero = @min(n, str.len);\n                            while (iter.next()) |d| {\n                                if (d != '0') break;\n                                last_non_zero -= 1;\n                            }\n                            try writer.writeAll(str[0..last_non_zero]);\n                        },\n                        else => continue,\n                    }\n                },\n                'N' => {\n                    if (std.mem.startsWith(u8, fmt[i..], \"ND\")) {\n                        i += 1;\n                        switch (self.day) {\n                            0, 4...20, 24...30 => try writer.writeAll(\"TH\"),\n                            1, 21, 31 => try writer.writeAll(\"ST\"),\n                            2, 22 => try writer.writeAll(\"ND\"),\n                            3, 23 => try writer.writeAll(\"RD\"),\n                        }\n                    } else try writer.writeByte(b);\n                },\n                'n' => {\n                    if (std.mem.startsWith(u8, fmt[i..], \"nd\")) {\n                        i += 1;\n                        switch (self.day) {\n                            0, 4...20, 24...30 => try writer.writeAll(\"th\"),\n                            1, 21, 31 => try writer.writeAll(\"st\"),\n                            2, 22 => try writer.writeAll(\"nd\"),\n                            3, 23 => try writer.writeAll(\"rd\"),\n                        }\n                    } else try writer.writeByte(b);\n                },\n                else => try writer.writeByte(b),\n            }\n        }\n    }\n\n    fn absHoursFromSeconds(seconds: Seconds) u32 {\n        if (seconds < 0)\n            return @intCast(@divTrunc(-seconds, 60 * 60))\n        else\n            return @intCast(@divTrunc(seconds, 60 * 60));\n    }\n\n    fn absMinutesFromSeconds(seconds: Seconds) u32 {\n        const hours = absHoursFromSeconds(seconds);\n        if (seconds < 0)\n            return @intCast(@divTrunc((-seconds) - hours * 3600, 60))\n        else\n            return @intCast(@divTrunc(seconds - hours * 3600, 60));\n    }\n\n    fn absSecondsFromSeconds(seconds: Seconds) u32 {\n        const hours = absHoursFromSeconds(seconds);\n        const minutes = absMinutesFromSeconds(seconds);\n        if (seconds < 0)\n            return @intCast(@divTrunc((-seconds) - hours * 3600 - minutes * 60, 1))\n        else\n            return @intCast(@divTrunc(seconds - hours * 3600 - minutes * 60, 1));\n    }\n\n    pub fn compare(self: Time, time: Time) TimeComparison {\n        const self_instant = self.instant();\n        const time_instant = time.instant();\n\n        if (self_instant.timestamp > time_instant.timestamp) {\n            return .after;\n        } else if (self_instant.timestamp < time_instant.timestamp) {\n            return .before;\n        } else {\n            return .equal;\n        }\n    }\n\n    pub fn after(self: Time, time: Time) bool {\n        const self_instant = self.instant();\n        const time_instant = time.instant();\n        return self_instant.timestamp > time_instant.timestamp;\n    }\n\n    pub fn before(self: Time, time: Time) bool {\n        const self_instant = self.instant();\n        const time_instant = time.instant();\n        return self_instant.timestamp < time_instant.timestamp;\n    }\n\n    pub fn eql(self: Time, time: Time) bool {\n        const self_instant = self.instant();\n        const time_instant = time.instant();\n        return self_instant.timestamp == time_instant.timestamp;\n    }\n};\n\n/// Returns the number of days since the Unix epoch. timestamp should be the number of seconds from\n/// the Unix epoch\npub fn daysSinceEpoch(timestamp: Seconds) Days {\n    return @intCast(@divFloor(timestamp, s_per_day));\n}\n\ntest \"days since epoch\" {\n    try std.testing.expectEqual(0, daysSinceEpoch(0));\n    try std.testing.expectEqual(0, daysSinceEpoch(1));\n    try std.testing.expectEqual(-1, daysSinceEpoch(-1));\n    try std.testing.expectEqual(-2, daysSinceEpoch(-(s_per_day + 1)));\n    try std.testing.expectEqual(1, daysSinceEpoch(s_per_day + 1));\n    try std.testing.expectEqual(19797, daysSinceEpoch(1710523947));\n}\n\npub fn isLeapYear(year: i32) bool {\n    // Neri/Schneider algorithm\n    const d: i32 = if (@mod(year, 100) != 0) 4 else 16;\n    return (year & (d - 1)) == 0;\n}\n\n/// returns the weekday given a number of days since the unix epoch\n/// https://howardhinnant.github.io/date_algorithms.html#weekday_from_days\npub fn weekdayFromDays(days: Days) Weekday {\n    return @enumFromInt(@mod((days + 4), 7));\n}\n\ntest \"weekdayFromDays\" {\n    try std.testing.expectEqual(.thu, weekdayFromDays(0));\n    try std.testing.expectEqual(.sat, weekdayFromDays(-5));\n    try std.testing.expectEqual(.wed, weekdayFromDays(-8));\n}\n\n/// Ben Joffe's very fast 64-bit date algorithm\n/// https://www.benjoffe.com/fast-date-64\npub fn civilFromDays(days: Days) Date {\n    const is_arm = builtin.cpu.arch == .aarch64 or builtin.cpu.arch == .arm;\n\n    const eras: u64 = 4726498270;\n    const d_shift: u64 = 146097 * eras - 719469;\n    const y_shift: u64 = 400 * eras - 1;\n    const scale: u64 = if (is_arm) 1 else 32;\n    const shift_0: u64 = 30556 * scale;\n    const shift_1: u64 = 5980 * scale;\n    const c1: u64 = 505054698555331;\n    const c2: u64 = 50504432782230121;\n    const c3: u64 = 8619973866219416 * 32 / scale;\n\n    // Adjust for 100/400 leap year rule, reverse day count\n    const rev: u64 = d_shift -% @as(u64, @bitCast(@as(i64, days)));\n    const cen: u64 = @truncate(@as(u128, c1) * rev >> 64);\n    const jul: u64 = rev +% cen -% cen / 4;\n\n    // Determine year and year-part\n    const num: u128 = @as(u128, c2) * jul;\n    const yrs: u64 = y_shift -% @as(u64, @truncate(num >> 64));\n    const low: u64 = @truncate(num);\n    const ypt: u64 = @truncate(@as(u128, 24451 * scale) * low >> 64);\n\n    // Year-modulo-bitshift for leap years\n    const bump: u64, const shift: u64, const month: u64 = if (is_arm) blk: {\n        const s: u64 = shift_0;\n        const n: u64 = (yrs % 4) * (16 * scale) +% s -% ypt;\n        const m: u64 = n / (2048 * scale);\n        break :blk .{ if (m > 12) 1 else 0, s, if (m > 12) m - 12 else m };\n    } else blk: {\n        const b: u64 = if (ypt < 3952 * scale) 1 else 0;\n        const s: u64 = if (b == 1) shift_1 else shift_0;\n        const n: u64 = (yrs % 4) * (16 * scale) +% s -% ypt;\n        break :blk .{ b, s, n / (2048 * scale) };\n    };\n\n    const n: u64 = (yrs % 4) * (16 * scale) +% shift -% ypt;\n    const day: u64 = @truncate(@as(u128, c3) * (n % (2048 * scale)) >> 64);\n\n    return .{\n        .year = @intCast(@as(i64, @bitCast(yrs)) + @as(i64, @intCast(bump))),\n        .month = @enumFromInt(month),\n        .day = @intCast(day + 1),\n    };\n}\n\ntest \"civilFromDays\" {\n    // trigger a doe and yoe range asserts if the era is not computed correctly\n    try std.testing.expectEqual(0, civilFromDays(-719469).year);\n    try std.testing.expectEqual(1970, civilFromDays(0).year);\n}\n\n/// Ben Joffe's fast overflow-safe inverse function\n/// https://www.benjoffe.com/fast-date-64\npub fn daysFromCivil(date: Date) Days {\n    const month: u32 = @intFromEnum(date.month);\n    const bump: u32 = if (month <= 2) 1 else 0;\n    const yrs: u32 = @bitCast(date.year +% 5880000 - @as(i32, @intCast(bump)));\n    const cen: u32 = yrs / 100;\n    const shift: i32 = if (bump == 1) 8829 else -2919;\n\n    const year_days: u32 = yrs * 365 + yrs / 4 - cen + cen / 4;\n    const month_days: u32 = @bitCast(@divFloor(979 * @as(i32, @intCast(month)) + shift, 32));\n    return @bitCast(year_days +% month_days +% date.day -% 2148345369);\n}\n\ntest \"daysFromCivil\" {\n    // -1 is not a leap year, so Feb 28th and Mar 1st should be 1 day apart\n    try std.testing.expectEqual(false, isLeapYear(-1));\n    try std.testing.expectEqual(\n        1,\n        daysFromCivil(.{ .year = -1, .month = .mar, .day = 1 }) -\n            daysFromCivil(.{ .year = -1, .month = .feb, .day = 28 }),\n    );\n\n    try std.testing.expectEqual(-719893, daysFromCivil(.{ .year = -1, .month = .jan, .day = 1 }));\n}\n\ntest {\n    std.testing.refAllDecls(@This());\n    _ = @import(\"timezone.zig\");\n}\n\ntest \"fmtStrftime\" {\n    var buf: [128]u8 = undefined;\n    const epoch = instant(.{ .unix_timestamp = 0 }, &utc);\n    const time = epoch.time();\n\n    var writer = std.Io.Writer.fixed(&buf);\n\n    try std.testing.expectError(error.InvalidFormat, time.strftime(&writer, \"no trailing lone percent %\"));\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%%\");\n    try std.testing.expectEqualStrings(\"%\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%a %A %b %B %c %C\");\n    try std.testing.expectEqualStrings(\"Thu Thursday Jan January Thu Jan  1 00:00:00 1970 19\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%d %D %e %F %h\");\n    try std.testing.expectEqualStrings(\"01 01/01/70  1 1970-01-01 Jan\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%H %I %j %k %l %m %M\");\n    try std.testing.expectEqualStrings(\"00 12 001 0 12 01 00\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%p %P %r %R %s %S\");\n    try std.testing.expectEqualStrings(\"AM am 12:00:00 AM 00:00 0 00\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%T %u\");\n    try std.testing.expectEqualStrings(\"00:00:00 4\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%U\");\n    try std.testing.expectEqualStrings(\"00\", writer.buffered());\n\n    writer.end = 0;\n    const d2 = (try time.instant().add(.{ .days = 3 })).time();\n    try d2.strftime(&writer, \"%U\");\n    try std.testing.expectEqualStrings(\"01\", writer.buffered());\n\n    writer.end = 0;\n    try time.strftime(&writer, \"%w %W %x %X %y %Y %z %Z\");\n    try std.testing.expectEqualStrings(\"4 00 01/01/70 00:00:00 70 1970 +0000 UTC\", writer.buffered());\n\n    writer.end = 0;\n    var d3 = time;\n    d3.offset = -3600;\n    try d3.strftime(&writer, \"%z\");\n    try std.testing.expectEqualStrings(\"-0100\", writer.buffered());\n}\n\ntest \"gofmt\" {\n    var buf: [128]u8 = undefined;\n    var writer = std.Io.Writer.fixed(&buf);\n\n    const time: Time = .{\n        .year = 1970,\n        .month = .feb,\n        .day = 3,\n        .designation = \"UTC\",\n    };\n\n    writer.end = 0;\n    try time.gofmt(&writer, \"Jan January J 01 02 03 04 05 06 002 Jan\");\n    try std.testing.expectEqualStrings(\"Feb February J 02 03 12 00 00 70 034 Feb\", writer.buffered());\n\n    writer.end = 0;\n    try time.gofmt(&writer, \"Mon Monday MST M 1 15 2 2006 _2 __2 Mon\");\n    try std.testing.expectEqualStrings(\"Tue Tuesday UTC M 2 00 3 1970  3  34 Tue\", writer.buffered());\n\n    writer.end = 0;\n    try time.gofmt(&writer, \"3 4 5\");\n    try std.testing.expectEqualStrings(\"12 0 0\", writer.buffered());\n\n    const time2: Time = .{\n        .offset = 3661, // 1 hour, 1 minute, 1 second\n        .millisecond = 123,\n        .microsecond = 456,\n        .nanosecond = 789,\n    };\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"-070000 -07:00:00 -0700 -07:00 -07 -00\");\n    try std.testing.expectEqualStrings(\"+010101 +01:01:01 +0101 +01:01 +01 -00\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"Z070000 Z07:00:00 Z0700 Z07:00 Z07 Z00\");\n    try std.testing.expectEqualStrings(\"+010101 +01:01:01 +0101 +01:01 +01 Z00\", writer.buffered());\n\n    writer.end = 0;\n    try time.gofmt(&writer, \"Z070000 Z07:00:00 Z0700 Z07:00 Z07 Z00\");\n    try std.testing.expectEqualStrings(\"Z Z Z Z Z Z00\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"frac .\");\n    try std.testing.expectEqualStrings(\"frac .\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"frac .000000000\");\n    try std.testing.expectEqualStrings(\"frac .123456789\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"frac .999999999\");\n    try std.testing.expectEqualStrings(\"frac .123456789\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"frac .000000000000\");\n    try std.testing.expectEqualStrings(\"frac .123456789000\", writer.buffered());\n\n    writer.end = 0;\n    try time2.gofmt(&writer, \"frac .0000000\");\n    try std.testing.expectEqualStrings(\"frac .1234567\", writer.buffered());\n\n    const time3: Time = .{\n        .offset = 3661, // 1 hour, 1 minute, 1 second\n        .millisecond = 123,\n        .microsecond = 456,\n    };\n\n    writer.end = 0;\n    try time3.gofmt(&writer, \"frac .999999999\");\n    try std.testing.expectEqualStrings(\"frac .123456\", writer.buffered());\n}\n\ntest \"Time.timeFmt\" {\n    const time: Time = .{\n        .year = 1970,\n        .month = .feb,\n        .day = 3,\n        .designation = \"UTC\",\n    };\n    try std.testing.expectFmt(\n        \"Feb February J 02 03 12 00 00 70 034 Feb\",\n        \"{f}\",\n        .{time.timeFmt(.gofmt, \"Jan January J 01 02 03 04 05 06 002 Jan\")},\n    );\n\n    try std.testing.expectFmt(\n        \"Tue Tuesday UTC M 2 00 3 1970  3  34 Tue\",\n        \"{f}\",\n        .{time.timeFmt(.gofmt, \"Mon Monday MST M 1 15 2 2006 _2 __2 Mon\")},\n    );\n\n    try std.testing.expectFmt(\n        \"12 0 0\",\n        \"{f}\",\n        .{time.timeFmt(.gofmt, \"3 4 5\")},\n    );\n\n    const time2: Time = .{\n        .offset = 3661, // 1 hour, 1 minute, 1 second\n        .millisecond = 123,\n        .microsecond = 456,\n        .nanosecond = 789,\n    };\n\n    try std.testing.expectFmt(\n        \"+010101 +01:01:01 +0101 +01:01 +01 -00\",\n        \"{f}\",\n        .{time2.timeFmt(.gofmt, \"-070000 -07:00:00 -0700 -07:00 -07 -00\")},\n    );\n\n    try std.testing.expectFmt(\n        \"+010101 +01:01:01 +0101 +01:01 +01 Z00\",\n        \"{f}\",\n        .{time2.timeFmt(.gofmt, \"Z070000 Z07:00:00 Z0700 Z07:00 Z07 Z00\")},\n    );\n\n    try std.testing.expectFmt(\n        \"Z Z Z Z Z Z00\",\n        \"{f}\",\n        .{time.timeFmt(.gofmt, \"Z070000 Z07:00:00 Z0700 Z07:00 Z07 Z00\")},\n    );\n\n    try std.testing.expectFmt(\n        \"frac .\",\n        \"{f}\",\n        .{time2.timeFmt(.gofmt, \"frac .\")},\n    );\n\n    const time3: Time = .{\n        .offset = 3661, // 1 hour, 1 minute, 1 second\n        .millisecond = 123,\n        .microsecond = 456,\n    };\n\n    try std.testing.expectFmt(\n        \"frac .123456\",\n        \"{f}\",\n        .{time3.timeFmt(.gofmt, \"frac .999999999\")},\n    );\n\n    const epoch = instant(.{ .unix_timestamp = 0 }, &utc);\n    const time4 = epoch.time();\n\n    var buf: [128]u8 = undefined;\n    var writer = std.Io.Writer.fixed(&buf);\n    try std.testing.expectError(error.WriteFailed, writer.print(\n        \"{f}\",\n        .{time4.timeFmt(.strftime, \"no trailing lone percent %\")},\n    ));\n\n    try std.testing.expectFmt(\n        \"%\",\n        \"{f}\",\n        .{time4.timeFmt(.strftime, \"%%\")},\n    );\n\n    try std.testing.expectFmt(\n        \"Thu Thursday Jan January Thu Jan  1 00:00:00 1970 19\",\n        \"{f}\",\n        .{time4.timeFmt(.strftime, \"%a %A %b %B %c %C\")},\n    );\n\n    try std.testing.expectFmt(\n        \"01 01/01/70  1 1970-01-01 Jan\",\n        \"{f}\",\n        .{time4.timeFmt(.strftime, \"%d %D %e %F %h\")},\n    );\n}\n\ntest Instant {\n    const zeit = @This();\n\n    const alloc = std.testing.allocator;\n\n    // Get an instant in time. The default gets \"now\" in UTC\n    const now = instant(.{ .now = std.testing.io }, &utc);\n\n    // Load our local timezone. This needs an allocator. Optionally pass in an\n    // EnvConfig to support TZ and TZDIR environment variables\n    const local_tz = try zeit.local(alloc, std.testing.io, .{});\n    defer local_tz.deinit();\n\n    // Convert our instant to a new timezone\n    const now_local = now.in(&local_tz);\n\n    // Generate date/time info for this instant\n    const dt = now_local.time();\n\n    // Print it out\n    std.log.info(\"{}\", .{dt});\n\n    // zeit.Time{\n    //    .year = 2024,\n    //    .month = zeit.Month.mar,\n    //    .day = 16,\n    //    .hour = 8,\n    //    .minute = 38,\n    //    .second = 29,\n    //    .millisecond = 496,\n    //    .microsecond = 706,\n    //    .nanosecond = 64\n    //    .offset = -18000,\n    // }\n\n    var discard_buf: [256]u8 = undefined;\n    var discarding: std.Io.Writer.Discarding = .init(&discard_buf);\n    // Format using strftime specifier. Format strings are not required to be comptime\n    try dt.strftime(&discarding.writer, \"%Y-%m-%d %H:%M:%S %Z\");\n\n    // Or...golang magic date specifiers. Format strings are not required to be comptime\n    try dt.gofmt(&discarding.writer, \"2006-01-02 15:04:05 MST\");\n\n    // Load an arbitrary location using IANA location syntax. The location name\n    // comes from an enum which will automatically map IANA location names to\n    // Windows names, as needed. Pass an optional EnvConfig to support TZDIR\n    const vienna = try zeit.loadTimeZone(alloc, std.testing.io, .@\"Europe/Vienna\", .{});\n    defer vienna.deinit();\n\n    // Parse an Instant from an ISO8601 or RFC3339 string\n    _ = try zeit.instantFromText(\n        .iso8601,\n        \"2024-03-16T08:38:29.496-1200\",\n        &utc,\n    );\n\n    _ = try zeit.instantFromText(\n        .rfc3339,\n        \"2024-03-16T08:38:29.496706064-1200\",\n        &utc,\n    );\n}\n\ntest \"github.com/rockorager/zeit/issues/15\" {\n    // https://github.com/rockorager/zeit/issues/15\n    const timestamp = 1732838300;\n    const tz = try loadTimeZone(std.testing.allocator, std.testing.io, .@\"Europe/Berlin\", .{});\n    defer tz.deinit();\n    const inst = instant(.{ .unix_timestamp = timestamp }, &tz);\n    const time = inst.time();\n\n    try std.testing.expectEqual(timestamp, time.instant().unixTimestamp());\n\n    try std.testing.expectEqual(2024, time.year);\n    try std.testing.expectEqual(Month.nov, time.month);\n    try std.testing.expectEqual(29, time.day);\n    try std.testing.expectEqual(0, time.hour);\n    try std.testing.expectEqual(58, time.minute);\n    try std.testing.expectEqual(20, time.second);\n\n    var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);\n    defer aw.deinit();\n    try time.strftime(&aw.writer, \"%a %A %u\");\n    try std.testing.expectEqualStrings(\"Fri Friday 5\", aw.writer.buffered());\n\n    aw.writer.end = 0;\n    try time.gofmt(&aw.writer, \"Mon Monday\");\n    try std.testing.expectEqualStrings(\"Fri Friday\", aw.writer.buffered());\n}\n\ntest \"github.com/rockorager/zeit/issues/27\" {\n    // April 23, 2025\n    const timestamp = 1745414170;\n    const inst = instant(.{ .unix_timestamp = timestamp }, &utc);\n\n    var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);\n    defer aw.deinit();\n\n    const time = inst.time();\n\n    try time.gofmt(&aw.writer, \"02.01.2006\");\n    try std.testing.expectEqualStrings(\"23.04.2025\", aw.writer.buffered());\n}\n\ntest \"github.com/rockorager/zeit/issues/24\" {\n    // April 23, 2025\n    const timestamp = 1745414170;\n    const inst = instant(.{ .unix_timestamp = timestamp }, &utc);\n\n    var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);\n    defer aw.deinit();\n\n    const time = inst.time();\n\n    try time.gofmt(&aw.writer, \"3pm MST\");\n    try std.testing.expectEqualStrings(\"1pm UTC\", aw.writer.buffered());\n\n    aw.writer.end = 0;\n    try time.gofmt(&aw.writer, \"3p MST\");\n    try std.testing.expectEqualStrings(\"1p UTC\", aw.writer.buffered());\n}\n\ntest \"github.com/rockorager/zeit/issues/26\" {\n    // April 23, 2025\n    const timestamp = 1745414170;\n    const inst = instant(.{ .unix_timestamp = timestamp }, &utc);\n\n    var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);\n    defer aw.deinit();\n\n    const time = inst.time();\n\n    try time.gofmt(&aw.writer, \"02nd\");\n    try std.testing.expectEqualStrings(\"23rd\", aw.writer.buffered());\n    aw.writer.end = 0;\n\n    try time.gofmt(&aw.writer, \"02ND\");\n    try std.testing.expectEqualStrings(\"23RD\", aw.writer.buffered());\n}\n\ntest \"bufPrintRFC3339Nano\" {\n    const Case = struct {\n        timestamp: []const u8,\n    };\n    const cases = [_]Case{\n        .{ .timestamp = \"2023-01-15T23:45:51.123456789Z\" },\n        .{ .timestamp = \"2023-01-15T23:45:51.000000789Z\" },\n        .{ .timestamp = \"2023-01-15T00:00:00.000000000Z\" },\n        .{ .timestamp = \"2023-01-15T00:00:00.001002003Z\" },\n    };\n    for (cases) |case| {\n        const iso = try instantFromText(\n            .rfc3339,\n            case.timestamp,\n            &utc,\n        );\n        var timeBuf: [35]u8 = undefined;\n        const time = try iso.time().bufPrint(&timeBuf, .rfc3339Nano);\n        try std.testing.expectEqualStrings(case.timestamp, time);\n    }\n}\n\ntest \"bufPrintRFC3339Nano with offset\" {\n    var timeBuf: [35]u8 = undefined;\n\n    // positive offset +05:30\n    const t1 = Time{\n        .year = 2023,\n        .month = .jan,\n        .day = 15,\n        .hour = 23,\n        .minute = 45,\n        .second = 51,\n        .millisecond = 123,\n        .microsecond = 456,\n        .nanosecond = 789,\n        .offset = 5 * 3600 + 30 * 60,\n    };\n    const s1 = try t1.bufPrint(&timeBuf, .rfc3339Nano);\n    try std.testing.expectEqualStrings(\"2023-01-15T23:45:51.123456789+05:30\", s1);\n\n    // negative offset -08:00\n    const t2 = Time{\n        .year = 2023,\n        .month = .jan,\n        .day = 15,\n        .hour = 23,\n        .minute = 45,\n        .second = 51,\n        .millisecond = 123,\n        .microsecond = 456,\n        .nanosecond = 789,\n        .offset = -(8 * 3600),\n    };\n    const s2 = try t2.bufPrint(&timeBuf, .rfc3339Nano);\n    try std.testing.expectEqualStrings(\"2023-01-15T23:45:51.123456789-08:00\", s2);\n}\n"
  }
]