Version: v0.5.0 (c24f605)
This one is invisible if your machine runs on UTC, which is probably why it has survived.
The date dropdown is built in UTC
static/chat.js:3541 populates the schedule popover's date options with:
opt.value = d.toISOString().slice(0, 10);
toISOString() formats in UTC. Whenever the user's local calendar date differs from the UTC date at that moment, which is most of the evening for anyone east of UTC and the early morning for anyone west of it, the option labelled Today carries yesterday's or tomorrow's date.
There is nothing to see: you pick the day that reads correctly and the message lands 24 hours away from where you meant.
The server then re-resolves the same moment independently
The browser submits a date string and a time string, and the server re-parses them:
app.py:1611:
dt = _dt.datetime.strptime(f"{send_at_date} {daily_at}", "%Y-%m-%d %H:%M")
send_at = dt.timestamp()
.timestamp() resolves in the server's timezone. On a single machine both sides agree and this is harmless, but two independent places are each deciding what "today at 3pm" means, so they only agree by coincidence rather than by design. Anyone reaching the server from a browser in another timezone gets the disagreement for real.
Suggested direction
Build the date options from local calendar fields (getFullYear(), getMonth(), getDate()) rather than from a UTC string.
For the second half, the browser already knows exactly which moment the user picked, so it can resolve it and send the epoch, leaving the server with nothing to re-derive. That removes the second code path instead of trying to keep two of them in agreement.
Fixed by #95. The new field is optional and additive, and requests that omit it behave exactly as before.
Version: v0.5.0 (
c24f605)This one is invisible if your machine runs on UTC, which is probably why it has survived.
The date dropdown is built in UTC
static/chat.js:3541populates the schedule popover's date options with:toISOString()formats in UTC. Whenever the user's local calendar date differs from the UTC date at that moment, which is most of the evening for anyone east of UTC and the early morning for anyone west of it, the option labelled Today carries yesterday's or tomorrow's date.There is nothing to see: you pick the day that reads correctly and the message lands 24 hours away from where you meant.
The server then re-resolves the same moment independently
The browser submits a date string and a time string, and the server re-parses them:
app.py:1611:.timestamp()resolves in the server's timezone. On a single machine both sides agree and this is harmless, but two independent places are each deciding what "today at 3pm" means, so they only agree by coincidence rather than by design. Anyone reaching the server from a browser in another timezone gets the disagreement for real.Suggested direction
Build the date options from local calendar fields (
getFullYear(),getMonth(),getDate()) rather than from a UTC string.For the second half, the browser already knows exactly which moment the user picked, so it can resolve it and send the epoch, leaving the server with nothing to re-derive. That removes the second code path instead of trying to keep two of them in agreement.
Fixed by #95. The new field is optional and additive, and requests that omit it behave exactly as before.