Moment.tz("Europe/Berlin").startOf("week") returning Sunday instead of Monday

68 views Asked by At

Certain timezones start the week on a Monday rather than Sunday, f.e. Germany. I expected Moment.tz("Europe/Berlin").startOf("week") to return Monday but instead it returns Sunday. Any way to workaround this?

3

There are 3 answers

2
Ian Price On

Start of week is dependent on locale (see link below to docs and an example).

See here and here

4
codeandcloud On

Updated Answer:

You can use Intl.Locale.prototype.getWeekInfo(), but Firefox doesn't support it at all.

const fallBackStartOfWeek = {
  'de-DE': 1,
  'en-US': 7
};

const getFallbackStartOfWeek = (tz) => 
    Object.keys(fallBackStartOfWeek).includes(tz) 
        ? fallBackStartOfWeek[tz] : 7; // fallback to sunday;
        
const getStartOfTheWeek = (date, tz) => {
  const locale = new Intl.Locale(tz);
  let firstDay = -1;
  if (locale.getWeekInfo) { // safari
    firstDay = locale.getWeekInfo().firstDay;
  } else if (locale.weekInfo) { // chrome, edge, opera
    firstDay = locale.weekInfo.firstDay;
  } else { // firefox. not implemented yet
    firstDay = getFallbackStartOfWeek(tz);
  }
  return moment(date).day(firstDay).toString();
}

const germanStartOfWeek = getStartOfTheWeek('2023-11-07', 'de-DE');
const usStartOfWeek = getStartOfTheWeek('2023-11-07', 'en-US');

console.log({
  german: germanStartOfWeek,
  us: usStartOfWeek
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.43/moment-timezone-with-data.min.js"></script>

Browser Compatibility: Intl: Locale: getWeekInfo


Old Answer:

You can use getDay('Monday') or getDay(0) to get Monday on all the timezone locale.

const mondayBerlin = moment('2023-11-07').tz('Europe/Berlin').day('Monday');
console.log({
  date: moment(mondayBerlin).format('yyyy-MM-DD'),
  day: moment(mondayBerlin).format('dddd')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.43/moment-timezone-with-data.min.js"></script>

0
Matt Johnson-Pint On

The starting day of the week is an aspect of locale, not time zone. They are independent concepts. You can use one or the other, or both.

// start of the week in your local time zone and the default locale
const m1 = moment().startOf('week');

// start of the week in your local time zone, using a German locale
const m2 = moment().locale('de').startOf('week');

// start of the week in Germany's time zone, using the default locale
const m3 = moment.tz('Europe/Berlin').startOf('week');

// start of the week in Germany's time zone, using a German locale
const m4 = moment.tz('Europe/Berlin').locale('de').startOf('week');

console.log('m1:', m1.toString());
console.log('m2:', m2.toString());
console.log('m3:', m3.toString());
console.log('m4:', m4.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment-with-locales.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.43/moment-timezone-with-data-10-year-range.min.js"></script>

I think you are expecting the behavior of the fourth example above, though you are using the third.

Also keep in mind that Moment.js is generally considered obsolete, and should only be used on legacy projects.