Search code examples
javascriptdatecomparemomentjsutc

Date to UTC string return date in one day but comparison return false


I am trying to convert these dates to UTC string with toUTCString() method!

const date1 = "2000-01-01T00:00:00Z";
const date2 = "2000-01-01T11:15:02Z";

The result is

 Sat, 01 Jan 2000 11:15:02 GMT 
 Sat, 01 Jan 2000 00:00:00 GMT:

but when I compare dates together with moment library

function isSameDay(date1, date2) {
  let d1 = new Date(date1);
  let d2 = new Date(date2);
  return moment(d1).isSame(moment(d2), "day");
}

let date1 = "2000-01-01T00:00:00Z";
let date2 = "2000-01-01T11:15:02Z";

console.log(isSameDay(date1, date2));
<script src="https://unpkg.com/[email protected]/moment.js"></script>

I have received false - Can any body guide me why this happened? I know in local time, when i convert them toString() they are in different date.

local with toString() method

Sat Jan 01 2000 06:15:02 GMT-0500 (Eastern Standard Time)
Fri Dec 31 1999 19:00:00 GMT-0500 (Eastern Standard Time)

Thanks


Solution

  • As you've discovered, moment.js compares the local date (which is probably the most common requirement). To compare as UTC, you can either:

    1. Convert to a timestamp in timezone +0 and compare just the date part, or
    2. Divide the date's time value by the number of milliseconds in one day and floor it (since in ECMAScript UTC days always have exactly 8.64e7 ms)

    Option 1

    If you start with Date objects, you can just do:

    date1.toLocaleDateString('en-ca',{timeZone:'UTC'}) == date2.toLocaleDateString('en-ca',{timeZone:'UTC'})
    

    as language "en-ca" generates a date in format YYYY-MM-DD (you could probably use any language, but an ISO 8601 like format seems appropriate). The important part is timezone: 'UTC'

    Another option is the date part of toISOString:

    date1.toISOString().substring(0,10) == date2.toISOString().substring(0,10)
    

    If you really want to use moment.js, use it to format the dates as UTC timestamps:

    /** Return true if date1 and date2 are same UTC day
      *
      * @param {Date} date1
      * @param {Date} date2
      * @returns {boolean} true if dates match, false otherwise
      */
    function isSameUTCDay(date1, date2) {
      let format = 'YYYY-MM-DD';
      let d1 = moment(date1).utc();
      let d2 = moment(date2).utc();
      return d1.format(format) == d2.format(format);
    }
    
    // Same UTC day but different local day anywhere but UTC +0
    let date1 = "2000-01-01T00:00:00Z";
    let date2 = "2000-01-01T23:59:59Z";
    
    console.log(isSameUTCDay(date1, date2));
    <script src="https://unpkg.com/[email protected]/moment.js"></script>

    Option 2

    To compare as time values:

    /** Return true if the UTC date for date1 and date2 are the same
      *
      * @param {Date} date1
      * @param {Date} date2
      * @returns {boolean} true if dates match, false otherwise
      */
    function isSameUTCDay(date1, date2) {
      return Math.floor(+date1 / 8.64e7) == Math.floor(+date2 / 8.64e7);
    }
    
    // Same UTC day but different local day anywhere but UTC +0
    let date1 = "2000-01-01T00:00:00Z";
    let date2 = "2000-01-01T23:59:59Z";
    
    // Should be true everywhere
    console.log(isSameUTCDay(new Date(date1), new Date(date2)));

    PS. Using the built–in parser is strongly discouraged, however since the timestamp format is supported by ECMAScript I think it's OK for this example.