Django, datetime, and timezone

I realize this is only half a Django issue, but I feel like I can get some advice here.

Here’s the background: I have an LMS app which allows teachers to create exams which can optionally have a time limit. When undertaking an exam which has a time limit, students are shown a timer which informs them of how much remaining time they have.

In order to implement this, I have a field called begin_timestamp on the model that represents the user participation into the exam, which of course is a DateTime field which gets populated with the current date and time upon participation instance creation. Moreover, the exam model has a field named time_limit_seconds, which holds the integer number of seconds of the time limit (I chose to use seconds in order to be able to represent fraction-of-a-minute times with integer values).

The value for begin_timestamp is serialized by DRF and sent in this format: "2023-02-08 09:32:39".

This function on the frontend determines how many seconds are left for the current participation—it is called when the student beings the exam (or reloads the exam page) and serves as a starting value for the countdown timer:

export const getParticipationRemainingTime = (
	participation: ExamParticipation,
	exam: Exam,
): number | null => {
	if (exam.time_limit_seconds === null) {
		return null;
	}
	const endDate = new Date(participation.begin_timestamp);
	endDate.setSeconds(endDate.getSeconds() + exam.time_limit_seconds);

	return Math.max(Math.floor((endDate.getTime() - new Date().getTime()) / 1000), 0);
};

I’ll quickly note that this is only “cosmetic”, in order to show the student a timer during the exam: the actual checking is done on the backend.

So, here’s the issue: yesterday a foreign student was taking a university exam on my LMS platform. Apparently, she had a different timezone than that of the server: one hour forward. The exam had a time limit of less than an hour.

What happened is that, as soon as she started the exam, the timer showed her 0 seconds remaining.

What I realized, after investigating a bit, is that the culprit was most likely her timezone.
In particular, in the function above, while all calculations are done from the datetime sent by the backend, the new Date() instruction relies on the device datetime; therefore, if the two timezones don’t match, we have a problem.

I believe I could solve my issue by using a more “absolute” calculation, i.e. since all I want to measure is elapsed seconds since a reference starting point, I should be able to make a determination as to how much time the user has left solely based on the timestamps, by subtracting seconds.

How would you achieve this?

I apologize once again for the likely not-so-relevant question, but I have little knowledge of all things dates, so I’m trying to make sense of all the different formats etc. I feel like just sending the number of seconds since Jan 1st 1970 could be the right way to perform this computation, but I’m definitely open to advice.

What is calling this function?

Where does it get called, and under what conditions does it get called?

It is called on my vue frontend upon receiving the data about the exam and the participation from my DRF backend.

I’m doing some experimentation, but it appears that sending DateTime as Unix epoch milliseconds from Djabgo may fix the issue because the client never goes through actually considering the timezone. But other advice or input is welcome of course.

I’d go the other route. I’d calculate the time differential on the back end, and forward the time remaining out to the client on each request.

1 Like

Excellent advice. The more work I can do on the backend, the less depends on the client’s browser. I’ll make remaining_time a property of the exam participation model.