Skip to content

Make schedule time-zone behavior explicit - #50

Open
iibaranov-IG wants to merge 5 commits into
KalyteraSystems:mainfrom
iibaranov-IG:feat/explicit-schedule-time-zone
Open

iibaranov-IG wants to merge 5 commits into
KalyteraSystems:mainfrom
iibaranov-IG:feat/explicit-schedule-time-zone

Conversation

@iibaranov-IG

Copy link
Copy Markdown
Contributor

Summary

  • resolve and inject one startup TimeZoneInfo for recurring schedules and UI conversion instead of reading TimeZoneInfo.Local ad hoc
  • use the same TimeProvider for future validation and creation timestamps
  • advance nonexistent spring-forward wall times by the DST gap and choose the earlier UTC occurrence for ambiguous one-time starts
  • keep both repeated-hour instants inside matching recurring windows and retain UTC storage for one-time starts
  • show the active zone and current offset on New session and System check
  • document container TZ defaults and restart/backward-compatibility behavior

Verification

  • dotnet test IPCamLapse.sln -c Release: 111 tests pass (64 IPCamLapse + 47 OpenCamInterop)
  • deterministic custom-zone tests cover spring-forward, fall-back, both repeated-hour instants, overnight windows, and UTC
  • page tests verify the injected zone and offset on both required pages
  • dotnet format IPCamLapse.sln --verify-no-changes --no-restore: pass
  • git diff --check: pass
  • signed commit: 8ab316b

Closes #33.

@elkampu elkampu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The startup dependency/UI direction is sound, but two recurring DST boundaries are incorrect at exact head 3ca4a27. I reproduced both as focused tests against the submitted service:

  1. In the second fall-back hour, Daily 01:30–01:45 at 2026-11-01 06:20Z (01:20 standard time) returns NextStartUtc 05:30Z, which is already in the past. ConvertWallTimeToUtc always chooses the earlier ambiguous occurrence, which is correct for a one-time start but not for the next recurring start after that occurrence has passed.

  2. On spring-forward day, Daily 02:30–04:00 at 07:10Z (03:10 daylight time) reports Active=true. The required gap rule moves the nonexistent 02:30 start to 03:30, so this window must remain inactive until 07:30Z. Raw TimeOfDay membership disagrees with the conversion policy.

Please make recurring boundary evaluation transition-aware for both Daily and Weekly schedules, guarantee a returned NextStartUtc is in the future, and add these focused fall-back/spring-forward regressions. The temporary tests were removed after reproduction.

@iibaranov-IG

iibaranov-IG commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for reproducing both boundaries so precisely — agreed. DST has once again demonstrated that clocks are hostile distributed systems. I’ll make Daily and Weekly boundary evaluation transition-aware, guarantee that NextStartUtc is actually in the future, apply the gap policy consistently to active-window evaluation, and add focused fall-back and spring-forward regressions.

@iibaranov-IG

Copy link
Copy Markdown
Contributor Author

Готово: recurring-окна теперь оцениваются как UTC-интервалы, с кандидатами для обоих повторов ambiguous wall time. Поэтому второй осенний 01:30 получает собственный будущий старт, а spring-forward 02:30 сдвигается по установленному gap-правилу и не активирует окно раньше времени. Добавил оба воспроизведённых регрессионных сценария. Head: e251297; CI зелёный на Ubuntu, Windows, контейнере и CodeQL. Буду признателен за повторную проверку.

@elkampu elkampu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact head e251297 fixes the two previously reported boundaries, but another required repeated-hour case still fails. For a daily 00:30–01:15 window, 2026-11-01 06:10Z is the second 01:10 occurrence and must still be active; an exact-head focused regression returns Active=false. In EvaluateRecurring, selecting WallTimeCandidates(endWall).FirstOrDefault(candidate => candidate > startUtc) pairs the unambiguous 00:30 start only with the first 01:15 end (05:15Z) and discards the second valid end (06:15Z). Please model the recurring interval so an ambiguous end includes both repeated-hour instants, add this exact regression for Daily and the equivalent Weekly path, and retain the new spring-gap and second-start coverage.

@iibaranov-IG

Copy link
Copy Markdown
Contributor Author

Addressed the latest review: a window that begins before the repeated fall-back hour now remains active through the second ambiguous end occurrence, while ambiguous starts still pair with their corresponding end. Added Daily and Weekly regressions for the reported 00:30–01:15 case. CI is green on Ubuntu and Windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make schedule time-zone behavior explicit and deterministic

2 participants