-
Notifications
You must be signed in to change notification settings - Fork 0
Fix DST timezone selection: Add "+" buttons to search, expand modal for timezone choice, and modernize with Temporal API #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
e195214
74bd097
172131f
88c5e14
ab8d79b
42a0a9f
982a750
4adb0db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -85,7 +85,7 @@ export function getUserTimezone(date?: Date): TimeZone { | |||||||||||||||||||||||||
| // Get user's timezone ID using Temporal (polyfill ensures availability) | ||||||||||||||||||||||||||
| const userTimezone = Temporal.Now.timeZoneId(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const now = date || new Date(); | ||||||||||||||||||||||||||
| const now = date || new Date(Temporal.Now.instant().epochMilliseconds); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Use Intl for offset calculation (proven compatibility) | ||||||||||||||||||||||||||
| const formatter = new Intl.DateTimeFormat('en', { | ||||||||||||||||||||||||||
|
|
@@ -421,7 +421,7 @@ function getTimezoneAbbreviation(displayName: string, iana: string, date?: Date) | |||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Format the provided date (or current date) and extract the timezone abbreviation | ||||||||||||||||||||||||||
| const parts = formatter.formatToParts(date || new Date()); | ||||||||||||||||||||||||||
| const parts = formatter.formatToParts(date || new Date(Temporal.Now.instant().epochMilliseconds)); | ||||||||||||||||||||||||||
| const timeZonePart = parts.find(part => part.type === 'timeZoneName'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (timeZonePart && timeZonePart.value && timeZonePart.value.length <= 5) { | ||||||||||||||||||||||||||
|
|
@@ -469,7 +469,7 @@ function createTimezoneDisplayName(iana: string, offset: number, date?: Date): s | |||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Get the timezone name from the provided date (or current date) | ||||||||||||||||||||||||||
| const parts = formatter.formatToParts(date || new Date()); | ||||||||||||||||||||||||||
| const parts = formatter.formatToParts(date || new Date(Temporal.Now.instant().epochMilliseconds)); | ||||||||||||||||||||||||||
| const timeZonePart = parts.find(part => part.type === 'timeZoneName'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (timeZonePart && timeZonePart.value) { | ||||||||||||||||||||||||||
|
|
@@ -513,7 +513,7 @@ function formatOffset(offset: number): string { | |||||||||||||||||||||||||
| * @returns Array of timeline hours with daylight information and date transitions | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| export function generateTimelineHours(numHours: number, timezone: TimeZone, baseDate?: Date): TimelineHour[] { | ||||||||||||||||||||||||||
| const now = baseDate || new Date(); | ||||||||||||||||||||||||||
| const now = baseDate || new Date(Temporal.Now.instant().epochMilliseconds); | ||||||||||||||||||||||||||
| const userTz = getUserTimezone(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Get current hour in user's timezone and round down | ||||||||||||||||||||||||||
|
|
@@ -924,7 +924,7 @@ export class TimelineManager { | |||||||||||||||||||||||||
| private modal: TimezoneModal; | ||||||||||||||||||||||||||
| private dateTimeModal: DateTimeModal; | ||||||||||||||||||||||||||
| private selectedTimezones: TimeZone[] = []; | ||||||||||||||||||||||||||
| private selectedDate: Date = new Date(); // Default to today | ||||||||||||||||||||||||||
| private selectedDate: Date = new Date(Temporal.Now.instant().epochMilliseconds); // Default to today | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| constructor() { | ||||||||||||||||||||||||||
| this.container = document.getElementById('timeline-container') as HTMLElement; | ||||||||||||||||||||||||||
|
|
@@ -1323,15 +1323,17 @@ function saveTimezoneCache(): void { | |||||||||||||||||||||||||
| * Initialize timezone data by processing all browser timezones for June and December | ||||||||||||||||||||||||||
| * This expensive operation should only be done once on page load | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| function initializeTimezoneData(year: number = new Date().getFullYear()): ProcessedTimezoneData { | ||||||||||||||||||||||||||
| function initializeTimezoneData(year: number = Temporal.Now.plainDateISO().year): ProcessedTimezoneData { | ||||||||||||||||||||||||||
| const userTimezone = Temporal.Now.timeZoneId(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Get all supported timezones (comprehensive list) | ||||||||||||||||||||||||||
| const allTimezones = Intl.supportedValuesOf('timeZone'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Create dates for June 1st and December 31st to capture DST variations | ||||||||||||||||||||||||||
| const juneDate = new Date(year, 5, 1); // June 1st | ||||||||||||||||||||||||||
| const decemberDate = new Date(year, 11, 31); // December 31st | ||||||||||||||||||||||||||
| // Create dates for June 1st and December 31st to capture DST variations using Temporal | ||||||||||||||||||||||||||
| const junePlainDate = Temporal.PlainDate.from({ year, month: 6, day: 1 }); | ||||||||||||||||||||||||||
| const decemberPlainDate = Temporal.PlainDate.from({ year, month: 12, day: 31 }); | ||||||||||||||||||||||||||
| const juneDate = new Date(junePlainDate.toZonedDateTime('UTC').epochMilliseconds); | ||||||||||||||||||||||||||
| const decemberDate = new Date(decemberPlainDate.toZonedDateTime('UTC').epochMilliseconds); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| console.log(`Processing ${allTimezones.length} timezones for June and December variants...`); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -1464,7 +1466,7 @@ function getTimezoneSetForDate(date: Date, processedData: ProcessedTimezoneData) | |||||||||||||||||||||||||
| * @returns Array of timezone objects ordered from user's timezone around the globe | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| export function getAllTimezonesOrdered(date?: Date): TimeZone[] { | ||||||||||||||||||||||||||
| const now = date || new Date(); | ||||||||||||||||||||||||||
| const now = date || new Date(Temporal.Now.instant().epochMilliseconds); | ||||||||||||||||||||||||||
| const currentYear = now.getFullYear(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Load cache from localStorage on first call | ||||||||||||||||||||||||||
|
|
@@ -1496,12 +1498,16 @@ export function getAllTimezonesOrdered(date?: Date): TimeZone[] { | |||||||||||||||||||||||||
| * Get timezone variations for a given IANA identifier using fixed dates | ||||||||||||||||||||||||||
| * Returns both summer (June 1st) and winter (December 31st) variations | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| function getTimezoneVariations(iana: string, year: number = new Date().getFullYear()): TimeZone[] { | ||||||||||||||||||||||||||
| function getTimezoneVariations(iana: string, year: number = Temporal.Now.plainDateISO().year): TimeZone[] { | ||||||||||||||||||||||||||
| const variations: TimeZone[] = []; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Use June 1st for summer time and December 31st for winter time | ||||||||||||||||||||||||||
| const summerDate = new Date(year, 5, 1); // June 1st | ||||||||||||||||||||||||||
| const winterDate = new Date(year, 11, 31); // December 31st | ||||||||||||||||||||||||||
| // Use June 1st for summer time and December 31st for winter time using Temporal | ||||||||||||||||||||||||||
| const summerPlainDate = Temporal.PlainDate.from({ year, month: 6, day: 1 }); | ||||||||||||||||||||||||||
| const winterPlainDate = Temporal.PlainDate.from({ year, month: 12, day: 31 }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Convert to Date objects for Intl.DateTimeFormat compatibility using the target timezone | ||||||||||||||||||||||||||
| const summerDate = new Date(summerPlainDate.toZonedDateTime(iana).epochMilliseconds); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| const winterDate = new Date(winterPlainDate.toZonedDateTime(iana).epochMilliseconds); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for (const date of [summerDate, winterDate]) { | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| // Convert to Date objects for Intl.DateTimeFormat compatibility using the target timezone | |
| const summerDate = new Date(summerPlainDate.toZonedDateTime(iana).epochMilliseconds); | |
| const winterDate = new Date(winterPlainDate.toZonedDateTime(iana).epochMilliseconds); | |
| for (const date of [summerDate, winterDate]) { | |
| // Use Temporal.ZonedDateTime objects directly for formatting and calculations | |
| const summerZdt = summerPlainDate.toZonedDateTime(iana); | |
| const winterZdt = winterPlainDate.toZonedDateTime(iana); | |
| for (const zdt of [summerZdt, winterZdt]) { | |
| // For Intl.DateTimeFormat, convert to Date using the UTC instant | |
| const date = new Date(zdt.toInstant().epochMilliseconds); |
Uh oh!
There was an error while loading. Please reload this page.