2
\$\begingroup\$

On StackOverflow I got a great answer to a question I had about creating a Date object from an ISO 8601 string with the ability to reposition into local time.

From there I wanted to see if I could make it any faster. We process a ton of dates in batches of 10,000 or more sometimes on slow phones.

This is the best I could do.

const isoToDate = (iso8601, ignoreTimezone = false) => {
  // Differences from default `new Date()` are...
  // - Returns a local datetime for all without-timezone inputs, including date-only strings.
  // - ignoreTimezone processes datetimes-with-timezones as if they are without-timezones.
  // - Accurate across all mobile browsers.  https://stackoverflow.com/a/61242262/25197

  const dateTimeParts = iso8601.match(
    /(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:([+-])(\d{2}):(\d{2}))?)?/,
  );

  // Create a "localized" Date.
  // If you create a date (without specifying time), you get a date set in UTC Zulu at midnight.
  // https://www.diigo.com/0hc3eb
  const date = new Date(
    dateTimeParts[1], // year
    dateTimeParts[2] - 1, // month (0-indexed)
    dateTimeParts[3] || 1, // day
    dateTimeParts[4] || 0, // hours
    dateTimeParts[5] || 0, // minutes
    dateTimeParts[6] || 0, // seconds
    dateTimeParts[7] || 0, // milliseconds
  );

  const sign = dateTimeParts[8];
  if (sign && !ignoreTimezone) {
    const direction = sign === '+' ? 1 : -1;
    const hoursOffset = dateTimeParts[9] || 0;
    const minutesOffset = dateTimeParts[10] || 0;
    const offset = direction * (hoursOffset * 60 + minutesOffset * 1);
    date.setMinutes(date.getMinutes() - offset - date.getTimezoneOffset());
  }

  return date;
};

It's about double the speed of the SO answer and 4-6x faster than moment.js and date-fns packages.

The key difference is a single regex that returns all the matching groups at once.

Regular expression visualization

Here's a regex101 with some examples of it matching/grouping.


Is there anything obvious that can be improved upon here? Thanks! 👍

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.