Skip to content

feat: timezone support for huddlz (storage, input, display) #192

@mwoods79

Description

@mwoods79

Summary

We don't currently support timezones. Huddl times are stored as
:utc_datetime, form inputs are interpreted as UTC, and every display
path (cards, hero, organize tables, calendar) formats the UTC value
directly via Calendar.strftime/2 with no shift. Users see times in
UTC, not in their local zone.

Current state

  • Huddlz.Communities.Huddlstarts_at and ends_at are
    :utc_datetime. Correct as canonical storage.
  • Huddlz.Communities.Huddl.Changes.CalculateDateTimeFromInputs builds
    the datetime as DateTime.new(date, time, "Etc/UTC") and the source
    comment explicitly flags this:

    "Assuming the user's input is in their local timezone, we'll use UTC
    for now. In a real app, you'd want to handle timezone conversion
    properly."

  • LiveViews format UTC directly: lib/huddlz_web/live/huddl_live.ex
    (huddl_month, huddl_day, format_meta_when),
    lib/huddlz_web/components/community_components.ex (format_datetime),
    lib/huddlz_web/live/organize_live.ex (multiple helpers),
    lib/huddlz_web/live/huddl_live/show.ex, etc.
  • The notification path is the one place that DOES localize:
    lib/huddlz/notifications/date_time_formatter.ex calls
    DateTime.shift_zone/2 against a time_zone from the payload. So
    emails will format correctly if a TZ is supplied — but no caller
    currently supplies one.
  • Tzdata is already a dependency (mix.exs) and configured
    (config/config.exs sets :time_zone_database, Tzdata.TimeZoneDatabase).
  • No timezone field on User, Group, or Huddl.

Concrete bug

A huddl scheduled by a Phoenix-area organizer for "May 21 at 7:00 PM"
gets stored as 2026-05-22 02:00:00Z because the form input is
interpreted as UTC. On the discover card, huddl_month /
huddl_day strftime that UTC datetime — so an Arizona viewer (UTC-7)
sees the date stamp MAY 22 and the meta line Wed · 2:00 AM, instead
of MAY 21 / Thu · 7:00 PM.

Proposed direction

Big enough to warrant a small design pass before code; rough shape:

  1. Add time_zone to Huddl (string, IANA name e.g.
    America/Phoenix), defaulting from the group's TZ at create time.
    Decide whether per-huddl override is allowed or whether it always
    inherits from the group.
  2. Add time_zone to Group so the organizer sets it once when
    creating the group; defaults to the group's geocoded location's TZ
    (we already geocode location to lat/lng — pair that with a TZ
    lookup, or just ask the organizer).
  3. Form input handling — interpret date + start_time as wall
    time in the huddl's TZ, then convert to UTC for storage. Replace the
    DateTime.new(..., "Etc/UTC") call in
    CalculateDateTimeFromInputs with DateTime.new(date, time, time_zone).
  4. Display — every formatter that takes a %DateTime{} shifts to
    the huddl's TZ (or the viewer's TZ, if we add one) before strftime.
    Probably worth extracting a Huddlz.DateTimeFormatter (or
    generalizing Huddlz.Notifications.DateTimeFormatter) so there's
    one place to enforce the rule.
  5. Optional: user preference. Store time_zone on User and let
    users opt to view all huddl times in their preferred TZ. Lower
    priority than Component standardization (cards, buttons, forms) #1–4 — most users expect huddl times in the host's TZ
    anyway.
  6. Notifier wiring — supply the huddl's time_zone to the
    notification payloads so the existing DateTimeFormatter actually
    gets a non-default value.
  7. Backfill — for existing huddlz, decide whether to assume a
    default TZ (we can probably get away with a one-shot script that
    sets every existing huddl's TZ to the group's TZ once Design system documentation #2 lands; the
    stored UTC stays correct only if the original input was already in
    UTC, which it isn't for any human-organized huddl. So: data fix
    needed too. Small project, the practical move is probably "ask the
    couple of test organizers to re-save").

Out of scope (file separately if pursued)

  • DST-boundary recurring huddlz — a weekly series spanning a DST switch
    needs special handling (does the local wall time stay constant or
    does the UTC offset stay constant?). The recurrence helper currently
    just adds a fixed Duration in UTC.
  • Calendar export / iCal feeds — once we have TZ info, .ics outputs
    should include TZID blocks.

Notes for whoever picks this up

  • Notifications already work — Huddlz.Notifications.DateTimeFormatter
    is the template for what every other display path should look like.
  • Test fixtures (test/support/generator.ex) build datetimes with
    DateTime.add(DateTime.utc_now(), …) — those'll need a TZ-aware
    variant once time_zone becomes part of the schema.
  • tzdata is already in deps; nothing new to add there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions