<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 {
--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; }
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; }
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-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: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;
+ position: relative;
}
td.col-utc { color: var(--accent); }
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-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;
<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>
</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="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>
- 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>
// ── DST detection ──────────────────────────────────────────────
function usDstActive(date) {
const y = date.getFullYear();
- // 2nd Sunday in March
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);
- // 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;
}
- // ── 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';
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>
- <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 = '';
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>`;
}
+ // ── 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);
+ const userInfo = getUserTzInfo();
// 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'),
- -7, -3, -4, // CA=PDT, AR=ART, OH=EDT
+ -7, -3, -4,
'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)'
);
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 {
- 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>