[object Object]

← back to build-pages

refactor: extract startOfDayInTz + todayInTz helpers — DRY the tz math across /api/fleet/today + home

b57cacdaf296321e440329af57f5b7df4a0bc261 · 2026-05-13 20:37:02 -0700 · SteveStudio2

Files touched

Diff

commit b57cacdaf296321e440329af57f5b7df4a0bc261
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 20:37:02 2026 -0700

    refactor: extract startOfDayInTz + todayInTz helpers — DRY the tz math across /api/fleet/today + home
---
 server.js | 42 +++++++++++++++++++-----------------------
 1 file changed, 19 insertions(+), 23 deletions(-)

diff --git a/server.js b/server.js
index e5be0b0..861a39e 100644
--- a/server.js
+++ b/server.js
@@ -354,13 +354,10 @@ app.get('/', async (req, res, next) => {
     // Velocity counters + 7-day sparkline across the whole fleet. Concats
     // per-project commit lists so the helper sees every commit in one shot.
     const fleetCommits = entries.flatMap(e => _projectCache.get(e.slug)?.commits || []);
-    // Today-in-PT count — server.tz-aware calendar boundary (Steve's day).
+    // Today-in-PT count — Steve's calendar day, not rolling-24h.
     const todayPT = (() => {
-      const todayStr = new Date().toLocaleString('sv-SE', { timeZone: 'America/Los_Angeles' }).slice(0, 10);
-      const probe = new Date(`${todayStr}T00:00:00Z`);
-      const fmt = probe.toLocaleString('sv-SE', { timeZone: 'America/Los_Angeles', hour12: false }).slice(0, 19).replace(' ', 'T');
-      const fromTz = new Date(fmt).getTime();
-      const startMs = probe.getTime() + (probe.getTime() - fromTz);
+      const todayStr = todayInTz('America/Los_Angeles');
+      const startMs = startOfDayInTz(todayStr, 'America/Los_Angeles');
       const endMs = startMs + 86400000;
       let n = 0;
       for (const c of fleetCommits) {
@@ -756,25 +753,10 @@ app.get('/p/:slug/c/:hash', async (req, res, next) => {
 // not rolling. ?tz= can override (e.g. ?tz=UTC).
 app.get('/api/fleet/today', async (req, res, next) => {
   const tz = typeof req.query.tz === 'string' ? req.query.tz : 'America/Los_Angeles';
-  // sv-SE locale gives YYYY-MM-DD HH:MM:SS — easy slice + reliable boundary.
-  const todayLocal = new Date().toLocaleString('sv-SE', { timeZone: tz }).slice(0, 10);
   const dateStr = (typeof req.query.date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(req.query.date))
     ? req.query.date
-    : todayLocal;
-  // Build the start-of-day in the target timezone, in ms. The trick is to
-  // ask the same Date what midnight in that tz translates to in epoch ms —
-  // we form the local-midnight string and pass it through Date.parse with the
-  // tz offset implicit. Simpler approach: parse 00:00 in tz via formatToParts.
-  const startMs = (() => {
-    // YYYY-MM-DDT00:00:00 plus the tz offset on that date, computed by
-    // formatting the candidate midnight in target tz and seeing how far it
-    // drifts from UTC. Off-by-DST safe within ±1h, fine for our use.
-    const probe = new Date(`${dateStr}T00:00:00Z`);
-    const fmt = probe.toLocaleString('sv-SE', { timeZone: tz, hour12: false }).slice(0, 19).replace(' ', 'T');
-    const fromTz = new Date(fmt).getTime();
-    const offset = probe.getTime() - fromTz;
-    return new Date(`${dateStr}T00:00:00Z`).getTime() + offset;
-  })();
+    : todayInTz(tz);
+  const startMs = startOfDayInTz(dateStr, tz);
   const endMs = startMs + 86400000;
   try {
     const all = [];
@@ -1010,6 +992,20 @@ function canonAuthor(name) {
   return AUTHOR_ALIASES[key] || name;
 }
 
+// Resolve the start-of-day epoch-ms for a YYYY-MM-DD date in the given IANA
+// timezone. Steve's wall clock is PT; UTC midnight at PT-evening straddles
+// "today" weirdly. This computes the same boundary the user sees on their
+// clock, DST-aware via Intl.
+function startOfDayInTz(dateStr, tz) {
+  const probe = new Date(`${dateStr}T00:00:00Z`);
+  const fmt = probe.toLocaleString('sv-SE', { timeZone: tz, hour12: false }).slice(0, 19).replace(' ', 'T');
+  const fromTz = new Date(fmt).getTime();
+  return probe.getTime() + (probe.getTime() - fromTz);
+}
+function todayInTz(tz) {
+  return new Date().toLocaleString('sv-SE', { timeZone: tz }).slice(0, 10);
+}
+
 // Parse a ?since= query value into a unix ms cutoff (or 0 = no filter).
 // Accepts 24h, 7d, 30m, or an ISO date prefix (YYYY-MM-DD…). Returns 0 for
 // missing/malformed input so callers can use the result as a min-Date filter

← b709184 home: today-PT counter (Steve's calendar day, not rolling-24  ·  back to build-pages  ·  home: today vs yesterday side-by-side counts (Steve's PT cal ca0922f →