196

How do I get the current weeknumber of the year, like PHP's date('W')?

It should be the ISO-8601 week number of year, weeks starting on Monday.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
  • 2
    Look here, which was the first link given when I googled 'javascript week of year'. – Pete Wilson May 24 '11 at 23:07
  • @Pete: That code gets 22 as the current week. While it should be 21 – PeeHaa May 24 '11 at 23:20
  • @Pete: :D Nopez a simple -1 won't do the trick :P That wouldn't get the ISO-8601 weeknumber. A week in ISO-8601 starts on monday. The first week is the week with the year's first Thursday in it. http://en.wikipedia.org/wiki/ISO-8601 . PS wasn't me who downvoted you. – PeeHaa May 25 '11 at 20:50

24 Answers24

369

You should be able to get what you want here: http://www.merlyn.demon.co.uk/js-date6.htm#YWD.

A better link on the same site is: Working with weeks.

Edit

Here is some code based on the links provided and that posted eariler by Dommer. It has been lightly tested against results at http://www.merlyn.demon.co.uk/js-date6.htm#YWD. Please test thoroughly, no guarantee provided.

Edit 2017

There was an issue with dates during the period that daylight saving was observed and years where 1 Jan was Friday. Fixed by using all UTC methods. The following returns identical results to Moment.js.

/* For a given date, get the ISO week number
 *
 * Based on information at:
 *
 *    THIS PAGE (DOMAIN EVEN) DOESN'T EXIST ANYMORE UNFORTUNATELY
 *    http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
 *
 * Algorithm is to find nearest thursday, it's year
 * is the year of the week number. Then get weeks
 * between that date and the first day of that year.
 *
 * Note that dates in one year can be weeks of previous
 * or next year, overlap is up to 3 days.
 *
 * e.g. 2014/12/29 is Monday in week  1 of 2015
 *      2012/1/1   is Sunday in week 52 of 2011
 */
function getWeekNumber(d) {
    // Copy date so don't modify original
    d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
    // Set to nearest Thursday: current date + 4 - current day number
    // Make Sunday's day number 7
    d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
    // Get first day of year
    var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
    // Calculate full weeks to nearest Thursday
    var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
    // Return array of year and week number
    return [d.getUTCFullYear(), weekNo];
}

var result = getWeekNumber(new Date());
document.write('It\'s currently week ' + result[1] + ' of ' + result[0]);

Hours are zeroed when creating the "UTC" date.

Minimized, prototype version (returns only week-number):

Date.prototype.getWeekNumber = function(){
  var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
  var dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
  return Math.ceil((((d - yearStart) / 86400000) + 1)/7)
};

document.write('The current ISO week number is ' + new Date().getWeekNumber());

Test section

In this section, you can enter any date in YYYY-MM-DD format and check that this code gives the same week number as Moment.js ISO week number (tested over 50 years from 2000 to 2050).

Date.prototype.getWeekNumber = function(){
  var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
  var dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
  return Math.ceil((((d - yearStart) / 86400000) + 1)/7)
};

function checkWeek() {
  var s = document.getElementById('dString').value;
  var m = moment(s, 'YYYY-MM-DD');
  document.getElementById('momentWeek').value = m.format('W');
  document.getElementById('answerWeek').value = m.toDate().getWeekNumber();      
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

Enter date  YYYY-MM-DD: <input id="dString" value="2021-02-22">
<button onclick="checkWeek(this)">Check week number</button><br>
Moment: <input id="momentWeek" readonly><br>
Answer: <input id="answerWeek" readonly>
Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
RobG
  • 142,382
  • 31
  • 172
  • 209
  • 4
    You saved my ass. Thanks. If you want to contribute to Open Source, I suggest you create a patch for the jQuery UI method: $.datepicker.iso8601Week(date) as it does only return weekNo, but no year. – Christian Oct 31 '12 at 22:08
  • Use the first day of the year as the start of the year is not correct. The first day of year should be the first day(Sunday or Monday) of the year's first week. – joker May 18 '15 at 10:21
  • @joker—you have to start with 1 Jan, whatever day that falls on. The only question then is whether you want Sunday or Monday as the first day of the week. This answer is for Monday (per the OP), orafaelreis's answer is for Sunday, Tigran has added an answer for any day as the start of the week. – RobG May 18 '15 at 11:46
  • You need to set the `startYear` to the beginning of the first week, if not, days such as tuesday, january 5th 2016 will come out as week 1, and not week 2. Modified your code with this: `yearStart.setDate(yearStart.getDate() - yearStart.getDay());`, which makes the week number work better for weeks 1 and 2. – peirix Aug 26 '15 at 08:28
  • @peirix—the question was for weeks as for PHP, which uses ISO week numbers per the algorithm stated in the answer with weeks starting on Monday. For 5 Jan 2016, the closest Thursday is 7 Jan, which is the first Thursday in 2016 therefore it in the first week. The previous Thursday (31 Dec 2015) is in the 53rd week of 2015. Perhaps you are using some other algorithm? – RobG Aug 26 '15 at 12:08
  • 18
    Today, January 4 2016, I noticed that it was necesarry to add `d.setMilliseconds(0)` as well - it kept showing different week numbers for the same date depending on whether I used new Date() or new Date("1/4/2016"). Just a heads up for others who might experience the same. – Jacob Lauritzen Jan 04 '16 at 06:38
  • 6
    Provided code does not follow ISO 8601, it's off by one – Eric Grange Feb 26 '16 at 07:53
  • 1
    @Dimitry—it works in every host that is compatible with [*ECMAScript ed 3*](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf) and later, which should be pretty much every implementation currently in use since it was released in December, 1999. I've converted the code to runnable snippets, please advise the implementation in which it returns NaN. – RobG Oct 25 '16 at 10:57
  • @JacobLauritzen—sorry, I missed your comment until now. Yes, the milliseconds need to be zeroed too which can be done when setting the hours to 0. Updated to `d.setHours(0,0,0,0);`. – RobG Oct 25 '16 at 11:00
  • you don't need to set `d.setHours(0,0,0,0);` if your input has already had the time set `var date = new Date("2016-12-29 00:00:00").getWeekNumber();` – Mark Giblin Feb 06 '17 at 22:41
  • @MarkGiblin—the answer includes why zeroing the hours is important. Parsing strings with the Date constructor is strongly recommended against, your example will return NaN in Safari and throw an error. – RobG Feb 06 '17 at 22:58
  • If you made a date object like `new Date()` compared to `new Date("2017-01-22");` then look at it you will see that the new Date() will produce a string like `Sat Feb 11 2017 11:20:16 GMT+0000 (GMT)` and the new Date("2017-01-22") will produce a string `Sun Jan 22 2017 00:00:00 GMT+0000 (GMT)`.... notice anything? Therefore you DON'T need to zero the time if you set a date reference because it automatically sets it to midnight. :) – Mark Giblin Feb 11 '17 at 11:23
  • @MarkGiblin—it's a general function, there is no guarantee that the time is midnight, e.g. `getWeekNumber(new Date())`. Also, `new Date("2017-01-22")` will be treated as UTC, so only the UTC hours will be zero (unless the host is set to a timezone of UTC+0000, when the local hours will be zero too), and this function uses the local time, not UTC. – RobG Feb 11 '17 at 13:32
  • That is true for `new Date()` but not for when you specify a date like previously shown, try it in your browser and see for yourself. – Mark Giblin Feb 15 '17 at 11:28
  • @MarkGiblin—and as I have shown, `new Date("2017-01-22")` sets the date to UTC midnight, not local, so hours are not necessarily zeroed. Of course if they are zero then there is no need to zero them, but there is not guarantee that they are zero to start with, hence the need to do so. This discussion is pointless. – RobG Feb 16 '17 at 00:27
  • @RobG, try it, in every date set the hours ARE zeroed, if you use `new Date()` by itself then the current time IS returned with the result. I wouldn't of posted the response UNLESS this had been checked and the results I found I did post, you seem to want to ignore this fact. As for the UTC and GMT hours, they are the same at midnight, so that a pretty lame argument. – Mark Giblin Feb 21 '17 at 12:11
  • @RobG. Consider this `var x = new Date(); var y = new Date(x.getFullYear(),x.getMonth()+1,x.getDate() ); console.log("> x="+ x); console.log("> y="+y); console.log("> x.getTime() = "+ x.getTime() ); console.log("> y.getTime() = ="+y.getTime() ); // output > x=Tue Feb 21 2017 12:09:54 GMT+0000 (GMT) > y=Tue Mar 21 2017 00:00:00 GMT+0000 (GMT) > x.getTime() = 1487678994042 > y.getTime() = =1490054400000` what do you see? Thats right, one with time, the other with zero hours and for good measure, the getTime() gets UTC milliseconds, what else do you see? – Mark Giblin Feb 21 '17 at 12:16
  • @RobG if you configure your system to São Paulo, Brazil, or Sydney, Australia and compare the results with python datetime for the year 2021 I believe you will see what I'm saying. – Felipe T. Jun 17 '17 at 10:44
  • @FelipeT.— with system set to Sydney Australia, 2021-01-01 (Friday) returns week 53 (of 2020), 2021-01-04 (the following Monday) returns week 1 (of 2021). Both are correct according to the ISO rules. I tested a few others and they were correct as well. Python should return the ISO week number, perhaps it's a bug in the implementation of Python that you're using? – RobG Jun 17 '17 at 13:39
  • It's not for all days, but for some days the result is incorrect. Set your time to São Paulo and try 2021 Feb 22. And I don't think it is a Python bug because the MacOS Calendar also shows the same week as datetime in Python. I wrote a python code to test from 2017 to 2027 and saw a lot of mismatches – Felipe T. Jun 17 '17 at 14:40
  • For 2021-02-22 I get week 8, which is correct. Please provide specific dates and the values returned by this code and Python. Note that if the Mac OS X calendar is set to show week numbers and start of week as Monday, it does not show ISO week numbers, e.g. Fri 2021-01-01 is shown as week 1 when it's ISO week 53 (since the closest Thursday is 2020-12-31). If set to Sunday as the start of the week, it shows week numbers consistent with ISO, but the wrong start of the week (ISO uses Monday). – RobG Jun 17 '17 at 21:21
  • @FelipeT.—I have added a test section where you can compare the results of the answer with those returned by Moment.js. If you find a mis-match, please provide the value entered. – RobG Jun 17 '17 at 21:50
  • 1
    @RobG Thank you for your effort testing your code. I'm sure my calendar shows ISO 8601 weeks. I'm also aware of the subtleties of the standard since I end up implementing my own code when I got some mismatches with yours. The thing is I get week 9 for 2021-02-22 (in my tests and in your test section using Moment.js). It could be my machine, but then I asked some friends to test and they get the same result – Felipe T. Jun 18 '17 at 23:00
  • @FelipeT.—thanks for your response, at this stage it's "unable to replicate", but I'll look into it further when I have time. I know there are bugs in certain Date implementations (e.g. Safari around daylight saving changes) and differences on when it's applied (some apply it exactly on the changeover hour, others 1ms after) and some DST changes are at midnight, but none of those cases seem to be the issue here. Moment.js may have the same bugs as this code as it uses the same Date object. Until I can replicate the issue I'm a bit stumped. – RobG Jun 19 '17 at 00:13
  • @RobG I just realized that I didn't express myself well in my comment above. MomentJS gives me 8 and your code 9. Just wanted to clarify, thank you. – Felipe T. Jun 20 '17 at 10:42
  • @Rob, I couldn't care less about Safari users, never been a Mac fan and that is based on using them. It still does not detract from the fact that you set a date and the hours are zeroed and argue all you like about that and problems in other browsers, it just shows that they are not standards compliant. – Mark Giblin Aug 11 '17 at 20:36
  • 1
    @FelipeT.—came back to this, fixed the issue. There was something going wrong with years starting on Friday during DST. Fixed by using UTC and avoiding DST entirely. I've tested against moment.js for the 50 years from 2000 to 2050 with a number of different time zones. Please let me know if there are any other issues! – RobG Aug 12 '17 at 11:29
  • @MarkGiblin—that Safari returns an invalid date for `new Date("2016-12-29 00:00:00")` is fully standards compliant. It's an example of how using the built-in parser is a bad idea since the standard does not specify parsing of any string other than the limited subset of ISO 8601 included in ECMA-262. Incidentally, I've changed the code to use a Date based on UTC, so hours are set to 0 when creating the "UTC" date. ;-) – RobG Aug 12 '17 at 11:30
  • @RobG -- That means that Safari is non-compliant with standards. It is a valid method of setting the time and date with the Date object. If Safari is having a problem with it, then thats the fault of the browser and not the code, it works in every browser I use on Linux or Windows without a problem, perhaps you should get a real computer? – Mark Giblin Oct 26 '17 at 11:09
  • Well I guess that with the problem of iOS and this Meltdown / Spectre problem, I think that Mac is pretty much done so any argument is pretty irrelevant now, such is the flakeyness of Apple products. When you look at the support that Safari has, it is last on the list of compliant browsers and anyone trying to address this issue as anything other than what it is, think you're blinded by the glitzy product shows apple puts on. – Mark Giblin Jan 09 '18 at 00:33
  • @MarkGiblin—returning an invalid date for "2016-12-29 00:00:00" is fully compliant with every version of ECMA-262. If you have a problem with that, take it up with the [*ECMAScript Technical Committee (TC39)*](https://www.ecma-international.org/memento/TC39.htm). It's an example that using the built–in parser is a bad idea, particularly when relying on non–standard behaviour. – RobG Jan 09 '18 at 01:18
  • No, the W3C set the standards, not ECMAScript guys. Date formats are meant to be 'locale neutral format' which is an ISO standard of YYY-MM-DD and can include a time stame, when one is not present, 00:00:00 is assumed. Now if a browser does not follow that standard, it is not a compliant browser and all the other browsers, even the off beat home brew browsers appear to be following that standard... So I guess the arguing should be done by you to Apple about their flaky product. I guess you would argue that you have to account for DLS times and correct the time on the users machine next..... – Mark Giblin Feb 26 '18 at 09:45
  • @MarkGiblin—the W3C has nothing to do with the ECMAScript language specification (ECMA-262) which defines the Date object, the TC39 members do that. Please understand that returning an invalid date for non–compliant strings is fully compliant with ECMA-262, it's not "off beat" behaviour. Also that built-in parsers are historically and notoriously unreliable, they should be avoided. – RobG Feb 27 '18 at 13:16
  • Sorry but a fully compliant browser will behave in the same way or produce the same results as its competitors, that's the whole point of having standards and compliance. – Mark Giblin Mar 01 '18 at 15:30
  • @MarkGiblin—compliance relates to the language specification. Where an implementation is consistent with the related standard, it is compliant. It's unreasonable and illogical to expect each browser to copy all the others. It would mean whoever introduces a feature first defines it for all others, which is unworkable. One possible result is a race to implement as many features as possible, then fight over who should then copy whom. – RobG Mar 02 '18 at 07:25
  • @RobG -- no it doesn't, it means that all browsers no matter what they are can produce a program or routine that has the desired result, just because only one way was found to make a function, does not automatically everyone follows suit and uses that, what planet are you on? Compliance means that, your browser if its told to getElementsById, it gets elements by the ID but however the programmers deal with it behind the scenes is their problem. So a date function not returning a date based on proper ISO format string and it does not return a valid date... IS NOT COMPLIANT. It is that simple. – Mark Giblin Mar 14 '18 at 16:36
  • @MarkGiblin—your definition of "compliance" is inconsistent with the [accepted meaning](https://www.google.com/search?q=define+compliant) in the context of technical subjects. Also see [*standards compliance*](https://www.google.com/search?q=standarsd+compliance). – RobG Mar 14 '18 at 20:37
  • @RobG - compliant /kəmˈplʌɪənt/ dictionary meaning = meeting or in accordance with rules or standards. SO, what does your dictionary say? Compliance is without a doubt, clear in its meaning and simply put, argue all you like on this point, Safari is a pile of dung and NOT COMPLIANT in terms of what it SHOULD BE DOING. End of as far as I am concerned, you can whistle dixie all you like, it is not going to alter the definition that EVERYONE AGREES WITH in terms of the meaning of the word COMPLIANT. Its not had to work out that Safari is like its vendor, pretty poor quality kit thats over priced. – Mark Giblin Mar 19 '18 at 12:53
  • 2
    Oops you're right, my typo, was supposed to be '2015-12-30' which works. – Ally Sep 24 '18 at 00:44
  • December 1969 29th was also wrong in my case. Adding d.setHours( 0 ) d.setMinutes( 0 ) d.setSeconds( 0 ) d.setMilliseconds( 0 ) fixed it. – Niilo Keinänen Nov 15 '19 at 07:39
  • 1
    @NiiloKeinänen—you can set all the values in one go: `d.setHours(0,0,0,0)`, which is also safer. – RobG Nov 15 '19 at 13:01
  • Does not work for new Date('2017-01-01').getWeekNumber() – Perez Lamed van Niekerk Dec 11 '19 at 11:51
  • @PerezLamedvanNiekerk—you're mistaken. 1 Jan 2017 was a Sunday, so belongs in the week of Thursday, 29 December which was week 52 of 2016. I included a test section in the answer, please check results and compare to the moment.js result before posting. – RobG Dec 11 '19 at 23:28
  • Care to document the `getWeekNumber()` function? It works, but it not clear what it is actually doing in the last three lines especially. – Homunculus Reticulli Dec 10 '20 at 18:26
  • Thank God for this code. I leave here an "auto-documented" version in Typescript that I wrote to help me understand better what this code is doing, in case it can help others as well. https://gist.github.com/oliverfernandez/a670aa9d1d51563316ed41bc935f047a – oliferna Oct 20 '21 at 16:02
  • I know this is quite old, but I'm still getting an unexpected answer I was hoping someone could explain with this. I live in CO/USA and when I type 2021-01-03 into this test I get week 53 from both moment and your script. In my local code I get this answer with 2021-01-04 as well. Can anyone explain how the first week of january is week 53?? – Shawn Pacarar Apr 04 '22 at 22:01
  • @ShawnPacarar—the function uses ISO weeks, which start on Monday. The first week of the year is the first one with 4 or more days in the year, which means the first Thursday or 4 January is always in the first week. 2021-01-03 is a Sunday, the first Thursday is 7 Jan, so the first week starts on the prior Monday, i.e. 4 Jan. The week before that is the last week of 2020, so Sunday 3 Jan and all the days back to the previous Monday (28 Dec 2020) are in week 53 of 2020. It can also be that the last couple of days of December are in week 1 of the following year (e.g. 31 Dec 2024). :-) – RobG Apr 04 '22 at 23:57
54

You can use momentjs library also:

moment().format('W')

PeeHaa
  • 71,436
  • 58
  • 190
  • 262
sixdays
  • 597
  • 4
  • 2
  • 18
    or `moment().week()` – Alex78191 May 18 '17 at 10:58
  • 1
    For those coming here after 2019, moment library was discontinued and the owners recommend the use of other more modern libraries like `Luxon` or `Day.js`. Here is the topic from moment.js: https://momentjs.com/docs/#/-project-status/recommendations/ – Raphael Mello Dec 30 '22 at 11:14
32

Not ISO-8601 week number but if the search engine pointed you here anyway.

As said above but without a class:

let now = new Date();
let onejan = new Date(now.getFullYear(), 0, 1);
let week = Math.ceil((((now.getTime() - onejan.getTime()) / 86400000) + onejan.getDay() + 1) / 7);

console.log(week);
RobG
  • 142,382
  • 31
  • 172
  • 209
nvd
  • 2,995
  • 28
  • 16
  • 12
    The question asked for ISO 8601 which this ignores. As an answer to the question it is simply wrong – havlock Nov 20 '18 at 10:40
  • 10
    @havlock yeah but this is the first result on google for "get week of a year in JavaScript" so it helps a lot of people for this to be there (that don't need the complexity of the accepted answer) – Ivan Castellanos Sep 15 '20 at 13:53
  • There is also [an answer with an identical solution](https://stackoverflow.com/a/19910622/257182) posted a year before this one. – RobG May 14 '21 at 03:20
  • Your code has a bug and returns incorrect numbers. See my answer with a fix. – realPro Apr 19 '22 at 14:45
26

Accordily http://javascript.about.com/library/blweekyear.htm

Date.prototype.getWeek = function() {
  var onejan = new Date(this.getFullYear(), 0, 1);
  var millisecsInDay = 86400000;
  return Math.ceil((((this - onejan) / millisecsInDay) + onejan.getDay() + 1) / 7);
};

let d = new Date(2020,11,30);
for (let i=0; i<14; i++) {
  console.log(`${d.toDateString()} is week ${d.getWeek()}`);
  d.setDate(d.getDate() + 1);
}
RobG
  • 142,382
  • 31
  • 172
  • 209
orafaelreis
  • 2,855
  • 2
  • 28
  • 31
  • 3
    i think since this is being added to the prototype it's what you would expect as Date treats sunday as the first day. – Ed Sykes Dec 10 '15 at 11:06
  • Won't this have problems on Daylight Saving Time days? I think it will not advance until 1am during the summer. – Hafthor Feb 17 '16 at 16:09
  • Also, doesn't this technically not advance the week until 0:00:00.001? Better to use Math.floor? – Hafthor Feb 17 '16 at 16:20
  • This answer treats Sunday as the first day of the week. If 1 Jan isn't a Sunday, then the prior days are in week 1 and the first Sunday is in week 2. That is a very different result to the OP's request. – RobG Apr 05 '22 at 05:49
14

The code below calculates the correct ISO 8601 week number. It matches PHP's date("W") for every week between 1/1/1970 and 1/1/2100.

/**
 * Get the ISO week date week number
 */
Date.prototype.getWeek = function () {
  // Create a copy of this date object
  var target = new Date(this.valueOf());

  // ISO week date weeks start on Monday, so correct the day number
  var dayNr = (this.getDay() + 6) % 7;

  // ISO 8601 states that week 1 is the week with the first Thursday of that year
  // Set the target date to the Thursday in the target week
  target.setDate(target.getDate() - dayNr + 3);

  // Store the millisecond value of the target date
  var firstThursday = target.valueOf();

  // Set the target to the first Thursday of the year
  // First, set the target to January 1st
  target.setMonth(0, 1);

  // Not a Thursday? Correct the date to the next Thursday
  if (target.getDay() !== 4) {
    target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
  }

  // The week number is the number of weeks between the first Thursday of the year
  // and the Thursday in the target week (604800000 = 7 * 24 * 3600 * 1000)
  return 1 + Math.ceil((firstThursday - target) / 604800000);
}

Source: Taco van den Broek


If you're not into extending prototypes, then here's a function:

function getWeek(date) {
  if (!(date instanceof Date)) date = new Date();

  // ISO week date weeks start on Monday, so correct the day number
  var nDay = (date.getDay() + 6) % 7;

  // ISO 8601 states that week 1 is the week with the first Thursday of that year
  // Set the target date to the Thursday in the target week
  date.setDate(date.getDate() - nDay + 3);

  // Store the millisecond value of the target date
  var n1stThursday = date.valueOf();

  // Set the target to the first Thursday of the year
  // First, set the target to January 1st
  date.setMonth(0, 1);

  // Not a Thursday? Correct the date to the next Thursday
  if (date.getDay() !== 4) {
    date.setMonth(0, 1 + ((4 - date.getDay()) + 7) % 7);
  }

  // The week number is the number of weeks between the first Thursday of the year
  // and the Thursday in the target week (604800000 = 7 * 24 * 3600 * 1000)
  return 1 + Math.ceil((n1stThursday - date) / 604800000);
}

Sample usage:

getWeek(); // Returns 37 (or whatever the current week is)
getWeek(new Date('Jan 2, 2011')); // Returns 52
getWeek(new Date('Jan 1, 2016')); // Returns 53
getWeek(new Date('Jan 4, 2016')); // Returns 1
thdoan
  • 18,421
  • 1
  • 62
  • 57
  • I like this function, but I have a question; What do I do if I want to put it back to sunday? I have no idea what the `+6 ) % 7` part does. Thanks from a scrub! – NoobishPro Oct 22 '16 at 16:53
  • 1
    @Babydead ISO week starts on a Monday, but JavaScript [`getDay()`](http://www.w3schools.com/jsref/jsref_getday.asp) starts on a Sunday, so if you want it to start on Sunday then you can remove the correction: `var nDay = date.getDay();` – thdoan Oct 24 '16 at 02:13
  • 1
    The function version mutates its argument (which is a bad practice). To remedy that, replace the guard at the top with: ```javascript date = date instanceof Date ? new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) : new Date() ``` – Tom Aug 23 '20 at 03:47
  • Shouldn't the last line be 'n1stThursday - date.getMilliseconds()' ? – Jamie Nicholl-Shelley Jan 17 '23 at 14:39
13

Jacob Wright's Date.format() library implements date formatting in the style of PHP's date() function and supports the ISO-8601 week number:

new Date().format('W');

It may be a bit overkill for just a week number, but it does support PHP style formatting and is quite handy if you'll be doing a lot of this.

Brad Koch
  • 19,267
  • 19
  • 110
  • 137
6
getWeekOfYear: function(date) {
        var target = new Date(date.valueOf()),
            dayNumber = (date.getUTCDay() + 6) % 7,
            firstThursday;

        target.setUTCDate(target.getUTCDate() - dayNumber + 3);
        firstThursday = target.valueOf();
        target.setUTCMonth(0, 1);

        if (target.getUTCDay() !== 4) {
            target.setUTCMonth(0, 1 + ((4 - target.getUTCDay()) + 7) % 7);
        }

        return Math.ceil((firstThursday - target) /  (7 * 24 * 3600 * 1000)) + 1;
    }

Following code is timezone-independent (UTC dates used) and works according to the https://en.wikipedia.org/wiki/ISO_8601

Dmitry Volokh
  • 1,630
  • 16
  • 28
  • The posted code is not "timezone independent". For example, a system set to Australia/Sydney (UTC+11 over summer) and a date for Monday 30 Dec 2019 at 05:00 it returns week 52 (of 2019) because the UTC date is Sunday 29 Dec. It should return week 1 (of 2020). – RobG May 14 '21 at 07:10
6

Get the weeknumber of any given Date

function week(year,month,day) {
    function serial(days) { return 86400000*days; }
    function dateserial(year,month,day) { return (new Date(year,month-1,day).valueOf()); }
    function weekday(date) { return (new Date(date)).getDay()+1; }
    function yearserial(date) { return (new Date(date)).getFullYear(); }
    var date = year instanceof Date ? year.valueOf() : typeof year === "string" ? new Date(year).valueOf() : dateserial(year,month,day), 
        date2 = dateserial(yearserial(date - serial(weekday(date-serial(1))) + serial(4)),1,3);
    return ~~((date - date2 + serial(weekday(date2) + 5))/ serial(7));
}

Example

console.log(
    week(2016, 06, 11),//23
    week(2015, 9, 26),//39
    week(2016, 1, 1),//53
    week(2016, 1, 4),//1
    week(new Date(2016, 0, 4)),//1
    week("11 january 2016")//2
);
A1rPun
  • 16,287
  • 7
  • 57
  • 90
Hans Petersen
  • 61
  • 1
  • 2
  • 1
    I cannot believe it, but this function is the only one that worked all the time! The accepted answer played up when it went past daylight savings, others said '0' as the week number on certain years. - and some relied on UTC functions that sometimes returned the previous day therefore assigning it week '53' or '54'. Unfortunately I need the week to begin on a Sunday and this code is very hard to understand... – Melissa Zachariadis Oct 16 '16 at 02:52
  • @MelissaZachariadis said `I need the week to begin on a Sunday`; I think the only needed change is in function weekday()'s `.getDay()+1` to be changed to `.getDay()` – Rafa Aug 28 '19 at 11:20
  • This is what i need, but this code is kinda messy and hard to read – ii iml0sto1 Aug 17 '20 at 20:29
5

I found useful the Java SE's SimpleDateFormat class described on Oracle's specification: http://goo.gl/7MbCh5. In my case in Google Apps Script it worked like this:

function getWeekNumber() {
  var weekNum = parseInt(Utilities.formatDate(new Date(), "GMT", "w"));
  Logger.log(weekNum);
}

For example in a spreadsheet macro you can retrieve the actual timezone of the file:

function getWeekNumber() {
  var weekNum = parseInt(Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "w"));
  Logger.log(weekNum);
}
Balu Ertl
  • 313
  • 5
  • 6
4

This adds "getWeek" method to Date.prototype which returns number of week from the beginning of the year. The argument defines which day of the week to consider the first. If no argument passed, first day is assumed Sunday.

/**
 * Get week number in the year.
 * @param  {Integer} [weekStart=0]  First day of the week. 0-based. 0 for Sunday, 6 for Saturday.
 * @return {Integer}                0-based number of week.
 */
Date.prototype.getWeek = function(weekStart) {
    var januaryFirst = new Date(this.getFullYear(), 0, 1);
    if(weekStart !== undefined && (typeof weekStart !== 'number' || weekStart % 1 !== 0 || weekStart < 0 || weekStart > 6)) {
      throw new Error('Wrong argument. Must be an integer between 0 and 6.');
    }
    weekStart = weekStart || 0;
    return Math.floor((((this - januaryFirst) / 86400000) + januaryFirst.getDay() - weekStart) / 7);
};
Tigran
  • 2,800
  • 1
  • 19
  • 19
  • 1
    The first calendar week of 2016 starts at the [4th of January in Germany](http://kalenderwoche.net/alle-kalenderwochen-2016.php), but your function starts counting again from 0 from the 1st January on. It also returns wrong numbers at the end of the year, e.g. 52 for 2018-11-31 (53rd week), although it's already the [1st calendar week of 2019](http://kalenderwoche.net/alle-kalenderwochen-2018.php): `new Date(Date.UTC(2018,11, 31)).getWeek(1)+1` (Monday is the 1st day of week in Germany). – CodeManX Aug 29 '15 at 18:02
  • That's how it was intended, and that's, I believe, the most likely use case. Otherwise the first 3 days of 2016 would fall out. First days of the month are considered to comprise the first week for that month, no-matter which and how many days there are. If you need the function to work differently, you can tweak it according to your needs. Likewise, if a week falls into both the given year and the following year, it can be called the last week of that year, as well as the first week of the following year (according to current logic). – Tigran Sep 01 '15 at 09:36
  • Thanks for the info. I ended up using RobG's solution, which implements ISO8601 week dates correctly (last days in December and the first days in January may belong to week 52, 53 or 1: https://en.m.wikipedia.org/wiki/ISO_week_date – CodeManX Sep 01 '15 at 11:08
3

If you are already in an Angular project you could use $filter('date').

For example:

var myDate = new Date();
var myWeek = $filter('date')(myDate, 'ww');
Gabriel Furstenheim
  • 2,969
  • 30
  • 27
2

This week number thing has been a real pain in the a**. Most trivial solutions around the web didn't really work for me as they worked most of the time but all of them broke at some point, especially when year changed and last week of the year was suddenly next year's first week etc. Even Angular's date filter showed incorrect data (it was the 1st week of next year, Angular gave week 53).

Note: The examples are designed to work with European weeks (Mon first)!

getWeek()

Date.prototype.getWeek = function(){

    // current week's Thursday
    var curWeek = new Date(this.getTime());
        curWeek.setDay(4);

    // current year's first week's Thursday
    var firstWeek = new Date(curWeek.getFullYear(), 0, 4);
        firstWeek.setDay(4);

    return (curWeek.getDayIndex() - firstWeek.getDayIndex()) / 7 + 1;
};

setDay()

/**
* Make a setDay() prototype for Date
* Sets week day for the date
*/
Date.prototype.setDay = function(day){

    // Get day and make Sunday to 7
    var weekDay = this.getDay() || 7;
    var distance = day - weekDay;
    this.setDate(this.getDate() + distance);

    return this;
}

getDayIndex()

/*
* Returns index of given date (from Jan 1st)
*/

Date.prototype.getDayIndex = function(){
    var start = new Date(this.getFullYear(), 0, 0);
    var diff = this - start;
    var oneDay = 86400000;
    
    return Math.floor(diff / oneDay);
};

I have tested this and it seems to be working very well but if you notice a flaw in it, please let me know.

Spacha
  • 313
  • 4
  • 7
2

The code snippet which works pretty well for me is this one:

var yearStart = +new Date(d.getFullYear(), 0, 1);
var today = +new Date(d.getFullYear(),d.getMonth(),d.getDate());
var dayOfYear = ((today - yearStart + 1) / 86400000);
return Math.ceil(dayOfYear / 7).toString();

Note:
d is my Date for which I want the current week number.
The + converts the Dates into numbers (working with TypeScript).

Vasco
  • 418
  • 1
  • 8
  • 12
2

With Luxon (https://github.com/moment/luxon) :

import { DateTime } from 'luxon';
const week: number = DateTime.fromJSDate(new Date()).weekNumber;
Nato Boram
  • 4,083
  • 6
  • 28
  • 58
  • 1
    Just a note: Luxon has so many options to create a given date; the `fromJSDate()` is just one of many. Luxon was created by one of the maintainers of MomentJS, and is expected to be maintained indefinitely. At this point in time, either this or Moment are really the best ways to accomplish this task. – randy Sep 05 '20 at 12:39
2

this code fixes a bug in answer by nvd

function getWeek(param) {
    let onejan = new Date(param.getFullYear(), 0, 1);
    return Math.ceil((((param.getTime() - onejan.getTime()) / 86400000) + onejan.getDay()) / 7);
}
realPro
  • 1,713
  • 3
  • 22
  • 34
  • 1
    please define what you are explaining – jaibalaji Apr 20 '22 at 13:19
  • @jaibalaji this code fixes a bug in answer by nvd – realPro Apr 20 '22 at 16:37
  • This is for Sunday being the first day of the week and fixes nvd's https://stackoverflow.com/a/27125580/4953663 which doesn't handle a non-Sunday first day of the year correctly. This is what I needed, thanks! – Elijah May 18 '23 at 20:43
1

Here is my implementation for calculating the week number in JavaScript. corrected for summer and winter time offsets as well. I used the definition of the week from this article: ISO 8601

Weeks are from mondays to sunday, and january 4th is always in the first week of the year.

// add get week prototype functions
// weeks always start from monday to sunday
// january 4th is always in the first week of the year
Date.prototype.getWeek = function () {
    year = this.getFullYear();
    var currentDotw = this.getWeekDay();
    if (this.getMonth() == 11 && this.getDate() - currentDotw > 28) {
        // if true, the week is part of next year 
        return this.getWeekForYear(year + 1);
    }
    if (this.getMonth() == 0 && this.getDate() + 6 - currentDotw < 4) {
        // if true, the week is part of previous year
        return this.getWeekForYear(year - 1);
    }
    return this.getWeekForYear(year);
}

// returns a zero based day, where monday = 0
// all weeks start with monday
Date.prototype.getWeekDay = function () {
    return  (this.getDay() + 6) % 7;
}

// corrected for summer/winter time
Date.prototype.getWeekForYear = function (year) {
    var currentDotw = this.getWeekDay();
    var fourjan = new Date(year, 0, 4);
    var firstDotw = fourjan.getWeekDay();
    var dayTotal = this.getDaysDifferenceCorrected(fourjan) // the difference in days between the two dates.
    // correct for the days of the week
    dayTotal += firstDotw; // the difference between the current date and the first monday of the first week, 
    dayTotal -= currentDotw; // the difference between the first monday and the current week's monday
    // day total should be a multiple of 7 now
    var weeknumber = dayTotal / 7 + 1; // add one since it gives a zero based week number.
    return weeknumber;
}

// corrected for timezones and offset
Date.prototype.getDaysDifferenceCorrected = function (other) {
    var millisecondsDifference = (this - other);
    // correct for offset difference. offsets are in minutes, the difference is in milliseconds
    millisecondsDifference += (other.getTimezoneOffset()- this.getTimezoneOffset()) * 60000;
    // return day total. 1 day is 86400000 milliseconds, floor the value to return only full days
    return Math.floor(millisecondsDifference / 86400000);
}

for testing i used the following JavaScript tests in Qunit

var runweekcompare = function(result, expected) {
    equal(result, expected,'Week nr expected value: ' + expected + ' Actual value: ' + result);
}

test('first week number test', function () {
    expect(5);
    var temp = new Date(2016, 0, 4); // is the monday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 4, 23, 50); // is the monday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 10, 23, 50); // is the sunday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 11, 23, 50); // is the second week of the year
    runweekcompare(temp.getWeek(), 2);
    var temp = new Date(2016, 1, 29, 23, 50); // is the 9th week of the year
    runweekcompare(temp.getWeek(), 9);
});

test('first day is part of last years last week', function () {
    expect(2);
    var temp = new Date(2016, 0, 1, 23, 50); // is the first last week of the previous year
    runweekcompare(temp.getWeek(), 53);
    var temp = new Date(2011, 0, 2, 23, 50); // is the first last week of the previous year
    runweekcompare(temp.getWeek(), 52);
});

test('last  day is part of next years first week', function () {
    var temp = new Date(2013, 11, 30); // is part of the first week of 2014
    runweekcompare(temp.getWeek(), 1);
});

test('summer winter time change', function () {
    expect(2);
    var temp = new Date(2000, 2, 26); 
    runweekcompare(temp.getWeek(), 12);
    var temp = new Date(2000, 2, 27); 
    runweekcompare(temp.getWeek(), 13);
});

test('full 20 year test', function () {
    //expect(20 * 12 * 28 * 2);
    for (i = 2000; i < 2020; i++) {
        for (month = 0; month < 12; month++) {
            for (day = 1; day < 29 ; day++) {
                var temp = new Date(i, month, day);
                var expectedweek = temp.getWeek();
                var temp2 = new Date(i, month, day, 23, 50);
                var resultweek = temp.getWeek();
                equal(expectedweek, Math.round(expectedweek), 'week number whole number expected ' + Math.round(expectedweek) + ' resulted week nr ' + expectedweek);
                equal(resultweek, expectedweek, 'Week nr expected value: ' + expectedweek + ' Actual value: ' + resultweek + ' for year ' + i + ' month ' + month + ' day ' + day);
            }
        }
    }
});
martijn
  • 1,417
  • 1
  • 16
  • 26
1

Here is a slight adaptation for Typescript that will also return the dates for the week start and week end. I think it's common to have to display those in a user interface, since people don't usually remember week numbers.

function getWeekNumber(d: Date) {
  // Copy date so don't modify original
  d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
  // Set to nearest Thursday: current date + 4 - current day number Make
  // Sunday's day number 7
  d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
  // Get first day of year
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  // Calculate full weeks to nearest Thursday
  const weekNo = Math.ceil(
    ((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7
  );

  const weekStartDate = new Date(d.getTime());
  weekStartDate.setUTCDate(weekStartDate.getUTCDate() - 3);

  const weekEndDate = new Date(d.getTime());
  weekEndDate.setUTCDate(weekEndDate.getUTCDate() + 3);

  return [d.getUTCFullYear(), weekNo, weekStartDate, weekEndDate] as const;
}
Thijs Koerselman
  • 21,680
  • 22
  • 74
  • 108
1

This is my typescript implementation which I tested against some dates. This implementation allows you to set the first day of the week to any day.

//sunday = 0, monday = 1, ...
static getWeekNumber(date: Date, firstDay = 1): number {
  const d = new Date(date.getTime());
  d.setHours(0, 0, 0, 0);

  //Set to first day of the week since it is the same weeknumber
  while(d.getDay() != firstDay){
    d.setDate(d.getDate() - 1);
  }

  const dayOfYear = this.getDayOfYear(d);
  let weken = Math.floor(dayOfYear/7);

  // add an extra week if 4 or more days are in this year.
  const daysBefore = ((dayOfYear % 7) - 1);
  if(daysBefore >= 4){
    weken += 1;
  }

  //if the last 3 days onf the year,it is the first week
  const t = new Date(d.getTime());
  t.setDate(t.getDate() + 3);
  if(t.getFullYear() > d.getFullYear()){
    return 1;
  }
  weken += 1;

  return weken;
}

private static getDayOfYear(date: Date){
  const start = new Date(date.getFullYear(), 0, 0);
  const diff = (date.getTime() - start.getTime()) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000);
  const oneDay = 1000 * 60 * 60 * 24;
  const day = Math.floor(diff / oneDay);
  return day;
}

Tests:

describe('getWeeknumber', () => {
  it('should be ok for 0 sunday', () => {
    expect(DateUtils.getWeekNumber(new Date(2015, 0, 4), 0)).toBe(1);

    expect(DateUtils.getWeekNumber(new Date(2017, 0, 1), 0)).toBe(1);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 2), 0)).toBe(1);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 8), 0)).toBe(2);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 9), 0)).toBe(2);

    expect(DateUtils.getWeekNumber(new Date(2020, 11, 28), 0)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 29), 0)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 30), 0)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 31), 0)).toBe(53);

    expect(DateUtils.getWeekNumber(new Date(2022, 0, 3), 0)).toBe(1);
  });

  it('should be ok for monday 1 default', () => {
    expect(DateUtils.getWeekNumber(new Date(2015, 0, 4), 1)).toBe(1);

    expect(DateUtils.getWeekNumber(new Date(2017, 0, 1), 1)).toBe(52);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 2), 1)).toBe(1);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 8), 1)).toBe(1);
    expect(DateUtils.getWeekNumber(new Date(2017, 0, 9), 1)).toBe(2);

    expect(DateUtils.getWeekNumber(new Date(2020, 11, 28), 1)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 29), 1)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 30), 1)).toBe(53);
    expect(DateUtils.getWeekNumber(new Date(2020, 11, 31), 1)).toBe(53);

    expect(DateUtils.getWeekNumber(new Date(2022, 0, 3), 1)).toBe(1);
  });
});
Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
0

I tried a lot to get the shortest code to get the weeknumber ISO-conform.

Date.prototype.getWeek=function(){
    var date=new Date(this);
    date.setHours(0,0,0,0);
    return Math.round(((date.setDate(this.getDate()+2-(this.getDay()||7))-date.setMonth(0,4))/8.64e7+3+(date.getDay()||7))/7)+"/"+date.getFullYear();}

The variable date is necessary to avoid to alter the original this. I used the return values of setDate() and setMonth() to dispense with getTime() to save code length and I used an expontial number for milliseconds of a day instead of a multiplication of single elements or a number with five zeros. this is Date or Number of milliseconds, return value is String e.g. "49/2017".

  • This doesn't work at all in 2020. Jan 5th returns as 53rd week of 2019 (ok, but not great). Jan 6th returns as 2nd week of 2020. Effectively, there's no first week of 2020... – randy Aug 30 '20 at 12:50
0

Another library-based option: use d3-time-format:

const formatter = d3.timeFormat('%U');
const weekNum = formatter(new Date());
ericsoco
  • 24,913
  • 29
  • 97
  • 127
0

Shortest workaround for Angular2+ DatePipe, adjusted for ISO-8601:

import {DatePipe} from "@angular/common";

public rightWeekNum: number = 0;
  
constructor(private datePipe: DatePipe) { }
    
calcWeekOfTheYear(dateInput: Date) {
  let falseWeekNum = parseInt(this.datePipe.transform(dateInput, 'ww'));
  this.rightWeekNum = (dateInput.getDay() == 0) ? falseWeekNumber-1 : falseWeekNumber;
}
connectedMind
  • 421
  • 4
  • 17
0

Inspired from RobG's answer.

What I wanted is the day of the week of a given date. So my answer is simply based on the day of the week Sunday. But you can choose the other day (i.e. Monday, Tuesday...);

First I find the Sunday in a given date and then calculate the week.

function getStartWeekDate(d = null) {
  const now = d || new Date();
  now.setHours(0, 0, 0, 0);
  const sunday = new Date(now);
  sunday.setDate(sunday.getDate() - sunday.getDay());
  return sunday;
}

function getWeek(date) {
  const sunday = getStartWeekDate(date);
  const yearStart = new Date(Date.UTC(2021, 0, 1));
  const weekNo = Math.ceil((((sunday - yearStart) / 86400000) + 1) / 7);
  return weekNo;
}
// tests
for (let i = 0; i < 7; i++)  {
  let m = 14 + i;
  let x = getWeek(new Date(2021, 2, m));
  console.log('week num: ' + x, x + ' == ' + 11, x == 11, m);
}

for (let i = 0; i < 7; i++)  {
  let m = 21 + i;
  let x = getWeek(new Date(2021, 2, m));
  console.log('week num: ' + x, x + ' == ' + 12, x == 12, 'date day: ' +  m);
}
for (let i = 0; i < 4; i++)  {
  let m = 28 + i;
  let x = getWeek(new Date(2021, 2, m));
  console.log('week num: ' + x, x + ' == ' + 13, x == 13, 'date day: ' + m);
}
for (let i = 0; i < 3; i++)  {
  let m = 1 + i;
  let x = getWeek(new Date(2021, 3, m));
  console.log('week num: ' + x, x + ' == ' + 13, x == 13, 'date day: ' +  m);
}

for (let i = 0; i < 7; i++)  {
  let m = 4 + i;
  let x = getWeek(new Date(2021, 3, m));
  console.log('week num: ' + x, x + ' == ' + 14, x == 14, 'date day: ' +  m);
}
Phoenix404
  • 898
  • 1
  • 14
  • 29
0
import dayJs from 'dayjs';
import isoWeek from 'dayjs/plugin/isoWeek';

dayJs.extend(isoWeek);

/**
 * Get the current week number based on date.
 *
 * @return {number}
 * @param date
 */
export const getWeekNumberByDate = (date) => dayJs(date).isoWeek();
farr3ll
  • 1
  • 1
-1
now = new Date();
today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
firstOfYear = new Date(now.getFullYear(), 0, 1);
numOfWeek = Math.ceil((((today - firstOfYear) / 86400000)-1)/7);
Le Dang Duong
  • 89
  • 1
  • 1
  • 7