skip to Main Content

I am trying to apply the filter based on date in aggregation pipeline of mongo. See the aggregation pipeline below :

var projectQry = [
      {
        $match: {
          "prmid": userId
        }
      },
      {
        "$unwind": {
          path : '$performanceData'
        }
      },
      {
        $match: {
          performanceData.recharge_date": {
            $gte: fromDate, $lte: toDate
          }
        }
      },
      {
        $group : {
          _id: "$performanceData.campaign_name", 
          basecount: {
            $sum: "$performanceData.basecount"
          }
        }
      },
      {
        $project: {
          _id: 0,
          campaign_name: "$_id",
          basecount: 1
        }
      }
    ];

Now, the fromDate and toDate I am getting from below logic. Actually, I am trying to get the data between 1st and 12th of the current month from recharge_date field:

    const date = new Date();
    var fromDate = new Date(`${date.getFullYear()}-${date.getMonth()+1}-${01}`);
    var toDate = new Date(`${date.getFullYear()}-${date.getMonth()+1}-${12}`);

But, When I am printing the fromDate and toDate in console, it is showing the below output :

2023-02-21T18:30:00.000Z
2023-03-02T18:30:00.000Z

I am not able to figure out how to remove this 18:30:00.000 time because of which I am getting wrong date as it is going 5 hours 30 minutes back of the time which I have defined in fromDate and toDate. Timezone is playing some role here.

I tried to use setHours(0,0,0,0) also but no success.

Thanks in advance for any response.

3

Answers


  1. Chosen as BEST ANSWER

     const date = new Date();
    var fromDate = new Date(`${date.getFullYear()}-${date.getMonth()+1}-${02}`);
    fromDate.setUTCHours(0,0,0,0);
    var toDate = new Date(`${date.getFullYear()}-${date.getMonth()+1}-${13}`);
    toDate.setUTCHours(0,0,0,0);
    
    console.log(fromDate);
    console.log(toDate);

    This will print :

    2023-02-01T00:00:00.000Z
    2023-02-12T00:00:00.000Z
    

    setUTCHours() method is what we need to use.


  2. Edit

    Please see RobG’s answer for an explanation on why the behavior described by OP occurs and how you can use padding to get the expected result.

    While my answer will resolve the issue, due to not parsing the actual string but instead providing year, month and day as numbers, it does not cover reasons on why parsing the string does not yield the expected result and why the result might differ on different browsers/ implementations of the ECMA standard.

    Orginal answer (please see edit!)

    The difference results from the date time offset of your timezone. You need to create the date using Date.UTC() in order to get the time in UTC.

    The following will demonstrate the difference:

    // 27th February, 2023 (Local time)
    const localDate = new Date(2023, 1, 27);
    // will display in your local time
    console.log(localDate.toISOString());
    // 27th February, 2023 (UTC)
    const utcDate = new Date(Date.UTC(2023, 1, 27));
    // will display in UTC => time part of string will be all zeroes
    console.log(utcDate.toISOString());
    
    // date time offset
    const offset = utcDate - localDate;
    const offsetInSeconds = offset / 1000;
    const offsetInMinutes = offsetInSeconds / 60;
    const offsetInHours = offsetInMinutes / 60;
    const remainingMinutes = offsetInMinutes % 60;
    // For you (OP) this should be 5h 30min, but may vary for others based on their local time
    console.log(`Offset: ${offsetInHours}h ${remainingMinutes}min`);
    Login or Signup to reply.
  3. The issue is that in the code:

    let date = new Date();
    let fromDate = new Date(`${date.getFullYear()}-${date.getMonth()+1}-${01}`);
    

    single digit months and days aren’t being padded, so you end up with a string in Feb 2023 like "2023-2-1" (note that the number 01 in ${01} will be stringified as "1"). That isn’t consistent with the format supported by ECMAScript, so parsing is implementation dependent and may be treated as UTC, local or invalid.

    In the OP’s case, it’s being treated as local. In Safari, it’s treated as invalid.

    If single digit months a days are padded, it will parse as UTC:

    // Pad single digits with leading zero
    let pad = n => ('0' + n).slice(-2);
    
    let d = new Date();
    // Note: use string "01" not number 01
    let fromDate = new Date(`${d.getFullYear()}-${pad(d.getMonth()+1)}-${'01'}`);
    let toDate = new Date(`${d.getFullYear()}-${pad(d.getMonth()+1)}-${'12'}`);
    
    console.log(fromDate.toISOString()+'n'+
                toDate.toISOString());
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search