tc39/ecma402

Is there a polyfill for the "extend-timezonename" proposal?

Closed this issue · 6 comments

getify commented

As I asked here, I'm looking to confirm if there was ever a polyfill (official or unofficial) for the proposal of extending the timezone names (e.g., longOffset, etc)?

Or did it advance all the way through to Stage 4 without any polyfill? As a side question: how did TC39 gather feedback on how it works (the accuracy and usefulness of the values it returns) without such a polyfill?

getify commented

I (unfortunately) need to support a server with Node 16, which has v8 version 9.4 -- and this feature didn't land in v8 until 9.5, and Node didn't backport it.

Specifically, I need to be able to calculate the timezone offset (aka longOffset) of any specified timezone -- something I would imagine is rather common. For example, for "America/Chicago" timezone (currently in DST), it's "-05:00".


For posterity sake, I'm currently using the below workaround, but I was really hoping maybe there was some more well-thought-out/tested polyfill for this:

// adapted from: https://www.npmjs.com/package/get-timezone-offset
function computeTZOffset(timezoneLabel) {
	try {
		let offset = (new Date()).toLocaleString("en-US",{
			timeZone: timezoneLabel,
			timeZoneName: "longOffset",
		})
		.match(/GMT(.*)$/)[1];
		if (/^[\-\+]\d{2}:\d{2}$/.test(offset)) {
			return offset;
		}
	}
	catch (err) {}

	var formatOptions = {
		timeZone: "UTC",
		hourCycle: "h23",
		year: "numeric",
		month: "numeric",
		day: "numeric",
		hour: "numeric",
		minute: "numeric",
	};

	var utcFormat = new Intl.DateTimeFormat("en-US",formatOptions);
	var tzFormat = new Intl.DateTimeFormat("en-US",{ ...formatOptions, timeZone: timezoneLabel, });
	var now = new Date();
	return formatHourMin(diffMinutes(
		parseDate(utcFormat.format(now)),
		parseDate(tzFormat.format(now))
	));


	// *****************************

	function parseDate(dateStr) {
		return Object.fromEntries(
			Object.entries(
				((
					dateStr.replace(/[\u200E\u200F]/g,"")
					.match(/^\d+.(?<day>\d+).\d+,?\s+(?<hour>\d+).(?<min>\d+)/)
				) || { groups: {}, })
				.groups
			)
			.map(([name,val]) => [ name, Number(val), ])
		);
	}

	function diffMinutes(d1,d2) {
		var day = d1.day - d2.day;
		var hour = d1.hour - d2.hour;
		var min = d1.min - d2.min;
		if (day > 15 ) day = -1;
		if (day < -15 ) day = 1;
		return 60 * (24 * day + hour) + min;
	}

	function formatHourMin(minutes) {
		var hour = Math.floor(minutes / 60);
		minutes -= (hour * 60);
		return `${minutes > 0 ? "+" : "-"}${String(hour).padStart(2,"0")}:${String(minutes).padStart(2,"0")}`;
	}
}
ljharb commented

A polyfill isn’t ever required for advancement, it’s just a good way to get earlier feedback.

getify commented

I didn't claim it was "required" (merely customary and common as far as I was aware).

My question remains: in the absence of a polyfill how does early usability feedback happen before multiple shipped implementations?

ljharb commented

Without a polyfill, user feedback indeed can’t happen until there’s a shipped implementation.

Polyfills are quite common for 262, but there doesn’t yet seem to be much activity around complete 402 polyfill implementations.

getify commented

ok

@getify you're right in that we really need to start showing polyfills some more love on the 402 side of things. That said, the need for access to locale data means that these polyfills can be quite data-heavy, especially unless unified. Therefore, we tend to focus on format.js as a way of delivering polyfills. It seems from this page that the extent-timezonename proposal might not have been polyfilled there. Perhaps we can start that conversation?