From 8aef480037b82a8082f5b871886efef7f1b3d23c Mon Sep 17 00:00:00 2001 From: Jakob Stechow Date: Mon, 18 Nov 2024 00:06:53 +0100 Subject: [PATCH] fix: utc times in scheduler (#136) --- backend/src/utils/date.ts | 66 +++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/backend/src/utils/date.ts b/backend/src/utils/date.ts index ad11caf..ac5e0fc 100644 --- a/backend/src/utils/date.ts +++ b/backend/src/utils/date.ts @@ -2,56 +2,47 @@ import { DefaultPostgresInterval } from './interval'; // TODO: this will only work for UTC+2, overall we need to add a local time zone in the recurring task group and do all the stuff dynamic. export function getStartOfInterval(interval: DefaultPostgresInterval): Date { - //HOTFIX: This seems very hacky. We should think of something more elegant to handle this in the future, also consider the case when + // HOTFIX: This seems very hacky. We should think of something more elegant to handle this in the future, also consider the case when // assignment scheduler runs during the changing days of DST. - // Function to check if the current date is in the DST period (from last Sunday in March to last Sunday in October) - const isDSTPeriod = (date: Date) => { - const year = date.getFullYear(); - const lastSundayInMarch = new Date(year, 2, 31); // Start from March 31 - lastSundayInMarch.setDate( - lastSundayInMarch.getDate() - lastSundayInMarch.getDay(), - ); // Find the last Sunday in March - const lastSundayInOctober = new Date(year, 9, 31); // Start from October 31 - lastSundayInOctober.setDate( - lastSundayInOctober.getDate() - lastSundayInOctober.getDay(), - ); // Find the last Sunday in October - return date >= lastSundayInMarch && date < lastSundayInOctober; - }; - // Determine target hour based on whether it's DST period - const targetHour = isDSTPeriod(new Date()) ? 22 : 23; // 22:00 during DST, 23:00 afterward + const targetHour = getIsDSTPeroid(new Date()) ? 22 : 23; // 22:00 during DST, 23:00 afterward switch (interval) { // Go back to previous day at the calculated target hour case '1 day': { const todayTargetTime = new Date(); - todayTargetTime.setHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) + todayTargetTime.setUTCHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) // Go back to previous day - return new Date(todayTargetTime.setDate(todayTargetTime.getDate() - 1)); + return new Date( + todayTargetTime.setUTCDate(todayTargetTime.getUTCDate() - 1), + ); } // Go back to previous Sunday at the calculated target hour case '7 days': { const now = new Date(); const todayTargetTime = new Date(now); - todayTargetTime.setHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) + todayTargetTime.setUTCHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) - if (now.getDay() === 0 && now.getTime() >= todayTargetTime.getTime()) { + if (now.getUTCDay() === 0 && now.getTime() >= todayTargetTime.getTime()) { // If it's Sunday and past target hour, return today at the target hour return todayTargetTime; } else { // Otherwise, find the previous Sunday at target hour const previousSundayTargetTime = new Date(todayTargetTime); - const daysSinceSunday = (now.getDay() + 7) % 7; - previousSundayTargetTime.setDate( - previousSundayTargetTime.getDate() - daysSinceSunday, + const daysSinceSunday = (now.getUTCDay() + 7) % 7; + previousSundayTargetTime.setUTCDate( + previousSundayTargetTime.getUTCDate() - daysSinceSunday, ); - if (now.getDay() === 0 && now.getTime() < todayTargetTime.getTime()) { + if ( + now.getUTCDay() === 0 && + now.getTime() < todayTargetTime.getTime() + ) { // If it's Sunday but before target hour, go back to the previous Sunday - previousSundayTargetTime.setDate( - previousSundayTargetTime.getDate() - 7, + previousSundayTargetTime.setUTCDate( + previousSundayTargetTime.getUTCDate() - 7, ); } @@ -64,15 +55,15 @@ export function getStartOfInterval(interval: DefaultPostgresInterval): Date { case '1 mon': const now = new Date(); const firstDayOfCurrentMonth = new Date( - now.getFullYear(), - now.getMonth(), + now.getUTCFullYear(), + now.getUTCMonth(), 1, ); const dayBeforeFirstDayOfCurrentMonth = new Date(firstDayOfCurrentMonth); - dayBeforeFirstDayOfCurrentMonth.setDate( - dayBeforeFirstDayOfCurrentMonth.getDate() - 1, + dayBeforeFirstDayOfCurrentMonth.setUTCDate( + dayBeforeFirstDayOfCurrentMonth.getUTCDate() - 1, ); - dayBeforeFirstDayOfCurrentMonth.setHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) + dayBeforeFirstDayOfCurrentMonth.setUTCHours(targetHour, 0, 0, 0); // Set to target hour (22 or 23 based on DST) return dayBeforeFirstDayOfCurrentMonth; } } @@ -82,3 +73,16 @@ export function addDays(date: Date, days: number) { newDate.setUTCDate(date.getUTCDate() + days); return newDate; } + +export function getIsDSTPeroid(date: Date) { + const year = date.getFullYear(); + const lastSundayInMarch = new Date(year, 2, 31); + lastSundayInMarch.setUTCDate( + lastSundayInMarch.getDate() - lastSundayInMarch.getDay(), + ); + const lastSundayInOctober = new Date(year, 9, 31); + lastSundayInOctober.setUTCDate( + lastSundayInOctober.getDate() - lastSundayInOctober.getDay(), + ); + return date >= lastSundayInMarch && date < lastSundayInOctober; +}