#!/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!"