0

I am getting 4 dates as inputs mentioned below from an external source.

Dates with time element:

"InitialDate": "2019-02-19T12:03:22.129Z",
"updateDate": "2019-02-28T05:26:57.115Z",

Dates without time element:

"startDate": "2019-02-18",
"endDate": "2020-02-16",

I am coverting InitialDate and updateDate and creating actualInitDatE out of them using a moment format as below, as they are getting time element also in it.

I don't want time element and i only want date elements of all the 4 dates.

   const actualInitDatE = moment(InitialDate).format('MM-DD-YYYY') || 
  moment(updateDate).format('MM-DD-YYYY');

Now, I am converting the startDate and endDate which are having only date element in it (and no time element) and finally creating actualStartDate and actualEndDateW variables,

const actualStartDateW = moment(startDate).format('MM-DD-YYYY');
const actualEndDateW = moment(endDate).format('MM-DD-YYYY');

Now I am comparing them with the below logic and is working fine in IST,

if (actualInitDatE >= actualStartDateW && actualInitDatE <= actualEndDateW) {
          console.log('Compared and True');
}

My Doubt is will this work correctly in UTC and other time zones as well? I am doubtful because some of the dates have time elements and some of them have only the date elements.

I have gone through this and implemented the approach. Is this approach is correct or do we need to use any offset?

javascript Date timezone issue

Can someone help me in this regard and let me know if this code works across timeZones?

user1660325
  • 747
  • 4
  • 20
  • 35

2 Answers2

1

I believe the core issue here is that you must specify a timezone for startDate and endDate. If you don't, moment.js will assume local time, for example IST or let's say you were in the US, Pacific time. The problem with this approach is that the code will give inconsistent results (depending on the machine).

You can demonstrate this by running the snippet below in your browser (Chrome is best) and changing your machine timezone. You'll see that parsing the startDate (and endDate) would result in different times depending on your timezone.

So the combination of a timestamp and a timezone give us a clear, unambiguous point in time for the most robust code. If we don't set a timezone when parsing the start and end date, the code could give a different result depending on the machine it is running on.

The best approach is to specify what timezone the startDate and endDate are in, e.g. are they in IST, or in UTC?

This way you can be sure your dates will parse consistently.

I would also suggest creating a function, say, parseDate that accepts a datestring, a format, and a timezone. This is makes all assumptions clear to anyone who reads the code.

There is no issue with InitialDate or updateDate, since they are specified as UTC times (the Z timezone specifier), so they are both clear and unambiguous.

const dates = { 
    startDate: "2019-02-18",
    endDate: "2020-02-16"
}

const startDateNoTimezoneSpecified = moment(dates.startDate);
console.log("StartDate (No Timezone Specified):", startDateNoTimezoneSpecified.toISOString());

function parseDate(dateString, format, timezone) {
    return moment.tz(dateString, format, timezone)
}

// Parse start date, assuming it is in IST (I'm assuimg IST refers to India Standard Time , if it's Israel Standard Time replace with Asia/Jerusalem!
console.log("Parse date result (IST):", parseDate(dates.startDate, "YYYY-MM-DD","Asia/Kolkata").toISOString());
console.log("Parse date result (UTC):", parseDate(dates.startDate, "YYYY-MM-DD","UTC").toISOString());


// You can also use moment.utc instead of moment.tz(date, "UTC").. it's simpler!
const startDateUTC = moment.utc(dates.startDate);
console.log("StartDate (UTC (moment.utc)):", startDateUTC.toISOString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data-1970-2030.js"></script>
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • instead of adding time zones to start and end dates I have removed time element using moment.format and then comparing them. Not at all considering time elements in any of the dates. Will that work with my above code? – user1660325 Dec 13 '19 at 14:57
  • Using these, new Date(moment(startDate).format('YYYY-MM-DD')) for startdate, new Date(moment(endDate).format('YYYY-MM-DD')) for endate and then doing the above mentioned comparision – user1660325 Dec 13 '19 at 15:01
  • I dont need ant time element in the above dates, I only need to format them to dates and compare – user1660325 Dec 13 '19 at 15:02
  • with the above new Date() comparison, below comparision is working fine,if (actualInitDatE >= actualStartDateW && actualInitDatE <= actualEndDateW) { console.log('Compared and True'); } – user1660325 Dec 13 '19 at 15:03
  • is new Date() ok? or for new Date() also do we need to do any other convertions? BTW i am not using moment.utc and only moment.format. is this is fine or utc is required for java script date objects? – user1660325 Dec 13 '19 at 15:04
  • Removing the time element from startDate and endDate won't get rid of the timezone problem. Adding, say 5 hours will change the dates, since a date like "2019-02-18" is implicitly "2019-02-18 00:00". new Date() will be fine if you're doing all your calculations in the same time zone, e..g local time. Like comparing 12:30 to 15:30 is fine as long as both times are in the same timezone! – Terry Lennox Dec 13 '19 at 15:38
  • The core thing to remember is that when we parse a string, we must implicitly _or_ explicitly set a timezone. A time string is highly ambiguous without a timezone! – Terry Lennox Dec 13 '19 at 15:39
0

You seem to be over complicating things.

Your conversion of UTC timestamps to local dates is OK, but the format doesn't make sense. MM-DD-YYYY is pretty useless for anything, I'd suggest using ISO 8601 YYYY-MM-DD.

Date-only timestamps should be treated as local, so no conversion is necessary for the second two dates. Using ISO 8601 format, the strings can be compared directly:

let initialDate = '2019-02-19T12:03:22.129Z';
let updateDate = '2019-02-28T05:26:57.115Z';

// Get local date in required format
let actualInitDatE = moment(initialDate || updateDate).format('YYYY-MM-DD');

// Use these as they are
let startDate = '2019-02-18';
let endDate = '2020-02-16';

if (actualInitDatE >= startDate &&
    actualInitDatE <= endDate) {
  console.log('Compared and True');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

You can also keep the values as moment objects after setting them to the start of the day and use various moment methods for comparison, but I think the string version is pretty simple so why make it harder than it has to be?

Whether "this code works across timeZones" is unknown as you haven't explained what you are actually trying to achieve.

RobG
  • 142,382
  • 31
  • 172
  • 209