fix(activities): stamp local tz offset on event datetimes before submit #66
1 changed files with 31 additions and 8 deletions
fix(activities): stamp local tz offset on event datetimes before submit
The form sent naive "YYYY-MM-DDTHH:MM" to the LNbits events backend, where _to_unix (nostr_publisher.py) assumes UTC when tzinfo is None. So 08:00 entered in CEST got stored as 08:00 UTC, and the NIP-52 start tag landed on the relays at the wrong instant — the detail page then re-localized it to 10:00 (offset doubly applied). Stamp the wall-clock value with the user's UTC offset before sending so the backend builds the correct unix and the detail page renders the intended wall-clock. Seconds (`:00`) included for pre-3.11 Python fromisoformat compatibility. Round-trips through edit mode unchanged: splitDateTime trims to "HH:MM" so the suffix drops cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
commit
ac3c663a66
|
|
@ -87,6 +87,28 @@ function foldDateTime(date: string, time: string): string {
|
|||
return time ? `${date}T${time}` : date
|
||||
}
|
||||
|
||||
// Stamp the form's wall-clock datetime with the user's local UTC offset
|
||||
// before sending it to the LNbits events backend. Without this, the
|
||||
// backend's `_to_unix` (nostr_publisher.py) treats a naive ISO string
|
||||
// as UTC, so e.g. "08:00" entered in CEST gets stored as 08:00 UTC and
|
||||
// the NIP-52 `start` tag is off by the user's offset on the relay
|
||||
// — the detail page then renders it +offset (08:00 → 10:00 in CEST).
|
||||
// Preserving the user's intended wall-clock means stamping it here.
|
||||
// Date-only values (no "T") pass through unchanged.
|
||||
function withLocalTzOffset(value: string): string {
|
||||
if (!value || !value.includes('T')) return value
|
||||
// The form's "YYYY-MM-DDTHH:MM" is parsed by JS Date as local time;
|
||||
// getTimezoneOffset() returns minutes west of UTC, so negate it.
|
||||
const offMin = -new Date(value).getTimezoneOffset()
|
||||
const sign = offMin >= 0 ? '+' : '-'
|
||||
const abs = Math.abs(offMin)
|
||||
const hh = String(Math.floor(abs / 60)).padStart(2, '0')
|
||||
const mm = String(abs % 60).padStart(2, '0')
|
||||
// Include `:00` seconds for compatibility with older Python
|
||||
// `datetime.fromisoformat` (pre-3.11 won't accept "HH:MM+HH:MM").
|
||||
return `${value}:00${sign}${hh}:${mm}`
|
||||
}
|
||||
|
||||
const formSchema = toTypedSchema(
|
||||
z
|
||||
.object({
|
||||
|
|
@ -138,8 +160,11 @@ interface BannerImage extends UploadedImage {
|
|||
}
|
||||
const bannerImages = ref<BannerImage[]>([])
|
||||
|
||||
// Inverse of foldDateTime: split a stored "YYYY-MM-DD[THH:MM]" back
|
||||
// into separate date + time pieces for the form inputs.
|
||||
// Inverse of foldDateTime: split a stored "YYYY-MM-DD[THH:MM[:SS][±HH:MM]]"
|
||||
// back into separate date + time pieces for the form inputs. The
|
||||
// time slice trims to "HH:MM" so any seconds + offset suffix added by
|
||||
// withLocalTzOffset on submit drops cleanly — the user sees the same
|
||||
// wall-clock they originally entered when re-editing.
|
||||
function splitDateTime(value: string | null | undefined): { date: string; time: string } {
|
||||
if (!value) return { date: '', time: '' }
|
||||
const [date, time = ''] = value.split('T')
|
||||
|
|
@ -267,9 +292,8 @@ const onSubmit = form.handleSubmit(async (formValues) => {
|
|||
try {
|
||||
const eventData: CreateEventRequest = {
|
||||
name: formValues.name,
|
||||
event_start_date: foldDateTime(
|
||||
formValues.event_start_date,
|
||||
formValues.event_start_time
|
||||
event_start_date: withLocalTzOffset(
|
||||
foldDateTime(formValues.event_start_date, formValues.event_start_time)
|
||||
),
|
||||
}
|
||||
if (!isEditMode.value) {
|
||||
|
|
@ -281,9 +305,8 @@ const onSubmit = form.handleSubmit(async (formValues) => {
|
|||
// Optional fields — only include if provided
|
||||
if (formValues.info) eventData.info = formValues.info
|
||||
if (formValues.event_end_date) {
|
||||
eventData.event_end_date = foldDateTime(
|
||||
formValues.event_end_date,
|
||||
formValues.event_end_time
|
||||
eventData.event_end_date = withLocalTzOffset(
|
||||
foldDateTime(formValues.event_end_date, formValues.event_end_time)
|
||||
)
|
||||
}
|
||||
if (formValues.location) eventData.location = formValues.location
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue