计算时区偏移:实现用户本地8点邮件发送的时区筛选问题
Let's break down why your original function fails and how to fix it. The core issue is that your current calculation doesn't account for the 24-hour cyclic nature of time and the valid range of real-world UTC offsets (which spans from -12 to +14, covering edge cases like UTC+14/Line Islands and UTC-12/Baker Island).
The Correct Approach
We need to find all UTC offsets where currentUTC + offset ≡ targetLocalHour (mod 24)—meaning adding the offset to the current UTC hour lands us at the target local time—while ensuring those offsets fall within the valid range of real-world timezones. Here's a revised function that handles this properly:
function getValidUTCOffsets(targetLocalHour, currentUTCHour) { const validOffsets = []; // Calculate the base offset using the core formula let baseOffset = targetLocalHour - currentUTCHour; // Check the base offset and its ±24 equivalents (since adding/subtracting 24h gives the same local time) const possibleOffsets = [baseOffset, baseOffset + 24, baseOffset - 24]; // Filter to only keep offsets that exist in real-world timezones for (const offset of possibleOffsets) { if (offset >= -12 && offset <= 14) { validOffsets.push(offset); } } // Remove duplicates (in case the base offset is already valid and ±24 isn't needed) return [...new Set(validOffsets)]; }
How It Works
- Base Offset Calculation: Start with the same core logic
targetLocalHour - currentUTCHourto get a starting point. - Cyclic Adjustment: Since adding or subtracting 24 hours to an offset results in the same local time (a full day cycle), we check these three possible offset values.
- Validation: We only keep offsets that fall within the real-world valid range (-12 to +14). This eliminates invalid values like -13 or -15, and captures both valid offsets when they exist (like -10 and +14 for UTC 18:00).
Testing the Function
Let's run this against your original test cases to verify it fixes all the issues:
console.log('At 12am UTC: ' + getValidUTCOffsets(8, 0)); // [8] ✔️ console.log('At 1am UTC: ' + getValidUTCOffsets(8, 1)); // [7] ✔️ console.log('At 8am UTC: ' + getValidUTCOffsets(8, 8)); // [0] ✔️ console.log('At 9am UTC: ' + getValidUTCOffsets(8, 9)); // [-1] ✔️ console.log('At 1pm UTC: ' + getValidUTCOffsets(8, 13)); // [-5] ✔️ console.log('At 3pm UTC: ' + getValidUTCOffsets(8, 15)); // [-7] ✔️ console.log('At 6pm UTC: ' + getValidUTCOffsets(8, 18)); // [-10, 14] ✔️ (matches expected) console.log('At 8pm UTC: ' + getValidUTCOffsets(8, 20)); // [-12, 12] ✔️ (matches expected) console.log('At 9pm UTC: ' + getValidUTCOffsets(8, 21)); // [11] ✔️ (invalid -13 is discarded, +11 is kept) console.log('At 11pm UTC: ' + getValidUTCOffsets(8, 23)); // [9] ✔️ (invalid -15 is discarded, +9 is kept)
All test cases now return the correct valid offsets!
Key Notes
- The valid UTC offset range (-12 to +14) covers all IANA timezones, including the most extreme ones used in remote islands.
- Using a
Setto remove duplicates ensures we don't return the same offset multiple times (this only happens if the base offset is already valid and its ±24 equivalents fall outside the valid range).
内容的提问来源于stack exchange,提问作者HJo

