skip to Main Content

I’m trying to do an action when the date today (via Node.js) and the date value (via MongoDB) is the same. However, I’m not receiving any output from my for loop indicating that there’s no match.

Here’s how I get the date today (date output is 2023-01-19T00:00:00.000Z):

const d = new Date(new Date().toLocaleString("en-US", { timeZone: "Asia/Hong_Kong" }));
const day = d.getDate();
const month = d.getMonth() + 1;
const year = "2023"; //this is a dummy variable since year is required for Date().
const date = new Date(year + "-" + month + "-" + day);
console.log(date);

Here’s the users document from MongoDB:

name: "Angelo"
birthday: 2023-01-11T00:00:00.000+00:00 //Date data type

name: "Josh"
birthday: 2023-01-19T00:00:00.000+00:00 //Date data type

Here’s the for loop that should trigger success when there’s a match, but there’s no output. This is my problem.

let users = [];
db.collection("users").find({})
.forEach((user) => { users.push(user) })
.then(() => {
   for (i = 0; i < users.length; i++) {
      if(users[i].birthday == date) {
         console.log("Success"); //no output on console
      }
   }
})

Checking users[i].birthday in console shows:

  • 2023-01-19T00:00:00.000Z (Shouldn’t this be a match of today’s date?)
  • 2023-01-11T00:00:00.000Z

4

Answers


  1. MongoDB Date objects store values in UTC. In your example you create a date object in the local timezone, so your dates will not match.

    You can create a UTC zero date using the Date.UTC() static method, where zero date means a date with zero for the hours, minutes, and seconds. Here is an example that simulates your users array from MongoDB, assuming that the birthdays are all UTC zero dates. You can’t compare the date objects directly, because two date objects that have the same date have different object addresses. Therefore you need to compare the value of the date objects (.valueOf()), or a string representation (.toISOString()).

    function getUtcZeroDate(str) {
      if(str) {
        return new Date(str + 'T00:00:00.000Z');
      } else {
        let date = new Date();
        return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
      }
    }
    
    const users = [
      {name: 'Angelo', birthday: getUtcZeroDate('2023-01-11') },
      {name: 'Josh', birthday: getUtcZeroDate() }, // today
    ]
    
    const todayUtcZeroDate = getUtcZeroDate();
    console.log("Today's UTC zero date:", todayUtcZeroDate.toISOString());
    
    users.forEach(doc => {
      const match = (todayUtcZeroDate.valueOf() == doc.birthday.valueOf()) ? 'match' : 'no match';
      console.log(doc.name + ', born ' + doc.birthday.toISOString(), '=>', match);
    });

    Output at the time of writing:

    Today's UTC zero date: 2023-01-18T00:00:00.000Z
    Angelo, born 2023-01-11T00:00:00.000Z => no match
    Josh, born 2023-01-18T00:00:00.000Z => match
    
    Login or Signup to reply.
  2. A simple way to compare dates is to use setHours(0,0,0) for both birthday date and date like below:
    
    const d = new Date(new Date().toLocaleString("en-US", { timeZone: "Asia/Hong_Kong" }));
    const day = d.getDate();
    const month = d.getMonth() + 1;
    const year = "2023"; //this is a dummy variable since year is required for Date().
    let date = new Date(year + "-" + month + "-" + day);
    date=date.setHours(0,0,0)
    
    
    for fetching date and comparing from db:
    let users = [];
    db.collection("users").find({})
    .forEach((user) => { users.push(user) })
    .then(() => {
       for (i = 0; i < users.length; i++) {
           users[i].birthday=new Date(users[i].birthday).setHours(0,0,0)
          if(users[i].birthday == date) {
             console.log("Success"); // output on console
          }
       }
    })
    
    Try it you will get output.
    
    Login or Signup to reply.
  3. I suggest considering using moment.js for this.
    You’ll be also need moment-timezone.js add-on to use timezones.

    I recommend moment.js because with it, the code becomes more readable.

    moment.tz.setDefault("Asia/Hong_Kong");
    
    const users = [{
        name: "Angelo",
        birthday: new Date('2023-01-11T00:00:00.000+00:00'),
      },
      {
        name: "Josh",
        birthday: new Date('2023-01-19T00:00:00.000+00:00'),
      },
    ];
    
    const today = moment();
    
    for (i = 0; i < users.length; i++) {
      const user = users[i];
      if ( today.isSame(user.birthday, 'date')) {
        console.log("Success", users[i]);
      }
    }
    <script src="https://momentjs.com/downloads/moment.min.js"></script>
    <script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
    Login or Signup to reply.
  4. This is really just a date formatting issue.

    If you want to get the date in a particular location, you can use the Intl.DateTimeFormat constructor but get the parts as separate values rather than a timestamp that then must be parsed by the built–in parser. That’s a flawed methodology because the built–in parser isn’t required to correctly parse such input (same with toLocaleString).

    So to get the current date in a particular location and then built a timestamp that is 0hrs UTC:

    // Return the date at loc for the provided date as 
    // a Date set to year, month, day as UTC values.
    function toUTCDateFromLoc(loc, date = new Date()) {
      let f = new Intl.DateTimeFormat('en', {
        year: 'numeric',
        month: 'numeric',
        day: 'numeric',
        timeZone: loc
      });
      let {year, month, day} = f.formatToParts(date)
        .reduce((acc, part) => {
          acc[part.type] = part.value;
          return acc;
        }, Object.create(null));
      return new Date(Date.UTC(year, month - 1, day));
    }
    
    // Kirimati and Midway should always be at least 1 day different
    ['Pacific/Kiritimati', // +14
     'Asia/Hong_Kong',     //  +8
     'America/Dominica',   //  -4
     'Pacific/Midway',     // -11
    ].forEach(loc => console.log(
      `${loc.padEnd(18, ' ')}: ${toUTCDateFromLoc(loc).toISOString()}`
    ));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search