PTO schedule block shifts back by one day

Objective

  • Fix calendar Block (PTO / time-off style) events so the saved and displayed span matches what staff enter—especially when a single block crosses calendar days (e.g. day one 8:00 AM through day two 7:00 PM).
  • Eliminate off-by-one calendar day behavior where the block appears to shift (e.g. intended Nov 12–13 rendering as Nov 13–14) so scheduling and payroll-adjacent views stay trustworthy.

Background

  • Reported for Rob O’War, Axiom Inspections Colorado Attic profile: a PTO block entered for November 12 to November 13, 8 AM until November 13 at 7 PM, shifted back by a day and landed on November 13 to November 14; repro checked across Nov 12, 13, and 14.
  • A Block is a standard event document: datetime (start) and endtime (end) as full timestamps—multi-day coverage is not a separate flag; it is entirely the interval between those two instants (attik-backend/src/models/eventSchema.ts).
  • Single-event create path in AddEventModel (non–multi-date mode) submits tzDayjs(data.datetime) and tzDayjs(data.endtime) as one interval (or a one-row batch with the same pair). Multi-date mode is different: it creates one event per selected calendar date with the same clock times on each day—not one continuous cross-midnight span (attik-backend / attik-frontend AddEventModel.tsx). Triage should confirm which path the reporter used if repro is ambiguous.
  • Calendar placement anchors the row timeline to dates[0] and computes startHours, endHours, and lengthHours via findNumbers / calcHours in eventPlacementFunc.tsx—so intended rendering for a valid multi-day interval is one positioned bar, not per-day duplication from the placement algorithm alone.
  • Symptom class matches common timezone / date-boundary defects (local vs UTC, startOf('day') drift, DST near early November in US zones) or payload issues between UI and POST event / PATCH event. Decision needed after repro with stored raw datetime / endtime vs UI.

Recording: Loom — PTO block day shift

Slack: Message from ryan

Scope

Backend

  • attik-backend/src/models/eventSchema.tsdatetime / endtime persistence for type: 'Block'.
  • attik-backend/src/routes/ (event create/update/batch handlers) — how ISO strings are parsed and stored relative to company or inspector timezone; batch path used for multi-inspector creates.

Frontend

  • attik-frontend/src/app/tools/calendar/AddEventModel.tsx — single-interval vs isMultiDate batch semantics; tzDayjs usage when building payloads.
  • attik-frontend/src/components/calendar/useEventPlacement.tsfirstDate = dates[0] anchor for eventPlacementFuncMemoized.
  • attik-frontend/src/components/calendar/eventPlacementFunc.tsxcalcHours / findNumbers for cross-day lengthHours; edge cases when the visible week window and event span interact.
  • TimezoneContext / TZDayjs — ensure evaluation matches server expectations for the affected profile.

Product / architecture decisions (for the implementer)

  • Decision needed: Confirm failure is storage (DB shows wrong instants), fetch/transform, or display-only (placement or label—see related multi-day display issue if split).
  • Decision needed: Whether multi-date mode should be visually distinct in the UI so users do not confuse it with one continuous multi-day block.

Investigation outcomes (draft acceptance)

  • [ ] Capture raw datetime / endtime for a repro block before and after save; compare to Loom expectations.
  • [ ] Note company timezone, inspector, and whether DST boundary applies on the repro dates.
  • [ ] If root cause isolated, split API vs placement fixes if appropriate.

References

  • Loom — PTO block day shift
  • Slack thread
  • Event model: attik-backend/src/models/eventSchema.ts
  • Add / edit calendar event UI: attik-frontend/src/app/tools/calendar/AddEventModel.tsx
  • Placement: attik-frontend/src/components/calendar/eventPlacementFunc.tsx, useEventPlacement.ts

Please authenticate to join the conversation.

Upvoters
Status

Planned

Board
🏠

Main App

Date

16 days ago

Author

Linear

Subscribe to post

Get notified by email when there are changes.