Different dates from the request on localhost and production

99 views Asked by At

I am sending info from front-end to back-end, one crucial part of the info is the date it was sent. I am using React and Node.js Express. It was working correctly while I was working on my own machine, I get the Date, make it in the correct time zone of the user that sent it, and save it to the database. How ever when I put my project in production: back-end - ''Cyclic.sh", front-end - Vercel, the dates I recieve in the back-end are in the wrong format.

For dates manipulation I used Luxon.

Here is how I receive them:

const { prods, createdAt, ...rest } = req.body;
  if (prods.length < 1)
    return res.status(400).json({ error: "At least one product is required" });
  const luxonDate = DateTime.fromISO(createdAt);
  console.log(luxonDate);
  if (luxonDate.invalidExplanation)
    return res.status(400).json({ error: luxonDate.invalidExplanation });
  const normalizedDate = luxonDate.toISO();

Here is how I send them:

const handleSaveMeal = () => {
    const currentDate = new Date();
    postMealWithProducts.mutate({
      ...mealInfo,
      prods: mealProducts,
      title: selectedMealType,
      isPortion: isPortion,
      createdAt: currentDate,
    });

Both on local machine and in production if I try to log the date before sending it shows the same format (local time). But on production when I receive it, it is 2 hours behind my time, even though on localhost I receive the date of my time.
What could be the reason for this phenomena?

When I log the dates in the back-end, that what I get:
Localhost - Normalized 2023-11-08T19:58:24.323+02:00

Production - Normalized 2023-11-08T18:01:18.358+00:00

2

There are 2 answers

0
Aušrys Mikoliūnas On BEST ANSWER

The problem was that when I logged the date in the front-end my console in the Chrome showed me the full date with the offset, which made me think that the date is going to be sent in the normal format. However in the comments it was explained to me that it only sends the date with out the offset. It can be seen when I copied the console output and pasted here, it showed the date with out the offset (maybe Chrome add's the offset). So in the front-end I added the offset:

const currentDate = new Date();
const userTimezone = currentDate.getTimezoneOffset();
postMealWithProducts.mutate({
  ...mealInfo,
  prods: mealProducts,
  title: selectedMealType,
  isPortion: isPortion,
  createdAt: currentDate,
  userTimezone: userTimezone,
});

Then in the back-end I edit the code so that Luxon would add the offset. The offset is multiplied by minus 1, because the function getTimezoneOffset() returns the difference date provided and the utc in minutes which are negative if timezone is ahead and positive if it's behind. The luxon does this vice versa, ahead timezone is positive and behind is negative, that is why I multiplied it by -1.

const { prods, createdAt, userTimezone, ...rest } = req.body;
if (prods.length < 1)
return res.status(400).json({ error: "At least one product is required" });
const luxonDate = DateTime.fromISO(createdAt, { zone: userTimezone * -1 });
if (luxonDate.invalidExplanation)
return res.status(400).json({ error: luxonDate.invalidExplanation });
const normalizedDate = luxonDate.toISO();
4
Matt Johnson-Pint On

It's not two hours behind your time, it's just that it's two hours offset, because the production environment uses UTC as its local time zone. That is the best practice, as it alerts you to issues like this one.

When you parse the string using DateTime.fromISO, the default time zone will be the computer's local time zone. If you want a different time zone, then you can override that behavior by providing a zone in the options - or you can use setZone on the resulting DateTime object.

However, I suspect what you want here is to retain the local time and offset that were provided in the original input string. To do that, set setZone: true when parsing:

const luxonDate = DateTime.fromISO(createdAt, { setZone: true });

Of course, this presumes that the createdAt string actually contains an offset, such as +02:00 in the example you showed. It's difficult to tell though, because I don't know what your postMealWithProducts.mutate function does with regard to converting the createdDate from a Date object to a string. If it's sending the offset then you should be fine. If however it's just sending the UTC time (offset: Z) then the server has no ability to retain the local time and offset, because you didn't send it from the client.