wttr/scripts/generate_timezone_table.sh

128 lines
3.7 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Generate timezone offset lookup table based on longitude
# Samples at multiple latitudes to handle political boundaries
set -e
OUTPUT_FILE="src/location/timezone_offsets.zig"
TEMP_FILE=$(mktemp)
# Latitudes to sample (equator, +/-30)
LATITUDES=(0 30 -30)
echo "Generating timezone offset table..."
echo "This will make 1080 API calls (360 longitudes × 3 latitudes)"
echo
# Start the output file
cat > "$TEMP_FILE" << 'EOF'
// Auto-generated timezone offset table
// Generated by scripts/generate_timezone_table.sh
//
// Maps longitude (0-359) to UTC offset in minutes
// Sampled at latitudes: 0°, 30°N, 30°S and uses most common offset
const std = @import("std");
/// 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 = .{
EOF
# For each longitude
for lon in {-180..179}; do
# Normalize to 0-359 for array index
array_idx=$((lon + 180))
echo -n "Processing longitude $lon ($((array_idx + 1))/360)..." >&2
# Collect offsets from all latitudes
declare -A offset_counts
for lat in "${LATITUDES[@]}"; do
# Query the API
response=$(curl -s "https://tools.maximmaeder.com/t/get-timezone-by-coordinates/?latitude=$lat&longitude=$lon")
# Extract offset (format: "UTC+05:30" or "UTC-08:00")
offset=$(echo "$response" | grep -oP 'UTC[+-]\d{2}:\d{2}' | head -1)
if [ -z "$offset" ]; then
echo " failed to get timezone for lat=$lat, lon=$lon" >&2
continue
fi
# Convert to minutes
sign=$(echo "$offset" | grep -oP '[+-]')
hours=$(echo "$offset" | grep -oP '\d{2}' | head -1)
mins=$(echo "$offset" | grep -oP '\d{2}' | tail -1)
total_mins=$((hours * 60 + mins))
if [ "$sign" = "-" ]; then
total_mins=$((total_mins * -1))
fi
# Count occurrences
offset_counts[$total_mins]=$((${offset_counts[$total_mins]:-0} + 1))
# Rate limit
sleep 0.1
done
# Find most common offset
max_count=0
most_common_offset=0
for offset in "${!offset_counts[@]}"; do
if [ "${offset_counts[$offset]}" -gt "$max_count" ]; then
max_count="${offset_counts[$offset]}"
most_common_offset="$offset"
fi
done
echo "${most_common_offset} minutes" >&2
# Add to array (with comma except for last element)
if [ "$array_idx" -eq 359 ]; then
echo " $most_common_offset," >> "$TEMP_FILE"
else
echo " $most_common_offset," >> "$TEMP_FILE"
fi
unset offset_counts
done
# Close the array
cat >> "$TEMP_FILE" << 'EOF'
};
/// Get timezone offset in minutes for a given longitude
/// longitude: -180 to 180
/// Returns: offset in minutes from UTC
pub fn getTimezoneOffset(longitude: f32) i16 {
// Normalize to 0-359
const normalized = @mod(@as(i32, @intFromFloat(@round(longitude))) + 180, 360);
return timezone_offsets[@intCast(normalized)];
}
test "timezone offset lookup" {
// London (0°) should be close to UTC
const london_offset = getTimezoneOffset(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(-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(139.0);
try std.testing.expect(tokyo_offset >= 480 and tokyo_offset <= 600);
}
EOF
# Move to final location
mv "$TEMP_FILE" "$OUTPUT_FILE"
echo
echo "Generated $OUTPUT_FILE"
echo "Running zig fmt..."
zig fmt "$OUTPUT_FILE"
echo "Done!"