diff --git a/frontend/tomorrow-plan.js b/frontend/tomorrow-plan.js index fd29455..5657984 100644 --- a/frontend/tomorrow-plan.js +++ b/frontend/tomorrow-plan.js @@ -27,8 +27,15 @@ function createTomorrowPlan({fetchJson,localDate,timeZone}={}) { function millisecondsUntilNextDay() { const now=Date.now(); const zone=timeZone(); - const formatter=new Intl.DateTimeFormat('en-CA',{timeZone:zone,year:'numeric',month:'2-digit',day:'2-digit', - hour:'2-digit',minute:'2-digit',second:'2-digit',hourCycle:'h23'}); + let formatter; + try { + formatter=new Intl.DateTimeFormat('en-CA',{timeZone:zone,year:'numeric',month:'2-digit',day:'2-digit', + hour:'2-digit',minute:'2-digit',second:'2-digit',hourCycle:'h23'}); + } catch (_error) { + const next=new Date(now); + next.setHours(24,0,0,250); + return Math.max(1,next.getTime()-now); + } const zoned=value=>Object.fromEntries(formatter.formatToParts(new Date(value)) .filter(part=>part.type!=='literal').map(part=>[part.type,Number(part.value)])); const current=zoned(now); diff --git a/tests/test_tomorrow_plan_frontend.py b/tests/test_tomorrow_plan_frontend.py index 65ad591..1a621a1 100644 --- a/tests/test_tomorrow_plan_frontend.py +++ b/tests/test_tomorrow_plan_frontend.py @@ -124,6 +124,20 @@ console.log(JSON.stringify({checks,delays:timers.map(timer=>timer.delay),cleared assert result["cleared"] == [1, 2] +def test_tomorrow_rollover_falls_back_when_the_reported_timezone_is_invalid(): + result = run_controller(""" +let scheduled=null; +const planner=createTomorrowPlan({fetchJson:async()=>({}),localDate:()=> '2026-08-20',timeZone:()=> 'Etc/Unknown'}); +const lifecycle=planner.startLifecycle({ + check:async()=>false,setTimer:(_fn,delay)=>{scheduled=delay;return 1;},clearTimer:()=>{}, +}); +await lifecycle.run(); +console.log(JSON.stringify({scheduled:Number.isFinite(scheduled)&&scheduled>0})); +""") + + assert result == {"scheduled": True} + + def test_tomorrow_plan_has_a_touch_safe_mobile_entry_and_reuses_the_ordered_planner(): index = INDEX.read_text() css = CSS.read_text()