]> git.za3k.com Git - za3k.git/commitdiff
Show where you are in tz chart master github/master
authorZachary Vance <za3k@za3k.com>
Wed, 16 Sep 2026 18:08:32 +0000 (14:08 -0400)
committerZachary Vance <za3k@za3k.com>
Wed, 16 Sep 2026 18:08:32 +0000 (14:08 -0400)
archive/tz.html

index 0bdfa526eafef29a03148a1cfbf7e2e06aecea4e..79ca0085acef66d144b715717f8ba8ceb31044b7 100644 (file)
@@ -3,7 +3,7 @@
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
-<title>Time Zone Conversion Chart</title>
+<title>Time Zone Conversion Chart — Live</title>
 <link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
 <style>
   :root {
 <link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
 <style>
   :root {
     --ca-col: #5eead422;
     --ar-col: #c084fc22;
     --oh-col: #fb923c22;
     --ca-col: #5eead422;
     --ar-col: #c084fc22;
     --oh-col: #fb923c22;
+
+    /* "You are here" highlights */
+    --row-now-bg: #f0b42918;
+    --row-now-border: #f0b429;
+    --col-you-bg: #5eead414;
+    --col-you-border: #5eead4;
   }
 
   * { margin: 0; padding: 0; box-sizing: border-box; }
   }
 
   * { margin: 0; padding: 0; box-sizing: border-box; }
     border: 1px solid #5eead455;
   }
 
     border: 1px solid #5eead455;
   }
 
-  .auto-label {
-    font-size: 11px;
-    color: var(--muted);
-    display: flex;
-    flex-direction: column;
-    gap: 3px;
-  }
-
-  #auto-label-sub {
-    font-size: 10px;
-    color: var(--muted);
-    opacity: 0.7;
-    line-height: 1.4;
-    max-width: 220px;
-  }
+  
 
   /* Section */
   .section { display: none; }
 
   /* Section */
   .section { display: none; }
     font-weight: 500;
     border-bottom: 1px solid var(--border);
     white-space: nowrap;
     font-weight: 500;
     border-bottom: 1px solid var(--border);
     white-space: nowrap;
