${formatTime(dogClock)}!
Dogs have very reliable internal clocks and don't automatically adjust to Daylight Saving Time.
Don't worry - your pup's schedule should adjust naturally over the next few days.
`;
} else {
bodyClockDiv.innerHTML = '';
}
}
function updateInfo() {
if (!isCaliforniaTimezone() && !pretendCaliforniaMode) {
document.getElementById('past-change').innerHTML = '';
document.getElementById('body-clock').innerHTML = '';
document.getElementById('current-dst').innerHTML = '';
document.getElementById('future-change').className = 'wrong-timezone';
document.getElementById('future-change').innerHTML = `
👋 Hey there! It looks like you're not in California.
This tool is designed specifically for folks in the Pacific Time zone (PST/PDT), so it won't be accurate for your location.
Pretend I am in California anyway
`;
return;
}
const { pastChange, futureChange } = getClockChanges();
// Show past change
const pastChangeDiv = document.getElementById('past-change');
const pastSaturday = new Date(pastChange.date);
pastSaturday.setDate(pastChange.date.getDate() - 1);
pastChangeDiv.className = 'past-change';
pastChangeDiv.innerHTML = `
Most recent change:
On
Sunday, ${formatDate(pastChange.date)},
clocks ${pastChange.isSpringForward ? 'sprang forward' : 'fell back'}
(you ${pastChange.isSpringForward ? 'lost' : 'gained'} one hour of sleep).
`;
// Show future change
const futureChangeDiv = document.getElementById('future-change');
const futureSaturday = new Date(futureChange.date);
futureSaturday.setDate(futureChange.date.getDate() - 1);
const now = new Date();
const isTonight = now.getDate() === futureSaturday.getDate() &&
now.getMonth() === futureSaturday.getMonth() &&
now.getFullYear() === futureSaturday.getFullYear();
const sleepEffect = futureChange.isSpringForward ? 'lose an hour of sleep' : 'get an extra hour of sleep';
const clockEffect = futureChange.isSpringForward ?
'clocks spring forward from 2:00 AM to 3:00 AM' :
'clocks fall back from 2:00 AM to 1:00 AM';
const tonightBadge = isTonight ? 'That\'s tonight!' : '';
futureChangeDiv.className = 'info-box';
futureChangeDiv.innerHTML = `
Next change:
When you go to bed on
Saturday, ${formatDate(futureSaturday)}${tonightBadge},
you will ${sleepEffect}!
The ${clockEffect} on
Sunday, ${formatDate(futureChange.date)}.
`;
// Update body clock info based on past change
updateBodyClockInfo(pastChange);
// Determine if it is currently daylight savings time or not
const currentDstDiv = document.getElementById('current-dst');
const isDst = pastChange.isSpringForward && !futureChange.isSpringForward;
currentDstDiv.className = 'info-box';
currentDstDiv.innerHTML = `
Current status:
It is currently ${isDst ? 'Daylight Saving Time (PDT)' : 'Standard Time (PST)'}.
`;
}
updateInfo();
// Update the times every minute
setInterval(updateInfo, 60000);
// Automated tests
function runTests() {
const results = [];
let passed = 0;
let failed = 0;
let currentGroup = null;
function group(name) {
currentGroup = name;
results.push({ type: 'group', name });
}
function assert(name, actual, expected) {
if (actual === expected) {
passed++;
results.push({ type: 'pass', name, actual });
} else {
failed++;
results.push({ type: 'fail', name, actual, expected });
}
}
function dateStr(d) {
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
}
function friendlyDate(d) {
const days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return `${days[d.getDay()]} ${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
}
// Helper to compute DST changes for a given year (mirrors getYearChanges)
function changesForYear(y) {
const marchDay = new Date(y, 2, 1).getDay() || 7;
const springForward = new Date(y, 2, 1 + (14 - marchDay));
const novDay = new Date(y, 10, 1).getDay() || 7;
const fallBack = new Date(y, 10, 1 + (7 - novDay));
return { springForward, fallBack };
}
// Test known DST dates for several years
const knownDates = [
{ year: 2024, spring: '2024-03-10', fall: '2024-11-03' },
{ year: 2025, spring: '2025-03-09', fall: '2025-11-02' },
{ year: 2026, spring: '2026-03-08', fall: '2026-11-01', note: '1st is Sunday' },
{ year: 2027, spring: '2027-03-14', fall: '2027-11-07' },
{ year: 2028, spring: '2028-03-12', fall: '2028-11-05' },
];
for (const { year, spring, fall, note } of knownDates) {
const label = note ? `${year} (${note})` : `${year}`;
group(label);
const c = changesForYear(year);
assert(`Spring forward = ${spring}`, dateStr(c.springForward), spring);
assert(`Fall back = ${fall}`, dateStr(c.fallBack), fall);
assert(`Spring forward (${friendlyDate(c.springForward)}) is Sunday`, c.springForward.getDay(), 0);
assert(`Fall back (${friendlyDate(c.fallBack)}) is Sunday`, c.fallBack.getDay(), 0);
}
// Render results
const el = document.getElementById('test-results');
const lines = [];
for (const r of results) {
if (r.type === 'group') {
lines.push(`\n── ${r.name} ──`);
} else if (r.type === 'pass') {
lines.push(` ✓ ${r.name}`);
} else {
lines.push(` ✗ ${r.name}`);
lines.push(` expected: ${r.expected}`);
lines.push(` got: ${r.actual}`);
}
}
const summary = `${passed} passed, ${failed} failed of ${passed + failed} tests`;
lines.push(`\n${summary}`);
el.textContent = lines.join('\n');
el.parentElement.querySelector('summary').textContent = `Tests: ${summary}`;
if (failed > 0) el.parentElement.open = true;
}
runTests();