From 63bbe5c2ab6cedae19ffa8dc7e99d44e30147471 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 01:21:57 +0000 Subject: [PATCH] Fix sunrise wait windows on DST change days daily_sunrise_video.sh and sunrise-audio-capture.sh added wall-clock seconds-since-midnight to a midnight epoch, which is 3600s off on the two days a year the clocks change. Resolve targets with date -d "today HH:MM:SS" instead. sunrise.py now builds local midnight with tz.localize(). Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_013wi3ZRpfenCe2TRwT4JFMG --- daily_sunrise_video.sh | 14 ++++++++------ sunrise-audio-capture.sh | 9 +++++---- sunrise.py | 4 +++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/daily_sunrise_video.sh b/daily_sunrise_video.sh index eeaa7bd..d51dc18 100755 --- a/daily_sunrise_video.sh +++ b/daily_sunrise_video.sh @@ -65,14 +65,16 @@ if ! $TEST_MODE; then start_sec=$((sunrise_sec - SUNRISE_PRE_MIN * 60)) end_sec=$((sunrise_sec + SUNRISE_POST_MIN * 60)) echo "Window: $((start_sec/3600)):$(printf '%02d' $(((start_sec%3600)/60))) → $((end_sec/3600)):$(printf '%02d' $(((end_sec%3600)/60)))" - midnight=$(date -d "today 00:00:00" +%s) - now_day_sec=$(( $(date +%s) - midnight )) - if [ "$now_day_sec" -lt "$end_sec" ]; then - wait_sec=$(( end_sec - now_day_sec + 30 )) - echo "Waiting ${wait_sec}s for capture window to finish (ends $(date -d "@$(( midnight + end_sec ))" '+%H:%M:%S'))..." + # Resolve wall-clock targets through `date -d` instead of adding seconds-since- + # midnight to a midnight epoch: on a DST day (23h/25h) the two differ by 3600s. + end_epoch=$(date -d "today $(printf '%02d:%02d:%02d' $((end_sec/3600)) $(((end_sec%3600)/60)) $((end_sec%60)))" +%s) + now_epoch=$(date +%s) + if [ "$now_epoch" -lt "$end_epoch" ]; then + wait_sec=$(( end_epoch - now_epoch + 30 )) + echo "Waiting ${wait_sec}s for capture window to finish (ends $(date -d "@$end_epoch" '+%H:%M:%S'))..." sleep "$wait_sec" else - echo "Capture window already closed at $(date -d "@$(( midnight + end_sec ))" '+%H:%M:%S') — processing available images" + echo "Capture window already closed at $(date -d "@$end_epoch" '+%H:%M:%S') — processing available images" fi fi diff --git a/sunrise-audio-capture.sh b/sunrise-audio-capture.sh index bb539a2..aef28fe 100755 --- a/sunrise-audio-capture.sh +++ b/sunrise-audio-capture.sh @@ -54,12 +54,13 @@ record_dur_sec=$SUNRISE_TARGET_SECS echo "Audio window: ${half_pre}s before → ${half_post}s after sunrise (${record_dur_sec}s total)" -midnight=$(date -d "today 00:00:00" +%s) -now_day_sec=$(( $(date +%s) - midnight )) -wait_sec=$(( record_start_sec - now_day_sec )) +# Resolve the wall-clock start via `date -d` (not midnight epoch + seconds): +# on a DST day (23h/25h) those differ by 3600s. +start_epoch=$(date -d "today $(printf '%02d:%02d:%02d' $((record_start_sec/3600)) $(((record_start_sec%3600)/60)) $((record_start_sec%60)))" +%s) +wait_sec=$(( start_epoch - $(date +%s) )) if [ "$wait_sec" -gt 0 ]; then - echo "Waiting ${wait_sec}s until audio window ($(date -d "@$(( midnight + record_start_sec ))" '+%H:%M:%S'))..." + echo "Waiting ${wait_sec}s until audio window ($(date -d "@$start_epoch" '+%H:%M:%S'))..." sleep "$wait_sec" fi diff --git a/sunrise.py b/sunrise.py index bb04a99..33898a6 100755 --- a/sunrise.py +++ b/sunrise.py @@ -58,7 +58,9 @@ tz = pytz.timezone(conf['TIMEZONE']) # This bracket is timezone-correct and handles any UTC offset, including large # positive offsets (UTC+12/+14) where local midnight falls on the previous UTC day. now_local = datetime.now(tz) -midnight_local = now_local.replace(hour=0, minute=0, second=0, microsecond=0) +# tz.localize (not .replace) so the UTC offset is re-resolved for midnight — +# on a DST-change day now_local's offset differs from midnight's. +midnight_local = tz.localize(datetime(now_local.year, now_local.month, now_local.day)) t0_utc = midnight_local.astimezone(timezone.utc) t1_utc = t0_utc + timedelta(hours=25) # 25 h covers any timezone's full day