410 lines
5.5 KiB
Zig
410 lines
5.5 KiB
Zig
// Auto-generated timezone offset table
|
|
// Generated by scripts/generate_timezone_table.py
|
|
//
|
|
// Maps longitude (0-359) to UTC offset in minutes
|
|
// Sampled at latitudes: 0°, 30°N, 30°S and uses most common offset
|
|
//
|
|
// ACCURACY NOTES:
|
|
// - This is a simplified longitude-only lookup for weather display purposes
|
|
// - Samples 3 latitudes per longitude and uses the most common offset
|
|
// - Works well for mid-latitudes (±30°) where most population lives
|
|
// - Can be off by 1-2.5 hours at extreme latitudes (e.g., Russia vs Australia)
|
|
// - Acceptable for "morning/afternoon/evening/night" weather labels
|
|
// - If higher accuracy is needed, modify getTimezoneOffset() to use latitude
|
|
|
|
const std = @import("std");
|
|
|
|
const Coordinates = @import("../Coordinates.zig");
|
|
|
|
/// Timezone offset in minutes from UTC for each degree of longitude (0-359)
|
|
/// Negative values = west of UTC, positive = east of UTC
|
|
pub const timezone_offsets: [360]i16 = .{
|
|
720,
|
|
-720,
|
|
-720,
|
|
-720,
|
|
-720,
|
|
-720,
|
|
-720,
|
|
-720,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-660,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-600,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-540,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-480,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-420,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-360,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-300,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-240,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-180,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-120,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
-60,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
60,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
120,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
180,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
240,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
300,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
360,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
420,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
480,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
540,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
600,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
660,
|
|
720,
|
|
720,
|
|
720,
|
|
720,
|
|
720,
|
|
720,
|
|
720,
|
|
};
|
|
|
|
/// Get timezone offset in minutes for given coordinates
|
|
/// Currently only uses longitude; latitude is available for future improvements
|
|
/// coords: Location coordinates
|
|
/// Returns: offset in minutes from UTC
|
|
pub fn getTimezoneOffset(coords: Coordinates) i16 {
|
|
// Currently only uses longitude (see ACCURACY NOTES above)
|
|
// Latitude could be used in future for better accuracy at extreme latitudes
|
|
_ = coords.latitude;
|
|
|
|
// Normalize longitude to 0-359
|
|
const normalized = @mod(@as(i32, @intFromFloat(@round(coords.longitude))) + 180, 360);
|
|
return timezone_offsets[@intCast(normalized)];
|
|
}
|
|
|
|
test "timezone offset lookup" {
|
|
// London (0°) should be close to UTC
|
|
const london_offset = getTimezoneOffset(.{ .latitude = 51.5, .longitude = 0.0 });
|
|
try std.testing.expect(london_offset >= -60 and london_offset <= 60);
|
|
|
|
// New York (-74°) should be around UTC-5 (-300 minutes)
|
|
const ny_offset = getTimezoneOffset(.{ .latitude = 40.7, .longitude = -74.0 });
|
|
try std.testing.expect(ny_offset >= -360 and ny_offset <= -240);
|
|
|
|
// Tokyo (139°) should be around UTC+9 (540 minutes)
|
|
const tokyo_offset = getTimezoneOffset(.{ .latitude = 35.7, .longitude = 139.0 });
|
|
try std.testing.expect(tokyo_offset >= 480 and tokyo_offset <= 600);
|
|
}
|