+    position: relative;
+    width: 25%;
   }
 
   th.col-utc { color: var(--accent);  background: var(--utc-col); }
   }
 
   th.col-utc { color: var(--accent);  background: var(--utc-col); }
   th.col-ar  { color: var(--accent3); background: var(--ar-col); }
   th.col-oh  { color: #fb923c;        background: var(--oh-col); }
 
   th.col-ar  { color: var(--accent3); background: var(--ar-col); }
   th.col-oh  { color: #fb923c;        background: var(--oh-col); }
 
+  /* "You are here" column highlight on header */
+  th.col-you {
+    box-shadow: inset 0 -3px 0 var(--col-you-border);
+    background: var(--col-you-bg) !important;
+  }
+  th.col-you::after {
+    content: ' ◀ you';
+    font-size: 9px;
+    color: var(--accent2);
+    letter-spacing: 0.06em;
+    text-transform: lowercase;
+    opacity: 0.9;
+  }
+
   tbody tr {
     border-bottom: 1px solid var(--border);
     transition: background 0.15s;
   tbody tr {
     border-bottom: 1px solid var(--border);
     transition: background 0.15s;
   tbody tr:last-child { border-bottom: none; }
   tbody tr:hover { background: var(--row-hover); }
 
   tbody tr:last-child { border-bottom: none; }
   tbody tr:hover { background: var(--row-hover); }
 
+  /* "You are here" row highlight */
+  tbody tr.row-now {
+    background: var(--row-now-bg) !important;
+    box-shadow: inset 3px 0 0 var(--row-now-border), inset -3px 0 0 var(--row-now-border);
+  }
+  tbody tr.row-now td {
+    color: var(--text);
+  }
+  tbody tr.row-now .time-val {
+    font-weight: 700;
+  }
+  /* The cell where row-now meets col-you — the "you are exactly here" cell */
+  td.cell-exactly-here {
+    background: #5eead420;
+    box-shadow: inset 0 0 0 1px var(--col-you-border);
+  }
+
+  /* "You are here" column highlight on body cells */
+  td.col-you {
+    background: var(--col-you-bg);
+  }
+
   td {
     padding: 11px 18px;
     white-space: nowrap;
   td {
     padding: 11px 18px;
     white-space: nowrap;
+    position: relative;
   }
 
   td.col-utc { color: var(--accent);  }
   }
 
   td.col-utc { color: var(--accent);  }
     margin-left: 6px;
   }
 
     margin-left: 6px;
   }
 
+  /* Now indicator */
+  .now-tag {
+    display: inline-block;
+    font-size: 9px;
+    color: var(--accent);
+    background: #f0b42922;
+    padding: 1px 5px;
+    border-radius: 3px;
+    margin-left: 6px;
+    letter-spacing: 0.04em;
+    vertical-align: middle;
+  }
+
   /* Legend */
   .legend {
     margin-top: 32px;
   /* Legend */
   .legend {
     margin-top: 32px;
 
   .legend-card .ldetail strong { color: var(--text); }
 
 
   .legend-card .ldetail strong { color: var(--text); }
 
+  /* Your-timezone info card */
+  .you-tz-card {
+    background: #5eead408;
+    border: 1px solid #5eead430;
+  }
+
   footer {
     margin-top: 48px;
     font-size: 11px;
   footer {
     margin-top: 48px;
     font-size: 11px;
         <button class="toggle-btn" id="btn-dst">☀️ DST Active</button>
         <button class="toggle-btn" id="btn-nodst">❄️ Standard Time</button>
       </div>
         <button class="toggle-btn" id="btn-dst">☀️ DST Active</button>
         <button class="toggle-btn" id="btn-nodst">❄️ Standard Time</button>
       </div>
-      <div class="auto-label" style="display:none">
-        <span id="auto-label-text">Auto-detected for today</span>
-        <span id="auto-label-sub"></span>
+      
       </div>
       </div>
-    </div>
   </header>
 
   <!-- DST Section (Mar 2nd Sun → Nov 1st Sun in US) -->
   </header>
 
   <!-- DST Section (Mar 2nd Sun → Nov 1st Sun in US) -->
       <div class="lname"><span class="lname-dot dot-oh"></span>Ohio</div>
       <div class="ldetail">DST: <strong>EDT (UTC−4)</strong><br>Standard: <strong>EST (UTC−5)</strong></div>
     </div>
       <div class="lname"><span class="lname-dot dot-oh"></span>Ohio</div>
       <div class="ldetail">DST: <strong>EDT (UTC−4)</strong><br>Standard: <strong>EST (UTC−5)</strong></div>
     </div>
+    <div class="legend-card you-tz-card">
+      <div class="lname"><span class="lname-dot" style="background:var(--accent2)"></span>Your Timezone</div>
+      <div class="ldetail" id="you-tz-detail">Detecting…</div>
+    </div>
   </div>
 
   <footer style="display:none">
     US DST begins 2nd Sunday of March · ends 1st Sunday of November<br>
     Argentina (ART, UTC−3) does not observe Daylight Saving Time<br>
   </div>
 
   <footer style="display:none">
     US DST begins 2nd Sunday of March · ends 1st Sunday of November<br>
     Argentina (ART, UTC−3) does not observe Daylight Saving Time<br>
-    All times shown as 24-hour clock with 12-hour equivalents
+    All times shown as 24-hour clock with 12-hour equivalents<br>
+    Row and timezone highlighted based on your browser's local time
   </footer>
 </div>
 
   </footer>
 </div>
 
   // ── DST detection ──────────────────────────────────────────────
   function usDstActive(date) {
     const y = date.getFullYear();
   // ── DST detection ──────────────────────────────────────────────
   function usDstActive(date) {
     const y = date.getFullYear();
-    // 2nd Sunday in March
     const mar = new Date(y, 2, 1);
     const mar = new Date(y, 2, 1);
-    const dstStart = new Date(y, 2, (14 - mar.getDay()) % 7 + 8); // Day 8-14
+    const dstStart = new Date(y, 2, (14 - mar.getDay()) % 7 + 8);
     dstStart.setHours(2, 0, 0, 0);
     dstStart.setHours(2, 0, 0, 0);
-    // 1st Sunday in November
     const nov = new Date(y, 10, 1);
     const dstEnd = new Date(y, 10, (7 - nov.getDay()) % 7 + 1);
     dstEnd.setHours(2, 0, 0, 0);
     return date >= dstStart && date < dstEnd;
   }
 
     const nov = new Date(y, 10, 1);
     const dstEnd = new Date(y, 10, (7 - nov.getDay()) % 7 + 1);
     dstEnd.setHours(2, 0, 0, 0);
     return date >= dstStart && date < dstEnd;
   }
 
-  // ── Build table ────────────────────────────────────────────────
-  // offsets: { ca, ar, oh } relative to UTC (in hours)
+  // ── Formatting helpers ────────────────────────────────────────
   function fmt12(h) {
     const d = ((h % 24) + 24) % 24;
     const ampm = d < 12 ? 'am' : 'pm';
   function fmt12(h) {
     const d = ((h % 24) + 24) % 24;
     const ampm = d < 12 ? 'am' : 'pm';
     return `${hh}:00`;
   }
 
     return `${hh}:00`;
   }
 
-  function dayNote(utcH, offset) {
-    const adjusted = utcH + offset;
-    if (adjusted < 0)   return '<span class="day-note">prev day</span>';
-    if (adjusted >= 24) return '<span class="day-note">next day</span>';
-    return '';
+  // ── Detect user's timezone and current UTC hour ───────────────
+  function getUserTzInfo() {
+    const tzName = Intl.DateTimeFormat().resolvedOptions().timeZone || 'Unknown';
+    const now = new Date();
+
+    // Current UTC hour (0-23)
+    const utcHour = now.getUTCHours();
+
+    // Get the user's current local offset from UTC in hours (includes DST)
+    const localOffsetMin = -now.getTimezoneOffset(); // minutes; positive = east of UTC
+    const localOffsetH = localOffsetMin / 60;
+
+    return { tzName, utcHour, localOffsetH };
+  }
+
+  // ── Determine which chart column matches the user ────────────
+  // Columns: utc, ca, oh, ar
+  // We match based on the user's current UTC offset.
+  // ca: -7 (DST) / -8 (std), oh: -4 (DST) / -5 (std), ar: -3 always
+  // If none match exactly, return null (user's tz isn't one of the four).
+  function matchUserColumn(localOffsetH, isDst) {
+    const caOff = isDst ? -7 : -8;
+    const ohOff = isDst ? -4 : -5;
+    const arOff = -3;
+    const utcOff = 0;
+
+    if (Math.abs(localOffsetH - caOff) < 0.01)  return 'ca';
+    if (Math.abs(localOffsetH - ohOff) < 0.01)  return 'oh';
+    if (Math.abs(localOffsetH - arOff) < 0.01)  return 'ar';
+    if (Math.abs(localOffsetH - utcOff) < 0.01) return 'utc';
+    return null;
   }
 
   }
 
+  // ── Build table ────────────────────────────────────────────────
   function buildTable(tableEl, caOff, arOff, ohOff, caLabel, ohLabel) {
     const thead = `<thead><tr>
   function buildTable(tableEl, caOff, arOff, ohOff, caLabel, ohLabel) {
     const thead = `<thead><tr>
-      <th class="col-utc">UTC</th>
-      <th class="col-ca">California<br><span style="font-size:10px;font-weight:400;opacity:.7">${caLabel}</span></th>
-      <th class="col-oh">Ohio<br><span style="font-size:10px;font-weight:400;opacity:.7">${ohLabel}</span></th>
-      <th class="col-ar">Argentina<br><span style="font-size:10px;font-weight:400;opacity:.7">ART (UTC−3)</span></th>
+      <th class="col-utc" data-col="utc">UTC</th>
+      <th class="col-ca" data-col="ca">California<br><span style="font-size:10px;font-weight:400;opacity:.7">${caLabel}</span></th>
+      <th class="col-oh" data-col="oh">Ohio<br><span style="font-size:10px;font-weight:400;opacity:.7">${ohLabel}</span></th>
+      <th class="col-ar" data-col="ar">Argentina<br><span style="font-size:10px;font-weight:400;opacity:.7">ART (UTC−3)</span></th>
     </tr></thead>`;
 
     let rows = '';
     </tr></thead>`;
 
     let rows = '';
       const caH = u + caOff;
       const arH = u + arOff;
       const ohH = u + ohOff;
       const caH = u + caOff;
       const arH = u + arOff;
       const ohH = u + ohOff;
-      rows += `<tr>
-        <td class="col-utc"><span class="time-val">${fmtHour(u)}</span><span class="tz-label">${fmt12(u)}</span></td>
-        <td class="col-ca"><span class="time-val">${fmt12(caH)}</span><span class="tz-label">${fmtHour(caH)}</span></td>
-        <td class="col-oh"><span class="time-val">${fmt12(ohH)}</span><span class="tz-label">${fmtHour(ohH)}</span></td>
-        <td class="col-ar"><span class="time-val">${fmtHour(arH)}</span><span class="tz-label">${fmt12(arH)}</span></td>
+      rows += `<tr data-utc-hour="${u}">
+        <td class="col-utc" data-col="utc"><span class="time-val">${fmtHour(u)}</span><span class="tz-label">${fmt12(u)}</span></td>
+        <td class="col-ca" data-col="ca"><span class="time-val">${fmt12(caH)}</span><span class="tz-label">${fmtHour(caH)}</span></td>
+        <td class="col-oh" data-col="oh"><span class="time-val">${fmt12(ohH)}</span><span class="tz-label">${fmtHour(ohH)}</span></td>
+        <td class="col-ar" data-col="ar"><span class="time-val">${fmtHour(arH)}</span><span class="tz-label">${fmt12(arH)}</span></td>
       </tr>`;
     }
     tableEl.innerHTML = thead + `<tbody>${rows}</tbody>`;
   }
 
       </tr>`;
     }
     tableEl.innerHTML = thead + `<tbody>${rows}</tbody>`;
   }
 
+  // ── Apply "you are here" highlights ────────────────────────────
+  function applyHighlights(tableEl, utcHour, youCol) {
+    // Clear previous highlights
+    tableEl.querySelectorAll('tr.row-now').forEach(r => r.classList.remove('row-now'));
+    tableEl.querySelectorAll('.col-you').forEach(e => e.classList.remove('col-you'));
+    tableEl.querySelectorAll('.cell-exactly-here').forEach(e => e.classList.remove('cell-exactly-here'));
+    tableEl.querySelectorAll('.now-tag').forEach(e => e.remove());
+
+    // Highlight the current UTC-hour row
+    const row = tableEl.querySelector(`tr[data-utc-hour="${utcHour}"]`);
+    if (row) {
+      row.classList.add('row-now');
+    }
+
+    // Put the "now" tag in the user's timezone column cell on this row,
+    // or fall back to the UTC cell if their timezone isn't listed.
+    if (row) {
+      const targetCol = youCol || 'utc';
+      const targetCell = row.querySelector(`td[data-col="${targetCol}"]`);
+      if (targetCell) {
+        const tag = document.createElement('span');
+        tag.className = 'now-tag';
+        tag.textContent = 'now';
+        targetCell.appendChild(tag);
+      }
+    }
+
+    // Highlight the user's timezone column (header + all body cells)
+    if (youCol) {
+      tableEl.querySelectorAll(`[data-col="${youCol}"]`).forEach(cell => {
+        cell.classList.add('col-you');
+      });
+      // Highlight the intersection cell
+      if (row) {
+        const intersect = row.querySelector(`td[data-col="${youCol}"]`);
+        if (intersect) intersect.classList.add('cell-exactly-here');
+      }
+    }
+  }
+
   // ── Init ───────────────────────────────────────────────────────
   const now = new Date();
   const autoDst = usDstActive(now);
   // ── Init ───────────────────────────────────────────────────────
   const now = new Date();
   const autoDst = usDstActive(now);
+  const userInfo = getUserTzInfo();
 
   // Display today's date
   document.getElementById('today-display').textContent =
     now.toLocaleDateString('en-US', { weekday: 'short', year: 'numeric', month: 'long', day: 'numeric' });
 
 
   // Display today's date
   document.getElementById('today-display').textContent =
     now.toLocaleDateString('en-US', { weekday: 'short', year: 'numeric', month: 'long', day: 'numeric' });
 
-  // Build both tables (offsets from UTC)
+  // Build both tables
   buildTable(
     document.getElementById('table-dst'),
   buildTable(
     document.getElementById('table-dst'),
-    -7, -3, -4,          // CA=PDT, AR=ART, OH=EDT
+    -7, -3, -4,
     'PDT (UTC−7)', 'EDT (UTC−4)'
   );
   buildTable(
     document.getElementById('table-nodst'),
     'PDT (UTC−7)', 'EDT (UTC−4)'
   );
   buildTable(
     document.getElementById('table-nodst'),
-    -8, -3, -5,          // CA=PST, AR=ART, OH=EST
+    -8, -3, -5,
     'PST (UTC−8)', 'EST (UTC−5)'
   );
 
     'PST (UTC−8)', 'EST (UTC−5)'
   );
 
     const btnNodst = document.getElementById('btn-nodst');
     btnDst.className   = 'toggle-btn' + (mode === 'dst'   ? ' active-dst'   : '');
     btnNodst.className = 'toggle-btn' + (mode === 'nodst' ? ' active-nodst' : '');
     const btnNodst = document.getElementById('btn-nodst');
     btnDst.className   = 'toggle-btn' + (mode === 'dst'   ? ' active-dst'   : '');
     btnNodst.className = 'toggle-btn' + (mode === 'nodst' ? ' active-nodst' : '');
+
+    // Re-apply highlights for the now-visible table
+    refreshHighlights();
   }
 
   }
 
-  setMode(currentMode);
+  // ── Refresh "you are here" highlights ──────────────────────────
+  function refreshHighlights() {
+    const isDst = currentMode === 'dst';
+    const youCol = matchUserColumn(userInfo.localOffsetH, isDst);
+    const visibleTable = document.getElementById(isDst ? 'table-dst' : 'table-nodst');
+    applyHighlights(visibleTable, userInfo.utcHour, youCol);
 
 
-  // Fix auto-dot logic (simpler)
-  function updateAutoLabel() {
-    const lbl = document.getElementById('auto-label-text');
-    const sub = document.getElementById('auto-label-sub');
-    const isAuto = (currentMode === 'dst') === autoDst;
-    if (isAuto) {
-      lbl.textContent = 'Auto-detected for today';
-      sub.textContent = 'Showing the table that matches today\'s date. Click a button above to override.';
+    // Update the legend's "your timezone" card
+    const detail = document.getElementById('you-tz-detail');
+    const colLabels = { utc: 'UTC', ca: 'California', oh: 'Ohio', ar: 'Argentina' };
+    if (youCol) {
+      detail.innerHTML = `Detected: <strong>${userInfo.tzName}</strong><br>Matches the <strong>${colLabels[youCol]}</strong> column.<br>UTC offset: <strong>${userInfo.localOffsetH >= 0 ? '+' : ''}${userInfo.localOffsetH}h</strong>`;
     } else {
     } else {
-      lbl.textContent = 'Manually selected';
-      sub.textContent = 'This differs from what today\'s date would suggest.';
+      detail.innerHTML = `Detected: <strong>${userInfo.tzName}</strong><br>No exact match with a listed column.<br>UTC offset: <strong>${userInfo.localOffsetH >= 0 ? '+' : ''}${userInfo.localOffsetH}h</strong>`;
     }
   }
 
     }
   }
 
-  document.getElementById('btn-dst').addEventListener('click', () => { setMode('dst'); updateAutoLabel(); });
-  document.getElementById('btn-nodst').addEventListener('click', () => { setMode('nodst'); updateAutoLabel(); });
-  updateAutoLabel();
+  // ── Wire up buttons ────────────────────────────────────────────
+  document.getElementById('btn-dst').addEventListener('click', () => { setMode('dst'); });
+  document.getElementById('btn-nodst').addEventListener('click', () => { setMode('nodst'); });
+
+  setMode(currentMode);
+
+  // ── Refresh at the exact next hour boundary ──────────────────
+  function scheduleNextHourRefresh() {
+    const now = new Date();
+    const next = new Date(now);
+    next.setUTCMinutes(0, 0, 0);
+    next.setUTCHours(next.getUTCHours() + 1);
+    const msUntil = next.getTime() - now.getTime();
+
+    setTimeout(() => {
+      const fresh = getUserTzInfo();
+      userInfo.utcHour = fresh.utcHour;
+      // Also refresh offset/timezone in case DST flipped at the boundary
+      userInfo.localOffsetH = fresh.localOffsetH;
+      userInfo.tzName = fresh.tzName;
+      refreshHighlights();
+      scheduleNextHourRefresh();
+    }, msUntil);
+  }
+
+  scheduleNextHourRefresh();
 </script>
 </body>
 </html>
 </script>
 </body>
 </html>