Skip to content

Commit 8f0253a

Browse files
committed
Recompute timezone adjustments for a given date.
Different dates can have different timezone adjustments in the case that the client timezone and server timezone are different and one of those time zones adheres to daylight savings time and the other does not. For example if the client timezone is America/Phoenix and the server timezone is America/Chicago. The America/Phoenix timezone does not adhere to daylight savings time and is always UTC-7 while America/Chicago is UTC-5 during daylight savings time, but is UTC-6 during standard time. So if an instructor is in the America/Phoenix timezone, but working on a server set for the America/Chicago timezone and selects a date that is during daylight savings time, then the current code use an incorrect differential of 1 hour because it uses the same differential for all dates. So this computes the timezone adjustment for a given date so that the correct timezone differential for that time is used. This fixes issue #2654.
1 parent f1da2b1 commit 8f0253a

File tree

2 files changed

+32
-21
lines changed

2 files changed

+32
-21
lines changed

htdocs/js/DatePicker/datepicker.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,25 @@
3333
const reduced_rule = document.getElementById(`${name}.reduced_scoring_date_id`);
3434
if (reduced_rule) groupRules.splice(1, 0, [reduced_rule]);
3535

36-
// Compute the time difference between the current browser timezone and the course timezone.
36+
// Compute the time difference between a time in the browser timezone and the same time in the course timezone.
3737
// flatpickr gives the time in the browser's timezone, and this is used to adjust to the course timezone.
38-
// Note that this is in seconds.
39-
const timezoneAdjustment =
40-
new Date(new Date().toLocaleString('en-US')).getTime() -
41-
new Date(
42-
new Date().toLocaleString('en-US', { timeZone: open_rule.dataset.timezone ?? 'America/New_York' })
43-
).getTime();
38+
// Note that the input time is in seconds and output times is in milliseconds.
39+
const timezoneAdjustment = (time) => {
40+
const dateTime = new Date(0);
41+
dateTime.setUTCSeconds(time);
42+
return (
43+
new Date(dateTime.toLocaleString('en-US')).getTime() -
44+
new Date(
45+
dateTime.toLocaleString('en-US', { timeZone: open_rule.dataset.timezone ?? 'America/New_York' })
46+
).getTime()
47+
);
48+
};
4449

4550
for (const rule of groupRules) {
4651
const classValue = document.getElementsByName(`${rule[0].name}.class_value`)[0]?.dataset.classValue;
4752
const value = rule[0].value || classValue;
48-
rule.push(value ? parseInt(value) * 1000 - timezoneAdjustment : 0);
49-
if (classValue) rule.push(parseInt(classValue) * 1000 - timezoneAdjustment);
53+
rule.push(value ? parseInt(value) * 1000 - timezoneAdjustment(parseInt(value)) : 0);
54+
if (classValue) rule.push(parseInt(classValue) * 1000 - timezoneAdjustment(parseInt(classValue)));
5055
}
5156

5257
const update = (input) => {
@@ -156,7 +161,8 @@
156161
parseDate(datestr, format) {
157162
// Deal with the case of a unix timestamp. The timezone needs to be adjusted back as this is for
158163
// the unix timestamp stored in the hidden input whose value will be sent to the server.
159-
if (format === 'U') return new Date(parseInt(datestr) * 1000 - timezoneAdjustment);
164+
if (format === 'U')
165+
return new Date(parseInt(datestr) * 1000 - timezoneAdjustment(parseInt(datestr)));
160166

161167
// Next attempt to parse the datestr with the current format. This should not be adjusted. It is
162168
// for display only.
@@ -171,7 +177,7 @@
171177
formatDate(date, format) {
172178
// In this case the date provided is in the browser's time zone. So it needs to be adjusted to the
173179
// timezone of the course.
174-
if (format === 'U') return (date.getTime() + timezoneAdjustment) / 1000;
180+
if (format === 'U') return (date.getTime() + timezoneAdjustment(date.getTime() / 1000)) / 1000;
175181

176182
return luxon.DateTime.fromMillis(date.getTime()).toFormat(
177183
datetimeFormats[luxon.Settings.defaultLocale]

htdocs/js/ProblemSetList/problemsetlist.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,22 @@
179179
if (importDateShift) {
180180
luxon.Settings.defaultLocale = importDateShift.dataset.locale ?? 'en';
181181

182-
// Compute the time difference between the current browser timezone and the course timezone.
182+
// Compute the time difference between a time in the browser timezone and the same time in the course timezone.
183183
// flatpickr gives the time in the browser's timezone, and this is used to adjust to the course timezone.
184-
// Note that this is in seconds.
185-
const timezoneAdjustment =
186-
new Date(new Date().toLocaleString('en-US')).getTime() -
187-
new Date(
188-
new Date().toLocaleString('en-US', { timeZone: importDateShift.dataset.timezone ?? 'America/New_York' })
189-
).getTime();
184+
// Note that the input time is in seconds and output times is in milliseconds.
185+
const timezoneAdjustment = (time) => {
186+
const dateTime = new Date(0);
187+
dateTime.setUTCSeconds(time);
188+
return (
189+
new Date(dateTime.toLocaleString('en-US')).getTime() -
190+
new Date(
191+
dateTime.toLocaleString('en-US', { timeZone: open_rule.dataset.timezone ?? 'America/New_York' })
192+
).getTime()
193+
);
194+
};
190195

191196
let fallbackDate = importDateShift.value
192-
? new Date(parseInt(importDateShift.value) * 1000 - timezoneAdjustment)
197+
? new Date(parseInt(importDateShift.value) * 1000 - timezoneAdjustment(parseInt(importDateShift.value)))
193198
: new Date();
194199

195200
const fp = flatpickr(importDateShift.parentNode, {
@@ -248,7 +253,7 @@
248253
parseDate(datestr, format) {
249254
// Deal with the case of a unix timestamp. The timezone needs to be adjusted back as this is for
250255
// the unix timestamp stored in the hidden input whose value will be sent to the server.
251-
if (format === 'U') return new Date(parseInt(datestr) * 1000 - timezoneAdjustment);
256+
if (format === 'U') return new Date(parseInt(datestr) * 1000 - timezoneAdjustment(parseInt(datestr)));
252257

253258
// Next attempt to parse the datestr with the current format. This should not be adjusted. It is
254259
// for display only.
@@ -263,7 +268,7 @@
263268
formatDate(date, format) {
264269
// In this case the date provided is in the browser's time zone. So it needs to be adjusted to the
265270
// timezone of the course.
266-
if (format === 'U') return (date.getTime() + timezoneAdjustment) / 1000;
271+
if (format === 'U') return (date.getTime() + timezoneAdjustment(date.getTime() / 1000)) / 1000;
267272

268273
return luxon.DateTime.fromMillis(date.getTime()).toFormat(
269274
datetimeFormats[luxon.Settings.defaultLocale]

0 commit comments

Comments
 (0)