Skip to content

Feature/add timezone converter tool - #432

Merged
shamilahmdt merged 5 commits into
shamilahmdt:mainfrom
Vikkesh:feature/add-timezone-converter-tool
Jul 28, 2026
Merged

Feature/add timezone converter tool#432
shamilahmdt merged 5 commits into
shamilahmdt:mainfrom
Vikkesh:feature/add-timezone-converter-tool

Conversation

@Vikkesh

@Vikkesh Vikkesh commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

📝 Description

Adds a new Timezone Converter utility to the Dev Utilities Sandbox. It's fully client-side (no backend calls), built entirely on the Intl API, and follows the existing Dev Utilities design conventions (monochrome, light/dark theme, card + sidebar registration).

Beyond a basic converter, it also includes:

  • World Clock — pick a source timezone and a date/time (or use live current time), and see that instant converted across a pinnable list of zones, each showing formatted local time and UTC offset.
  • Meeting Overlap Finder — set a working-hours window (default 09:00–18:00) and the tool shows a 24-hour grid per pinned zone, plus a summary of which UTC hours fall inside working hours for every pinned zone simultaneously — answers "is there a time that works for everyone?"
  • Persisted pinned zones — the pinned zone list is saved to localStorage (same pattern as the existing favorite-utilities feature) so it survives page reloads instead of resetting to defaults.
  • DST indicator — flags any pinned zone currently observing daylight saving time, since a zone's UTC offset silently shifts twice a year and is a common source of scheduling mistakes.

Files changed

  • src/pages/DevUtilities/devutilities/TimezoneConverter.jsx (new) — the tool component: conversion logic (localToUtcIso, getOffsetMinutes), DST detection (isObservingDst), the overlap-finder grid (overlapGrid, collapseHourRanges), and localStorage persistence for pinned zones.
  • src/App.jsx — imports the component and registers the route /devutilities/timezone-converter.
  • src/config/sidebarSections.js — adds the sidebar nav entry under Dev Utilities.
  • src/pages/DevUtilities/DevUtilities.jsx — adds the tool's card (title, description, search keywords, icon) to the Dev Utilities home grid.

🔗 Related Issue

Closes #193

🎯 Type of Change

  • fix: Bug fix
  • feat: New feature
  • style: UI/Theme changes (Monochrome)
  • chore: Build/Maintenance

✅ Checklist

  • Follows project's Monochrome design (Black/Grey/White) 🎨
  • Follows Conventional Commits 📜
  • Added screenshots (if UI was changed) 📸
  • Tested locally on the latest version 🧪

📸 Screenshots (if applicable)

| Before | After |
image
image
image

| | |

Vikkesh added 5 commits July 27, 2026 23:37
Implements the Timezone Converter tool for issue shamilahmdt#193 (Add a New Tool to
Dev Utilities Sandbox), following the existing Dev Utilities patterns:
tool component, sidebar entry, home-grid card, and route registration.

- src/pages/DevUtilities/devutilities/TimezoneConverter.jsx (new):
  Client-side timezone converter and live world clock built entirely on
  the Intl API (no backend/network calls). Lets a user pick a source
  timezone and a date/time (or use the live current time), then view
  that instant rendered across a pinnable list of world clock
  timezones. Includes a `localToUtcIso` helper that resolves a wall-clock
  date/time typed in a given timezone to the correct UTC instant via an
  offset-correction loop (handles DST correctly), and a `formatInZone`
  helper that renders a date plus its UTC offset for an arbitrary
  timezone. Falls back to a static list of common timezones when
  `Intl.supportedValuesOf` is unavailable. Matches the existing
  light/dark theme conventions used by sibling tools such as
  TimestampConverter.

- src/App.jsx: Imports the new TimezoneConverter component and registers
  its route at /devutilities/timezone-converter, alongside the existing
  /devutilities/timestamp route.

- src/config/sidebarSections.js: Adds a "Timezone Converter" entry to the
  Dev Utilities sidebar section so the tool is reachable from the app
  navigation.

- src/pages/DevUtilities/DevUtilities.jsx: Adds a "Timezone Converter"
  card to the Dev Utilities home grid, with title, description, search
  keywords, and icon, positioned next to the Timestamp card.
Adds a "Meeting Overlap Finder" section to the Timezone Converter tool
so it can answer the actual scheduling question users have when
comparing timezones: "is there a time that works for everyone?"

- src/pages/DevUtilities/devutilities/TimezoneConverter.jsx:
  - New `getLocalHour(date, timeZone)` helper: returns the local
    hour-of-day (0-23) for a given instant in an arbitrary IANA
    timezone, using Intl.DateTimeFormat with hourCycle "h23".
  - New `collapseHourRanges(hours)` helper: takes a set of individually
    "true" hour indices and collapses contiguous runs into readable
    "HH:00–HH:00" range strings (e.g. turns [14,15,16] into
    "14:00–17:00") so overlap results read as ranges instead of a list
    of matching hours.
  - New `workStart` / `workEnd` state (default 09:00–18:00), with two
    dropdowns in the UI to configure the working-hours window that
    applies to every pinned zone's own local time.
  - New `overlapGrid` memo: builds a 24-hour grid anchored to the UTC
    calendar day of the current reference date/time. For each of the
    24 UTC hours, it computes each pinned zone's local hour and
    whether that hour falls inside [workStart, workEnd) for that zone,
    then flags the hour as a full overlap when every pinned zone is
    simultaneously in its working window. Recomputes whenever the
    reference date, pinned zones, or working-hour bounds change.
  - New UI: a horizontal per-zone hour grid (green cells = inside that
    zone's working hours, muted cells = outside), an "All zones (UTC)"
    summary row that outlines the hours where every zone overlaps, and
    a results banner listing the collapsed overlap ranges in UTC (or a
    message when no such hour exists). The grid scrolls horizontally
    on narrow viewports via `overflow-x-auto`.
Previously the world clock's pinned zone list always reset to the same
5 hardcoded defaults (UTC, America/New_York, Europe/London, Asia/Kolkata,
Asia/Tokyo) on every page load/reload, discarding any zones the user
added or removed. This mirrors the localStorage pattern already used
for favorite utilities in src/pages/DevUtilities/DevUtilities.jsx
(FAVORITES_STORAGE_KEY / lazy useState initializer / mirroring effect)
so pinned zones behave the same way.

- src/pages/DevUtilities/devutilities/TimezoneConverter.jsx:
  - Added `PINNED_ZONES_STORAGE_KEY` ("timezone_converter_pinned_zones")
    and extracted the previous hardcoded default array into
    `DEFAULT_PINNED_ZONES`.
  - Added `loadPinnedZones()`, used as the lazy initializer for the
    `pinnedZones` state: reads and JSON-parses the saved list from
    localStorage, guards against `window` being undefined (SSR/build
    safety), and falls back to `DEFAULT_PINNED_ZONES` if the value is
    missing, invalid JSON, not an array, empty, or fails to parse
    (logging the error rather than throwing).
  - Added a `useEffect` that writes `pinnedZones` back to localStorage
    as JSON every time the list changes (zone added or removed via
    the existing `addZone` / `removeZone` handlers), so the list
    survives page reloads and future visits.
Adds a "DST" badge to each pinned zone in the World Clock so users can
tell at a glance which zones are currently offset by daylight saving
time, since that's a common source of scheduling mistakes (a zone's
UTC offset silently shifts twice a year).

- src/pages/DevUtilities/devutilities/TimezoneConverter.jsx:
  - Extracted a shared `getOffsetMinutes(date, timeZone)` helper that
    returns a zone's UTC offset in minutes (positive = ahead of UTC)
    at a given instant, by diffing the zone's wall-clock reading
    (via Intl.DateTimeFormat.formatToParts) against the instant's
    actual UTC time.
  - Refactored `localToUtcIso`'s offset-correction loop to use
    `getOffsetMinutes` instead of duplicating the same
    formatToParts/Date.UTC logic inline; behavior is unchanged
    (verified by re-deriving the same wall-clock -> UTC instant for
    both a UTC+5:30 zone and a zone with a non-integer historical
    offset case via DST, e.g. Asia/Kolkata and America/New_York).
  - Added `isObservingDst(date, timeZone)`: samples a zone's offset in
    January and July of the reference date's year. Since DST always
    shifts local clocks forward relative to standard time (regardless
    of hemisphere/season labelling), the smaller of the two sampled
    offsets is the zone's standard offset; a zone is "in DST" at the
    given date when its current offset exceeds that standard offset.
    Zones that don't observe DST have identical Jan/Jul samples and
    always return false.
  - World Clock rows now compute `isObservingDst(referenceDate, zone)`
    per pinned zone and render an amber "DST" pill next to the zone
    name when true, with a title tooltip explaining what it means.
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

@Vikkesh is attempting to deploy a commit to the shamilahmdt's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

Copy link
Copy Markdown

👋 Hello, @Vikkesh!

Thank you for your contribution to DevTasks.

The maintainer has been notified and will review your pull request shortly. If any changes are needed, we will let you know in the comments below.

@shamilahmdt
shamilahmdt merged commit 988ec68 into shamilahmdt:main Jul 28, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🟢 Good First Issue: Add a New Tool to Dev Utilities Sandbox

2 participants