fix: handle datetime-local timezone conversion correctly

- Convert datetime-local values to UTC ISO strings before sending to API
  (new Date(r).toISOString()) in both create and update flows
- Parse UTC ISO strings directly in API instead of manual Date.UTC() parsing
  that treated local components as UTC, causing timezone offset bugs
- Convert UTC API response times to local on load using new Date(str + 'Z')
  and date-fns format() to avoid double-timezone shift when editing
This commit is contained in:
Victor
2026-05-09 02:44:13 +00:00
parent 4b8d75617b
commit f4e3919417
4 changed files with 17 additions and 21 deletions

View File

@@ -77,15 +77,9 @@ export async function PUT(
nextOccurrence: nextOccurrence ? new Date(nextOccurrence) : undefined,
reminders: {
deleteMany: {},
create: (reminders || []).map((r: string) => {
// Parse local datetime string and construct Date to preserve local time
const [datePart, timePart] = r.split('T');
const [year, month, day] = datePart.split('-').map(Number);
const [hours, minutes] = timePart.split(':').map(Number);
return {
reminder: new Date(Date.UTC(year, month - 1, day, hours, minutes)),
};
}),
create: (reminders || []).map((r: string) => ({
reminder: new Date(r),
})),
},
},
include: {

View File

@@ -93,15 +93,9 @@ export async function POST(request: NextRequest) {
parentTaskId: parentTaskId || undefined,
sortOrder: (maxSort._max.sortOrder ?? 0) + 1,
reminders: {
create: (reminders || []).map((r: string) => {
// Parse local datetime string and construct Date to preserve local time
const [datePart, timePart] = r.split('T');
const [year, month, day] = datePart.split('-').map(Number);
const [hours, minutes] = timePart.split(':').map(Number);
return {
reminder: new Date(Date.UTC(year, month - 1, day, hours, minutes)),
};
}),
create: (reminders || []).map((r: string) => ({
reminder: new Date(r),
})),
},
},
include: {

View File

@@ -44,7 +44,11 @@ export default function EditTaskModal() {
.then(data => {
setSubtasks(data.subtasks || []);
if (data.reminders && data.reminders.length > 0) {
setReminders(data.reminders.map((r: any) => r.reminder));
// API returns UTC times — convert to local for datetime-local input
setReminders(data.reminders.map((r: any) => {
const d = new Date(r.reminder + 'Z');
return format(d, "yyyy-MM-dd'T'HH:mm");
}));
}
})
.catch(console.error);
@@ -81,7 +85,9 @@ export default function EditTaskModal() {
status,
recurrenceRule,
recurrenceInterval,
reminders: reminders.filter((r) => r !== ''),
reminders: reminders
.filter((r) => r !== '')
.map((r) => new Date(r).toISOString()),
}),
});

View File

@@ -66,7 +66,9 @@ export default function NewTaskModal() {
status,
recurrenceRule,
recurrenceInterval,
reminders: reminders.filter((r) => r !== ''),
reminders: reminders
.filter((r) => r !== '')
.map((r) => new Date(r).toISOString()),
}),
});