BUG: Shared trip page day calculation ignores timezone (s/[shareSlug]) #3

Closed
opened 2026-05-09 00:26:29 +00:00 by Mark · 1 comment
Owner

Description

In src/app/s/[shareSlug]/page.tsx, the inline getDayPlans() function (line 71-82) uses toISOString().split("T")[0] to group items by day, which ignores the trip timezone. This can cause items to appear on the wrong day for non-UTC timezones.

Code

const getDayPlans = (): DayPlan[] => {
  if (!trip) return [];
  const start = new Date(trip.startDate);
  const end = new Date(trip.endDate);
  const days: DayPlan[] = [];
  for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
    const dateStr = d.toISOString().split("T")[0];  // BUG: no timezone
    const dayItems = items.filter(item => item.startAt && new Date(item.startAt).toISOString().split("T")[0] === dateStr);  // BUG: no timezone
    days.push({ date: dateStr, dayNumber: days.length + 1, items: dayItems });
  }
  return days;
};

Impact

  • A trip with timezone "Asia/Tokyo" might show items on the wrong day
  • The private trip detail page (/trips/[tripId]) uses the correct buildDayPlans() from the domain module which handles timezone with toLocaleDateString(en-CA, { timeZone: timezone })
  • The shared view should use the same domain function for consistency

Fix

Use buildDayPlans() from @/domain/day-plan instead of the inline implementation, passing trip.timezone.

Alternatively, use toLocaleDateString(en-CA, { timeZone: trip.timezone }) for date string computation.

## Description In `src/app/s/[shareSlug]/page.tsx`, the inline `getDayPlans()` function (line 71-82) uses `toISOString().split("T")[0]` to group items by day, which ignores the trip timezone. This can cause items to appear on the wrong day for non-UTC timezones. ## Code ```typescript const getDayPlans = (): DayPlan[] => { if (!trip) return []; const start = new Date(trip.startDate); const end = new Date(trip.endDate); const days: DayPlan[] = []; for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { const dateStr = d.toISOString().split("T")[0]; // BUG: no timezone const dayItems = items.filter(item => item.startAt && new Date(item.startAt).toISOString().split("T")[0] === dateStr); // BUG: no timezone days.push({ date: dateStr, dayNumber: days.length + 1, items: dayItems }); } return days; }; ``` ## Impact - A trip with timezone "Asia/Tokyo" might show items on the wrong day - The private trip detail page (`/trips/[tripId]`) uses the correct `buildDayPlans()` from the domain module which handles timezone with `toLocaleDateString(en-CA, { timeZone: timezone })` - The shared view should use the same domain function for consistency ## Fix Use `buildDayPlans()` from `@/domain/day-plan` instead of the inline implementation, passing `trip.timezone`. Alternatively, use `toLocaleDateString(en-CA, { timeZone: trip.timezone })` for date string computation.
Author
Owner

Fixed in commit a5510ba: the shared trip page (/s/[shareSlug]) hand-rolled day bucketing with toISOString() (UTC), ignoring trip.timezone — items near midnight landed on the wrong day. Now uses the domain buildDayPlans(items, start, end, timezone) helper, same as the member trip page.

Fixed in commit a5510ba: the shared trip page (/s/[shareSlug]) hand-rolled day bucketing with toISOString() (UTC), ignoring trip.timezone — items near midnight landed on the wrong day. Now uses the domain buildDayPlans(items, start, end, timezone) helper, same as the member trip page.
Mark closed this issue 2026-08-12 03:47:10 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AuWoMe/planish#3
No description provided.