3

Im trying to get the first day of first week by given day

Correct results :

2017 = 2 Jan (Monday)

2016 = 4 Jan (Monday)

2015 = 1 Jan (Thursday)

2014 = 1 Jan (Wednesday)

2013 = 1 Jan (Tuesday)

I can get the first day of the year by :

moment().year(year).startOf('year') // All result is 1. jan XXXX

Then I tried : (correct)

moment().day(1).year(2017).week(1) // 2 Jan (Monday) (correct)

But when changed to 2016 : (wrong)

moment().day(1).year(2016).week(1) // 10 Jan (Sunday) (wrong)

Any know how to get correct results ? (Im open for pure JS date() also)

PS: Week number is based in Norway

Playground : https://jsfiddle.net/6sar7eb4/

l2aelba
  • 21,591
  • 22
  • 102
  • 138
  • does this need to be achieved purely in moment. wouldnt be too hard to do this with a loop – Tik Jun 30 '17 at 12:58

3 Answers3

6

There is no need to use loop, you can simply test if the week number is not 1 using week() that gives localized output

The output of moment#week will depend on the locale for that moment.

You have to set the locale to moment using locale() method to get start of week locale aware. If you have to show result in english you can change locale locally.

Here a working sample:

function getFirstDayOfFirstWeekByYear( year ) {
  // Create moment object for the first day of the given year
  let func = moment({year:year})
  // Check if 1st of January is in the first week of the year
  if( func.week() !== 1 ){
    // If not, add a week to the first day of the current week
    func.startOf('week').add(1, 'week');
  }
  // Return result using english locale
  return func.locale('en').format('D. MMMM YYYY (dddd)')
}

// Set Norwegian Bokmål locale globally
moment.locale('nb');

// Tester
[2017, 2016, 2015, 2014, 2013].forEach(function ( year ) {
  let s = '<li>' + getFirstDayOfFirstWeekByYear( year ) + '</li>'
  document.getElementsByTagName('BODY')[0].innerHTML += s
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.min.js"></script>
VincenzoC
  • 30,117
  • 12
  • 90
  • 112
  • I really wish IT people would learn that a *language code* does not define a *locale*, it is a complete misnomer. Also, if changing the language changes the first week of the year, then you need to be aware that two users sitting next to each other may see a different first week just because they have chosen to use a different language. The first week of the year is determined differently by different administrations and cultures, you can't assume it based on the language used. – RobG Jun 30 '17 at 22:29
  • @RobG I agree with you, _language code_ != _locale_. In my answer I used `locale(code)` in order to take advantage of [moment localized](http://momentjs.com/docs/#/i18n/locale-data/) `firstDayOfWeek` and `firstDayOfYear` since OP stated _Week number is based in Norway_. Reading your detailed (+1) answer I understand that _based in Norway_ is a _vague_ way to choose week number scheme. Am I missing something in your comment? Do you see issues in my answer? Anyway thank you for sharing knowledge about schemes for first day of the week and first day of the year. – VincenzoC Jul 03 '17 at 22:35
  • @VincenzoC—sorry, the "locale" comment wasn't directed at you but at the standards writers who think personal preferences can be determined by language. I think you've got it, either stick to a standard scheme and tell the user what it is, or let the user nominate the scheme they wish to use. The first is a lot simpler. ;-) – RobG Jul 04 '17 at 01:15
2

Anyway if your happy to do it within a loop this works

function getFirstDayOfFirstWeekByYear( year ){
  let D = 1;
  x = 0;
  while(x !== 1){
   x = moment(`${year}-01-${D}`).isoWeek();
   if(x === 1 ){
    return moment(`${year}-01-${D}`).format('D. MMMM YYYY (dddd)')
   }
   D++;
  };
}

results

2. January 2017 (Monday)
4. January 2016 (Monday)
1. January 2015 (Thursday)
1. January 2014 (Wednesday)
1. January 2013 (Tuesday)
Tik
  • 822
  • 6
  • 14
2

Im trying to get the first day of first week by given day

Using moment.js to get the first day of the first week of the year based on the ISO 8601 scheme, you can just use the first day of the first week of the year since the ISO week starts on Monday:

// Return a moment.js object for the first weekday of the first week
// of the year using ISO 8601 scheme
function firstDay(year) {
  return moment(year + '011', 'GGGGWWE');
}

// Examples
['2015', '2016', '2017', '2018', '2019', '2020']
.forEach(function(year) {
  console.log('ISO First day of ' + year + ': ' +
               firstDay(year).format('dddd D MMMM, YYYY'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

However you seem to not want to use the ISO scheme, so if you just want to get the first day of the year that isn't a Saturday or Sunday (i.e. ignore the ISO 8601 scheme), you can do (without moment.js):

// Return Date for first day of year that is one of
// Monday to Friday
function firstDay(year) {
  var d = new Date(year, 0, 1);
  var day = d.getDay();
  d.setDate(d.getDate() + (day%6? 0 :  (++day%4)));
  return d;
}

// Examples
['2015', '2016', '2017', '2018', '2019', '2020']
.forEach(function(year) {
  console.log('First weekday of ' + year + ': ' + firstDay(year).toString());
});

Discussion

There are many different schemes for first day of the week and first day of the year. A commonly used scheme is ISO 8601, where the first day of the week is Monday and the first week of the year is the one in which the first Thursday appears (or the first that contains at least 4 days of the week, it's the same result).

According to ISO 8601 rules, the first day of the first week of 2019 is Monday 31 December, 2018.

If you decide to support different schemes (e.g. in Saudi Arabia the week starts on Saturday and ends on Friday, with work days Saturday to Wednesday and in the US a week is typically Sunday to Saturday with work days Monday to Friday), then you should clearly state which scheme you support and not simply assume a scheme based on the language the user has chosen. Schemes may also be based on other cultural factors such as religion, so are not necessarily region or language-based.

Which scheme should be used for an English person in Saudi Arabia? An Islamic person in Bhutan? In Saudi the official language for commerce is French, but most international discussion is in English, while the national language is Arabic. But they use the Hijri calendar, which does not align with the Georgian calendar commonly used elsewhere and is not defined by language but by religion.

There may also be differences even in the same place, with departments of the same government choosing different schemes so even locale (in the correct meaning of the term) is not a definitive indicator of which scheme to use.

If you decide to support different schemes, far better to adopt a standard scheme (like ISO 8601) and let the user change it to the one they prefer if they wish (and which the preferences in my computer and calendar application allow me to do).

RobG
  • 142,382
  • 31
  • 172
  • 209
  • `moment('2017-01-02').isoWeek()` this return `1` and its correct, But this is correct way to return right week number as my question ? – l2aelba Jul 04 '17 at 13:36
  • Opps your code is something wrong. In 2016 should return `4 Jan (Monday)` – l2aelba Jul 04 '17 at 13:52
  • 1
    @l2aelba—yes, sorry, I was using the "locale aware" tokens (ggggwwe) not ISO tokens (GGGGWWE). Hoist by my own petard, but highlights the issue with adopting a random "locale" scheme (even though I didn't mean to!). :-( – RobG Jul 05 '17 at 00:01