Parse datetime string as TZ/local

by PhilQ

JavaScript 1.7

function datePartsToYMDHIS(parts) {
  parts = parts
    .filter(p => p.type!=='literal')
    .reduce((o, v) => { o[v.type] = v.value; return o; }, {});
  return `${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}:${parts.second}`;
}

function datePartsToISO(parts) {
  parts = parts
    .filter(p => p.type!=='literal')
    .reduce((o, v) => { o[v.type] = v.value; return o; }, {});
  return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}.000000Z`;
}

// In: datetime ISO string (in true UTC)
// Out: datetime representation (where UTC is local/tz time)
function dateToTimezone(isoString, timeZone) {
  const date = new Date(Date.parse(isoString));
  // const date = new Date(isoString);
  const dateTimeFormat = new Intl.DateTimeFormat('en-US', {
    timeZone: timeZone ?? undefined,
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
    hourCycle: "h23",
  });
  
  return new Date( Date.parse(
    datePartsToISO( dateTimeFormat.formatToParts( date ) )
  ) );
}

// In: datetime ISO string (where UTC is local/tz time)
// Out: datetime representation (in true UTC)
function dateFromTimezone(isoString, timeZone) {
  const dateUTC = dateToTimezone(isoString, 'UTC');
  const dateTZ = dateToTimezone(isoString, timeZone);
	const offsetTZ = dateTZ.getTime() - dateUTC.getTime();
	
  const dateCalculated = new Date( dateUTC.getTime() - offsetTZ );
	
	// Note: We need to check (and correct) for DST switching,
	//       to make sure the calculated date is the correct UTC date
	//       corresponding to the ISO string local timestamp.
	
	// Check if the calculated date (UTC) gives the correct ISO string in TZ.
	const dateTZasUTC = dateToTimezone(dateCalculated.toISOString(), timeZone);
	
	// And correct if necessary (when: isoString !== dateTZasUTC.toISOString()).
	return new Date( dateCalculated.getTime() + dateUTC.getTime() -...