0

Here is cutoffDate is passed as an argument to this method.
Sample value for cutoffDate = "2020-04-19 23:59:59"

If cutoffDate is past, as per the current time in Denver, return true
If cutoffDate is future, as per the current time in Denver, return false

let cutoffDate = "2020-04-19 23:59:59";

const currentDatetime = new Date(
  new Date().toLocaleString("en-US", {
    timeZone: "America/Denver",
  })
);

const cutoffDateTime = new Date(cutoffDate);

console.log(currentDatetime + '\n' + cutoffDateTime);

console.log(currentDatetime < cutoffDateTime);

This method returns incorrect result, in some cases. This method is working correctly as expected in some cases and not working as expected in some cases. Observation: As per logs, it tends to fail in IOS (iPhone). (in some cases)

As per my understanding, above code should function correctly always. But, I am unable to determine why it is failing in some cases.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask): _"**Describe the problem.** "It doesn't work" isn't descriptive enough to help people understand your problem. Instead, tell other readers what the expected behavior should be. Tell other readers what the exact wording of the error message is, and which line of code is producing it. Use a brief but descriptive summary of your problem as the title of your question."_ -> Add a [mcve] that reproduces the problem. – Andreas Jan 09 '23 at 12:58
  • The string is parsed as local to the host settings, then stringified to America/Denver in a format that is not required (and in many cases unlikely) to be correctly parsed back to a Date and you wonder why it goes wrong sometimes? – RobG Jan 09 '23 at 15:22
  • Hi @RobG, thank you for your response. So, Are we initialising currentDatetime field in an in-correct way? Also, I corrected the code a little bit. Request you to check once, and suggest any changes.. – PAIDIPELLY HEMANTH RAO Jan 09 '23 at 16:57
  • There is nothing in the OP that relates to react.js, it's plain JS. The format of "2020-04-19 23:59:59" is not supported by ECMA-262 so parsing is implementation dependent. It may be treated as an invalid date. Where parsed correctly it will be treated as local, so will represent a different instant in time for each host with a different offset for that date and time and hence represent a different date and time in America/Denver. The return value from *toLocaleString* is not required to be parsable by the built–in parser either, so that result is implementation dependent too. – RobG Jan 09 '23 at 22:55

1 Answers1

0

What you're trying to do seems valid, however the way you're doing it is prone to failure.

"2020-04-19 23:59:59" is not a format supported by ECMA-262 so parsing is implementation dependent. Apple devices until very recently treated it as an invalid date, so this method will fail for any device running an earlier OS.

A better way is to manually parse the string to remove issues associated with the built–in parser. Similarly for the return value from toLocaleString.

The following manually parses the timestamp, then uses Intl.DateTimeFormat with formatToParts to get the date and time values for any IANA representative location. It uses Date.UTC to generate time values to compare and avoid local DST issues.

Note that if the input timestamp represents a date and time that doesn't exist in the location (i.e. it's in the period when clocks are advanced going into DST) or exists twice (i.e. it's in the period when clocks are wound back going out of DST) then results may or may not be "correct". However, this is an issue for any system comparing such dates and times.

// Return true if current time is before timestamp at loc
function nowIsBeforeDateAtLoc(ts, loc = 'UTC') {

  // Get time value for timestamp parsed as UTC
  let [Y,M,D,H,m,s] = ts.split(/\D/);
  let tsTV = Date.UTC(Y,M-1,D,H,m,s);
  
  // Get current date and time values for loc
  let {year, month, day, hour, minute, second} = new Intl.DateTimeFormat('en', {
    year:'numeric',
    month:'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
    second: 'numeric',
    hour12: false,
    timeZone: loc
  }).formatToParts(new Date()).reduce((acc, part) => {
    acc[part.type] = part.value;
    return acc;
  }, Object.create(null));
  
  // Get UTC time value for loc
  let locTV = Date.UTC(year, month-1, day, hour, minute, second);
  // Debug
  // Parsed timestamp
  console.log('Cutoff: ' + new Date(tsTV).toISOString().slice(0,-1));
  // Current date and time at loc
  console.log('Now ' + loc + ' : ' + new Date(locTV).toISOString().slice(0,-1));
  
  return locTV < tsTV;
}


// Example
let cutoffTime = "2020-04-19 23:59:59";

//
console.log('Now is before cutoff at loc? '  + nowIsBeforeDateAtLoc(cutoffTime, 'America/Denver'));

You could also use a library to parse the timestamp for a particular location then compare it to "now", which might be simpler. See this answer to How to initialize a JavaScript Date to a particular time zone.

RobG
  • 142,382
  • 31
  • 172
  • 209