luxon: startOf('week') is not respecting locale setting

While most countries in the world assume the week starts on Monday, US, Canada, and Australia consider Sunday as the first day of the week. It seems that luxon hard-coded the start of week as Monday.

// prints "2018-11-19T00:00:00.000-08:00"
console.log(DateTime.fromISO('2018-11-22T10:00', {zone: 'America/Los_Angeles'}.startOf('week').toISO());

Note that moment does actually respect the locale setting

// prints "2018-11-18T08:00:00.000Z"
console.log(moment.tz('2018-11-22T10:00', "America/Los_Angeles").startOf('week').toISOString());

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 13
  • Comments: 28 (5 by maintainers)

Commits related to this issue

Most upvoted comments

While this is a quite old issue, I still wanted to share my quick work around:

const date = DateTime.fromISO('2021-09-16').startOf('week')
const sunday = date.minus({day: 1})

By simply subtracting a day, you get a sunday which you can use as a start point for further actions.

edit: However, once possible, this should be part of the API.

As far as I know, there’s no Intl API I can use to get the local first day of the week.

It’s coming soon: https://chromestatus.com/feature/5566859262820352

While this is a quite old issue, I still wanted to share my quick work around:

const date = DateTime.fromISO('2021-09-16').startOf('week')
const sunday = date.minus({day: 1})

By simply subtracting a day, you get a sunday which you can use as a start point for further actions.

edit: However, once possible, this should be part of the API.


Don’t run that code on Sundays

Can we put this information in the documentation? I scoured it looking for a setting to set what day of the week is considered the start or how luxon decides what the start of the week is and hence what the basis would be for any offset I’d need to control it.

In case anyone else is experimenting with this, this is what I am using:

function getWeekStart(date) {
  const offset = Duration.fromObject({ days: 1 })
  return date
    .plus(offset)
    .startOf('week')
    .minus(offset)
}

To account for cases where the reference date is Sunday, the reference date is increased by one, the start is calculated, then that date is decreased. I haven’t encountered any issues with the approach so far.

Not quite sure what you mean @bvandercar-vt - your solution acts just the same. The solution proposed will always get the previous sunday which just works as I proposed.

Bildschirmfoto 2021-12-07 um 09 52 06


If someone needs the current weeks sunday, they should use the solution below.

import { DateTime } from 'luxon'

// using the 5th of december which is a sunday
const date = DateTime.fromISO('2021-12-05').setLocale('en-US')

const getSunday = 
  date.weekdayShort === 'Sun' 
    ? date.toISODate()
    : date.startOf('week').minus({day: 1}).toISODate()

// will return the 5th of december
getSunday

Bildschirmfoto 2021-12-07 um 09 56 55

This again is a work around, as you get the current sunday and can build your own week from that date on to create your sunday-as-first day week, iterating over the date and pushing the following 6 days into an array. I once wrote a method to get the current week dates based of a date that is passed.

https://github.com/lostdesign/linked/blob/58c8796d2059e26572366b846dd26212b789ea97/src/store/modules/calendar/helper.js#L38-L56

I’d just like to chime in here, and say that in the original post, @mars-lan has stated that Sunday is the start of week for Australia. This is incorrect.

Australia adheres to ISO 8601-2007 (and in turn, ISO 8601) - which clearly states Monday is the first day of the week.

This can be verified in many places, but here is the wikipedia for easy reading: https://en.wikipedia.org/wiki/ISO_8601 Note the inclusion of Australia under the “Adoption as national standards” section.

And the definition “[D] is the weekday number, from 1 through 7, beginning with Monday and ending with Sunday.”

For a brief period, in the official Unicode Common Locale Data Repository (CLDR), Australia’s start day was incorrectly changed to Sunday due to a misunderstanding. But after the following case, it was changed back to Monday, which is correct.

https://unicode-org.atlassian.net/browse/CLDR-14795

So hopefully Luxon does correctly use Monday as the start of the week for Australia.

In my case, I need to get the start of the week given any day of the week…

const getStartOfWeek(dateTime: DateTimeType) = {
    return dateTime.minus({ days: dateTime.weekday }).startOf('day');
}

Cheers…

@lostdesign this is a misleading solution as it would not work when the day is Sunday. If the current day is Sunday, you would want the start of the week day to be today, but startOf('week') would give you last Monday so your resulting Sunday would be last Sunday, not the current day (Sunday)

The start day of the week in Arab countries is Saturday, so that I came with the following workaround:

  1. Extend the DateTime type to add more utilities [index.d.ts]:

     import { DateTime } from 'luxon';
    
     declare module 'luxon/src/datetime' {
       export interface DateTime {
         /**
          * Returns new `DateTime` instance with the time sets to the first day in the current week.
          */
          startOfWeek(): DateTime;
    
         /**
          * Returns new `DateTime` instance with the time sets to the last day in the current week.
          */
          endOfWeek(): DateTime;
    
         /**
          * Returns new `DateTime` instance with the time sets to the first day in the current Arabic week.
          */
          startOfArabicWeek(): DateTime;
    
         /**
          * Returns new `DateTime` instance with the time sets to the last day in the current Arabic week.
          */
          endOfArabicWeek(): DateTime;
       }
     }
    
  2. Add the implementation of the new methods [app.ts]:

     DateTime.prototype.startOfWeek = function (): DateTime {
       return this.startOf('week');
     };
    
     DateTime.prototype.endOfWeek = function (): DateTime {
       return this.endOf('week');
     };
    
     DateTime.prototype.startOfArabicWeek = function (): DateTime {
       /**
        * Because the start of week in the luxon package is always Monday.
        * We are going back two days to reach Saturday.
        */
       return this.startOf('week').minus({ days: 2 });
     };
    
     DateTime.prototype.endOfArabicWeek = function (): DateTime {
       /**
        * Because the end of week in the luxon package is always Sunday.
        * We are going back two days to reach Friday.
        */
       return this.endOf('week').minus({ days: 2 });
     };
    

I just ran across this limitation too. I implemented my own function to do it in https://gist.github.com/wkeese/20514beb68bc1bac807ec07cda4175db.

Note that dojo’s data came from the CLDR but we just inlined it into the function.

Also, here’s the test case I used:

$ npm install full-icu
$ node --icu-data-dir=./node_modules/full-icu
> const { DateTime } = require("luxon");
undefined
> DateTime.fromObject({year: 2020, month: 4, day: 12, locale: "en-us"}).startOf("week").day
6
> DateTime.fromObject({year: 2020, month: 4, day: 12, locale: "bn-BD"}).startOf("week").day
6

Before reading this ticket, I expected the en-us call to return Sunday, April 5, 2020 and the bn-BD one to return Friday, April 10, 2020.

Hi would it make sense to have a setter for this? We are running into this issue now where we are grouping data by weeks and we are finding the result is incorrect as our front end respects locale, and our backend is using Luxon and does not.

Thanks.