From f9e16964e160f94090d82242a2d02878a9165896 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 18 Oct 2022 18:36:13 -0500 Subject: [PATCH] Fix off-by-one calendar months with time zones that are greater than UTC+0 (#86) Fix off-by-one calendar months with time zones that are greater than UTC+0 (GMT+0). Fix https://github.com/matrix-org/matrix-public-archive/issues/77 Previously, we would calculate `lastDayOfTheMonthDate` in the local timezone because we were using the vanilla `new Date(year, month, 0)` constructor. For any timezone greater than `UTC+0` (like London UTC+1 or Korea UTC +9), this means that the date is a day-behind when we go back to UTC+0. **Before:** ``` inputDate Fri, 29 Jul 2022 00:00:00 GMT 1659052800000 lastDayOfTheMonthDate Sat, 30 Jul 2022 23:00:00 GMT 1659222000000 lastDayOfTheMonth 30 ``` **After** ``` inputDate Fri, 29 Jul 2022 00:00:00 GMT 1659052800000 lastDayOfTheMonthDate Sun, 31 Jul 2022 00:00:00 GMT 1659225600000 lastDayOfTheMonth 31 ``` --- shared/views/CalendarView.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/shared/views/CalendarView.js b/shared/views/CalendarView.js index 98cc06f..c650317 100644 --- a/shared/views/CalendarView.js +++ b/shared/views/CalendarView.js @@ -12,13 +12,18 @@ function sameDay(date1, date2) { ); } -// Month in JavaScript is 0-indexed (January is 0, February is 1, etc), -// but by using 0 as the day it will give us the last day of the prior -// month. +// Get the number of days in the given month where the `inputDate` lies. // // via https://stackoverflow.com/a/1184359/796832 -function numDaysInMonthForDate(date) { - return new Date(date.getUTCFullYear(), date.getUTCMonth() + 1, 0).getUTCDate(); +function numDaysInMonthForDate(inputDate) { + // Month in JavaScript is 0-indexed (January is 0, February is 1, etc), + // but by using 0 as the day it will give us the last day of the prior + const lastDayOfTheMonthDate = new Date( + Date.UTC(inputDate.getUTCFullYear(), inputDate.getUTCMonth() + 1, 0) + ); + const lastDayNumberOfTheMonth = lastDayOfTheMonthDate.getUTCDate(); + // The last day number in the month is a proxy for how many days there are in that month + return lastDayNumberOfTheMonth; } // Map from day of week to the localized name of the day @@ -147,9 +152,10 @@ class CalendarView extends TemplateView { }), (() => { const todayTs = Date.now(); + const numberOfDaysInMonth = numDaysInMonthForDate(calendarDate); let dayNodes = []; - for (let i = 0; i < numDaysInMonthForDate(calendarDate); i++) { + for (let i = 0; i < numberOfDaysInMonth; i++) { const dayNumberDate = new Date(calendarDate); // Date is a 1-based number dayNumberDate.setUTCDate(i + 1);