skip to Main Content

The issue at a high level:

A hotel owner sets a time range as to when a reservation can be booked at a restaurant (5pm – 10pm). In this record, there will also be a timezone, so when the data gets displayed to a user, I can convert the date to the original timezone it was encoded in. This is so a user in another timezone can see the dates as they were intended and not encoded into their local timezone.

The issue:

If a user is in another timezone, making a reservation, their data will be stored as so:

date: DateObj

timezone: zyx

If I am now trying to retrieve all the reservations for the day, I am foreshadowing an issue:

  1. If the UTC timestamp is less the previous / next day it will not be found

here is a snippet of the grabbing method

const startOfDay = new Date(dateParam);
startOfDay.setHours(0, 0, 0, 0);

const startOfNextDay = new Date(startOfDay);
startOfNextDay.setDate(startOfDay.getDate() + 1);

const reservations = await this.reservationModel
  .find({
    reservationDate: {
      $gte: startOfDay,
      $lt: startOfNextDay,
    },
    restaurantId: restaurantId,
  })

Potential solution:

I could pass the date as a broken up string

{
   day: 12,
   month:11,
   year:2024,
   time:xyz
}

and construct the date using the servers timezone so it will always be consistent. So when I am getting the reservations, there will be no time zoning issues since all dates will be in the servers timezone.

I was curious to know if I could set the startOfDay date variable to use the start of the UTC day. Would this be something that would work as well?

2

Answers


  1. Setting the startOfDay variable to the start of the UTC day can indeed be an option to avoid timezone issues. This will ensure consistency in how dates are handled regardless of the user’s timezone.
    You can achieve this by using methods like setUTCHours, setUTCMinutes, and setUTCSeconds to set the time components to zero in the UTC timezone. Something like this should theoritically work,

    const startOfDay = new Date(dateParam)
    startOfDay.setUTCHours(0, 0, 0, 0) // ...set hours, minutes, seconds, and milliseconds to zero in UTC timezone
    
    const startOfNextDay = new Date(startOfDay)
    startOfNextDay.setUTCDate(startOfDay.getUTCDate() + 1) // ...increment UTC date by 1 to get the start of the next UTC day
    
    const reservations = await this.reservationModel
      .find({
        reservationDate: {
          $gte: startOfDay,
          $lt: startOfNextDay,
        },
        restaurantId: restaurantId,
      })
    
    Login or Signup to reply.
  2. I don’t agree with @Matt Johnson-Pint. A Date is a Date and Date Objects in MongoDB / JavaScript are stored as UTC time, this you cannot change. But actually you should not care about the internal storage format of a Date object. For example, in Oracle DATE are stored as internal binary value, there you don’t care either.

    Storing Date/Time values as string is a design flaw, you should never do that. This is not limited to MongoDB, it applies to any database. Here on SO you can find hundreds of question where people run into problems because they store date values wrongly as string.

    Now, having said all this, regarding to your question: In general, when people have to work with times and timezones I recommend to use a 3rd party Date library, e.g. Luxon, Day.js or (deprecated) moment. They are much easier to use.

    In your case the solution could be this one:

    const { DateTime, Settings } = require("luxon");
    
    const reservation = DateTime.fromISO('2024-02-16T19:00:00', { zone: 'America/New_York' });
    // or if you prefer
    const reservation = DateTime.fromObject(
       { year: 2024, month: 11, day: 12, hour: 10, minute: 26 },
       { zone: 'America/New_York' }
    )
    
    db.reservations.insertOne({
       restaurantId: 1,
       reservationDate: reservation.toJSDate() // or your native `Date` object
    })
    

    If you like to get all reservations from a specific day, it could be

    const startOfDay = DateTime.fromISO('2024-02-16', { zone: 'America/New_York' }).startOf('day');
    const endOfDay = DateTime.fromISO('2024-02-16', { zone: 'America/New_York' }).endOf('day');
    
    db.reservations.find({
       reservationDate: {
          $gte: startOfDay.toJSDate(),
          $lte: endOfDay.toJSDate(),
       },
       restaurantId: 1
    })
    

    All your times are in New York time zone, thus you can also use it as default:

    Settings.defaultZone = 'America/New_York';
    // Most likely it will be already set by your system settings
    const reservation = DateTime.fromISO('2024-02-16T19:00:00');
    // or
    const reservation = DateTime.local(2024, 02, 16, 19);
    
    const startOfDay = DateTime.fromISO('2024-02-16').startOf('day');
    const endOfDay = DateTime.fromISO('2024-02-16').endOf('day');
    

    will do the same.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search