Date & Time Reference
Event timing is critically important for an amateur radio club. Members need to know exactly when meetings start, contests run, and field days happen—often across timezone boundaries. This page documents how we handle all date/time concerns to ensure accuracy and usability.
Design Principles
- Dates are calendar dates. When someone says "the meeting is January 20th," they mean the calendar date, not a UTC timestamp that might resolve to a different day depending on timezone.
- Times display in context. Event times show in the event's timezone by default, but users can toggle to see their local time or UTC.
- Timezone derives from venue. If you specify a venue, the timezone comes from that
venue's configuration. You only need explicit
timezonefor events at unusual locations. - Categorization adapts to viewer. "Upcoming" vs "past" is determined client-side based on the viewer's actual time, not the server's build time.
Calendar Dates vs Timestamps
The eventDate field is stored as a calendar date, not a
timezone-aware timestamp. Internally, it's represented as midnight UTC on that date, but we
always render it as a pure calendar date (ignoring the time component).
Why this matters: If you store "January 20, 2026" as a UTC timestamp and a user
in Hawaii views the page, JavaScript's
toLocaleDateString() would show "January 19" (because midnight UTC is still the previous
day in HST). By treating it as a calendar date, January 20 is always January 20, regardless of
viewer timezone.
In frontmatter, specify dates without time components:
eventDate: 2026-01-20
endDate: 2026-01-21 Timezone Resolution
The timezone for an event is determined by this priority chain:
- Explicit
timezonefield — highest priority - Venue's configured timezone — from
site.config.ts - Site default —
America/Los_Angeles
// Most events: timezone comes from venue
venue: "building-31" // → America/Los_Angeles
// Override for unusual cases
venue: "building-31"
timezone: "America/Denver" // Explicit override
// No venue: falls back to site default
customVenue:
name: "Special Location"
address: "123 Main St" This means contributors rarely need to think about timezones. Just specify the venue, and the correct timezone is applied automatically.
Supported Timezones
We use IANA timezone identifiers, which are recognized worldwide and handle daylight saving time automatically. Common US timezones:
| IANA Identifier | Common Name | UTC Offset (Winter) |
|---|---|---|
America/Los_Angeles | Pacific Time | UTC-8 |
America/Denver | Mountain Time | UTC-7 |
America/Chicago | Central Time | UTC-6 |
America/New_York | Eastern Time | UTC-5 |
America/Phoenix | Arizona (no DST) | UTC-7 |
Pacific/Honolulu | Hawaii (no DST) | UTC-10 |
Why not PST/PDT? Abbreviations like "PST" are ambiguous (Pakistan Standard Time
also uses PST) and don't automatically switch for daylight saving. America/Los_Angeles
is unambiguous and handles DST transitions correctly.
Interactive Time Toggle
On event detail pages, clicking the date/time line toggles between display modes. Try it yourself:
Click to toggle between your local time and UTC:
| Mode | Display | Use Case |
|---|---|---|
| Local (default) | User's browser timezone | When is this event for me? |
| UTC | Coordinated Universal Time | Contest logs, satellite passes, DXpeditions |
The toggle is implemented as a <button> with
data-event-datetime attributes. JavaScript reads the event's ISO date, start time, end
time, and timezone, then recalculates the display for the target timezone.
How Time Conversion Works
Converting "6:00 PM Pacific" to UTC requires knowing the actual UTC instant that corresponds to 6 PM in Pacific time on that calendar date. The code:
- Takes the calendar date (e.g., Jan 20, 2026)
- Parses the time string (e.g., "6:00 PM" → 18:00)
- Constructs what that time means in the event's timezone
- Calculates the corresponding UTC instant
- Formats that instant in the target timezone
This handles DST transitions correctly because we use Intl.DateTimeFormat
with explicit IANA timezone identifiers, not fixed offsets.
Event Categorization
The events listing page divides events into three categories:
| Category | Condition | Display |
|---|---|---|
| Happening Now | start ≤ now ≤ end | Highlighted section, join buttons |
| Upcoming | start > now | Soonest first, join buttons |
| Past | end < now | Most recent first, compact cards |
Timestamp Calculation
For categorization, we need actual timestamps (not just calendar dates). The event timestamp is calculated as:
start = eventDate + startTime (or midnight if no startTime)
end = endDate + endTime (or end of day on eventDate/endDate) Build time vs runtime: At build time, events are categorized based on the server's clock. This categorization is then corrected client-side to match the viewer's actual time. See the next section.
Client-Side Re-sorting
Because Astro generates static HTML at build time, an event that's "upcoming" when the site is built might be "happening now" or "past" when someone views the page hours or days later.
The events listing page includes a client-side script that:
-
Reads
data-event-timestampanddata-event-endfrom each event card - Compares against the viewer's current
Date.now() - Moves event cards between the "Happening Now", "Upcoming", and "Past" sections
- Re-sorts within each section (soonest first for upcoming, most recent first for past)
- Runs every 60 seconds to catch events that start/end while the page is open
This means even if a page was built days ago, users always see the correct categorization when they view it.
Multi-Day Events
Field Days, contests, and conventions often span multiple days. The schema supports this with endDate:
---
title: "Winter Field Day"
eventDate: 2026-01-25
startTime: "11:00 AM"
endDate: 2026-01-26
endTime: "11:00 AM"
--- Multi-day events show as "Happening Now" for the entire duration, from the start time on the first day through the end time on the last day.
Format Configuration
Date and time formats are centralized in site.config.ts under
dateTimeFormats:
| Key | Use | Example Output |
|---|---|---|
dateLong | Event detail pages | Monday, January 20, 2026 |
dateShort | Card headers | January 20, 2026 |
dateCompact | Inline references | Jan 20 |
All formatting uses Intl.DateTimeFormat with the site's configured locale (en-US). This ensures consistent, locale-appropriate formatting throughout the site.