Skip to content

Instantly share code, notes, and snippets.

@bathos
Last active December 7, 2019 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bathos/84286d0d6052d10dd98a444d41e9db43 to your computer and use it in GitHub Desktop.
Save bathos/84286d0d6052d10dd98a444d41e9db43 to your computer and use it in GitHub Desktop.
/util/date/weekdata.mjs
import range from '/util/iterator/range.mjs';
// Week start data pulled from similarly golfed answer on SO:
// https://stackoverflow.com/a/57102881/1631952
//
// I’m not thrilled with this; we probably ought to be generating it since the
// data is pretty obscure. OTOH I’d be far less thrilled with loading hefty
// chunks of ICU data and this is pretty solid and compact!
//
// Note that the RegExp given for lang tags in that answer is a bit off. The one
// below is more accurate but deliberately doesn’t bother matching any segments
// after region and doesn’t include grandfathered tags etc, since browsers
// should not be returning those values. It also does not bother matching region
// tag segments which use the three-digit format since we don’t have data for
// those below (and again I doubt browsers ever surface language tags that way).
//
// The exports here are live. Queue a render on languagechange in elements that
// consume this data if you want it to respond to system language changes. In
// practice, such events are very rare and on Windows they don’t reliably
// occur, so it’s your call whether it’s worthwhile in a given case.
const LANG_TAG_REGION =
/^(?:[a-z]{2,3}(?:-[a-z]{3}){0,3}|[a-z]{4,8})(?:-[a-z]{4})?-([a-z]{2})/i;
// ^ lang (1) ^ extlangs ^ lang (2) ^ script ^ region
const [ SATURDAYS, SUNDAYS ] = [
'AEAFBHDJDZEGIQIRJOKWLYOMQASDSY',
'AGARASAUBDBRBSBTBWBZCACNCODMDOETGTGUHKHNIDILINJMJPKEKHKRLAMHMMMOMTMXMZNINP' +
'PAPEPHPKPRPTPYSASGSVTHTTTWUMUSVEVIWSYEZAZW'
].map(src => new Set(src.split(/(?=(..)+$)/)));
////////////////////////////////////////////////////////////////////////////////
export let indices, longNames, shortNames, start;
update();
addEventListener('languagechange', update);
////////////////////////////////////////////////////////////////////////////////
function getRegion() {
for (const tag of navigator.languages) {
const match = LANG_TAG_REGION.exec(tag);
if (match) {
return match[1].toUpperCase();
}
}
}
function getWeekNames(format) {
return indices.map(i => {
const date = new Date(0, 0, i);
return date.toLocaleDateString(navigator.languages, {
calendar: 'gregory',
weekday: format
});
});
}
function update() {
const region = getRegion();
start = SATURDAYS.has(region) ? 6 : SUNDAYS.has(region) ? 0 : 1;
indices = Array.from(range(0, 7), i => (start + i) % 7);
shortNames = getWeekNames('short');
longNames = getWeekNames('long');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment