Time zone bugs in scheduled actions
I built an automation that gives a traveler access on the day they leave and takes it away the night they get back. The engineer picks the user, the travel group, and two dates. The package adds the user to the group at the start of the leave date and removes them at the end of the return date.
The first version removed people the evening before they got back.
What went wrong
The date picker returns a date as midnight UTC. Pick October 20 and you get something like 2026-10-20T00:00:00Z. That looks like "October 20", so I scheduled the removal from it.
Midnight UTC on October 20 is 7:00 PM on October 19 in a time zone five hours behind UTC, like US Central in October. The removal ran the evening before the return date, while the traveler could still be abroad and need access.
It's easy to miss. Logs printed in UTC show the date you expect. The picker displays the local date. Nothing errors. You only notice when a removal fires early.
The fix
Treat the picker's value as a calendar date and nothing more. Then build the times you mean, in the time zone you mean, and convert to UTC once, right before handing them to the scheduler:
- Add at 12:00 AM local on the leave date.
- Remove at 11:59 PM local on the return date.
Here's the idea in plain PowerShell. It's simplified, and a locked-down automation runtime may need it adapted.
# The picker sends midnight UTC. Keep only the calendar date.
# Parse as an offset so the runtime's own time zone can't shift the day.
$leaveDate = [datetimeoffset]::Parse($leavePicked).UtcDateTime.Date
$returnDate = [datetimeoffset]::Parse($returnPicked).UtcDateTime.Date
# Decide whose day it is. Use the Windows time zone ID you actually mean.
$tz = [TimeZoneInfo]::FindSystemTimeZoneById('Pacific Standard Time')
# Build local times, then convert once. ConvertTimeToUtc handles daylight saving.
$addLocal = [datetime]::SpecifyKind($leaveDate, 'Unspecified')
$removeLocal = [datetime]::SpecifyKind($returnDate.AddDays(1).AddMinutes(-1), 'Unspecified')
$addUtc = [TimeZoneInfo]::ConvertTimeToUtc($addLocal, $tz)
$removeUtc = [TimeZoneInfo]::ConvertTimeToUtc($removeLocal, $tz)
Checks that came with it
- Stop if the dates are out of order or already past.
- If the trip starts today, add the user right away and confirm in chat instead of scheduling.
- Write an internal note at setup, on add, and on removal, so the ticket shows what happened and when.
The takeaway
"End of day" is a local idea. Decide whose day you mean, put that time zone in the code where the next person can see it, and convert to UTC at the edge. Don't let a date picker's midnight make that decision for you.