49

How can I calculate the date in JavaScript knowing the week number and the year? For week number 20 and year 2013 I want to obtain 2013-05-16. I am trying it like this:

Date.prototype.dayofYear = function () {
  var d = new Date(this.getFullYear(), 0, 0)
  return Math.floor((/* enter code here */ this - d) / 8.64e + 7)
}
adius
  • 13,685
  • 7
  • 45
  • 46
user2369009
  • 555
  • 2
  • 5
  • 11
  • You should be able to find the answer here: http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php - just Googled it. – Elle May 16 '13 at 14:45
  • 1
    i want the revers. knowing weeknumber, getting date.. – user2369009 May 16 '13 at 14:48
  • 6
    The answers below actually fulfill your request of Javascript code, but FWIW, the momentjs library handles this nicely. For ISO 8601 week numbers, `moment("2013W20")` gives: `"2013-05-13T00:00:00-06:00"`. – Rich Armstrong Dec 22 '17 at 17:02

14 Answers14

118
function getDateOfWeek(w, y) {
    var d = (1 + (w - 1) * 7); // 1st of January + 7 days for each week

    return new Date(y, 0, d);
}

This uses the simple week definition, meaning the 20th week of 2013 is May 14.

To calculate the date of the start of a given ISO8601 week (which will always be a Monday) either use Moment.js, e.g.:

moment("2013W20").toDate()

or without external libraries:

/**
 * Get the date from an ISO 8601 week and year
 *
 * https://en.wikipedia.org/wiki/ISO_week_date
 *
 * @param {number} week ISO 8601 week number
 * @param {number} year ISO year
 *
 * Examples:
 *  getDateOfIsoWeek(53, 1976) -> Mon Dec 27 1976
 *  getDateOfIsoWeek( 1, 1978) -> Mon Jan 02 1978
 *  getDateOfIsoWeek( 1, 1980) -> Mon Dec 31 1979
 *  getDateOfIsoWeek(53, 2020) -> Mon Dec 28 2020
 *  getDateOfIsoWeek( 1, 2021) -> Mon Jan 04 2021
 *  getDateOfIsoWeek( 0, 2023) -> Invalid (no week 0)
 *  getDateOfIsoWeek(53, 2023) -> Invalid (no week 53 in 2023)
 */
function getDateOfIsoWeek(week, year) {
    week = parseFloat(week);
    year = parseFloat(year);
  
    if (week < 1 || week > 53) {
      throw new RangeError("ISO 8601 weeks are numbered from 1 to 53");
    } else if (!Number.isInteger(week)) {
      throw new TypeError("Week must be an integer");
    } else if (!Number.isInteger(year)) {
      throw new TypeError("Year must be an integer");
    }
  
    const simple = new Date(year, 0, 1 + (week - 1) * 7);
    const dayOfWeek = simple.getDay();
    const isoWeekStart = simple;

    // Get the Monday past, and add a week if the day was
    // Friday, Saturday or Sunday.
  
    isoWeekStart.setDate(simple.getDate() - dayOfWeek + 1);
    if (dayOfWeek > 4) {
        isoWeekStart.setDate(isoWeekStart.getDate() + 7);
    }

    // The latest possible ISO week starts on December 28 of the current year.
    if (isoWeekStart.getFullYear() > year ||
        (isoWeekStart.getFullYear() == year &&
         isoWeekStart.getMonth() == 11 &&
         isoWeekStart.getDate() > 28)) {
        throw new RangeError(`${year} has no ISO week ${week}`);
    }
  
    return isoWeekStart;
}

Result: the 20th week of 2013 is May 13, which can be confirmed here.

Elle
  • 3,695
  • 1
  • 17
  • 31
  • 2
    this is not working for e.g first week of 2009. which should start at 29.12.2008 and your method is returning 5th of January – Marcin Sep 03 '13 at 09:52
  • I believe `dow < 4` should be `dow <= 4` but I haven't thoroughly tested it. – Elle Sep 05 '13 at 07:31
  • 1
    yes, the ISO week start in year when first Thursday is in that week. So if dow is 4 means week start. <= will solve this issue. – Marcin Sep 05 '13 at 07:33
  • Still not working properly >>> getDateOfISOWeek(1,2009) Date {Mon Dec 29 2008 00:00:00 GMT+0530 (IST)} - This right >>> getDateOfISOWeek(14,2009) Date {Mon Mar 30 2009 00:00:00 GMT+0530 (IST)} - Right >>> getDateOfISOWeek(15,2009) Date {Mon Apr 06 2009 00:00:00 GMT+0530 (IST)} - Worng – Subha Apr 25 '14 at 15:25
  • 1
    @Damodharan Week 15 in 2009 DO start at Mon Apr 6. – Leif Neland May 23 '14 at 07:32
  • @Damodharan http://www.epochconverter.com/date-and-time/weeknumbers-by-year.php?year=2009 – Elle May 24 '14 at 09:12
  • 14
    I was getting incorrect dates when dealing with parts of the year that took into consideration Daylight Saving Time, to prevent this I changed the creation of the simple variable to use the Date.UTC() constructor. `var simple = new Date(Date.UTC(y, 0, 1 + (w - 1) * 7));` – Tr1stan Jan 15 '15 at 21:23
  • @Tr1stan I don't understand, how does Daylight Savings affect the date? – Elle Jan 17 '15 at 01:54
  • 1
    @JordanTrudgett, When I was testing this last week, the `simple` var was being set as `Wed Sep 03 2014 **23:00:00** GMT+0100 (GMT Daylight Time)` - which was causing the final date to be a week out - I'll do some more testing as it is no longer doing this, but I'm on a different machine. – Tr1stan Jan 20 '15 at 17:11
  • @Tr1stan could be an interesting edge case. I wasn't aware of any time-zone considerations in this function.. They all should be midnight / timeless dates in the local timezone, but it's Javascript so.. – Elle Jan 20 '15 at 23:33
  • How would I go about getting the first day of the week, but with the weeks starting with Monday instead of Sunday? – hampani Aug 28 '21 at 08:51
8

Sorry if this is a little verbose but this solution will also return the Sunday after calculating the week number. It combines answers I've seen from a couple different places:

function getSundayFromWeekNum(weekNum, year) {
    var sunday = new Date(year, 0, (1 + (weekNum - 1) * 7));
    while (sunday.getDay() !== 0) {
        sunday.setDate(sunday.getDate() - 1);
    }
    return sunday;
}
nairys
  • 333
  • 3
  • 9
6

2019 version (if anyone wants to calculate the date of week's start)

The answer of Elle is pretty much right, but there is one exception: if you want to get a date of start of the week - it won't help you because Elle's algorithm doesn't mind the day, from which the week starts of, at all.

And here is why:

Elle's solution

function getDateOfWeek(w, y) {
  var d = (1 + (w - 1) * 7); // 1st of January + 7 days for each week

  return new Date(y, 0, d);
}

Here you basically just calculating the amount of days from the start of the year (1st January). This means that it doesn't matter from which day your year starts of: Monday, Sunday or Friday - it will not make any difference.

To set the day, from which your week will start of (let's say Monday, for example), you just need to:

function getDateOfWeek(w, y) {
  let date = new Date(y, 0, (1 + (w - 1) * 7)); // Elle's method
  date.setDate(date.getDate() + (1 - date.getDay())); // 0 - Sunday, 1 - Monday etc
  return date
}
Andrew
  • 101
  • 1
  • 7
  • Simple week definition just starts on Jan 1 and counts weeks from there. The ISO week start will always start on Monday. – Elle Jun 29 '23 at 14:51
5

ISO Weeks

function weekDateToDate (year, week, day) {
  const firstDayOfYear = new Date(year, 0, 1)
  const days = 2 + day + (week - 1) * 7 - firstDayOfYear.getDay()
  return new Date(year, 0, days)
}
adius
  • 13,685
  • 7
  • 45
  • 46
NoName
  • 75
  • 1
  • 1
4

Get date range according to week number

Date.prototype.getWeek = function () {
    var target  = new Date(this.valueOf());
    var dayNr   = (this.getDay() + 6) % 7;
    target.setDate(target.getDate() - dayNr + 3);
    var firstThursday = target.valueOf();
    target.setMonth(0, 1);
    if (target.getDay() != 4) {
        target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
    }
    return 1 + Math.ceil((firstThursday - target) / 604800000);
}

function getDateRangeOfWeek(weekNo){
    var d1 = new Date();
    numOfdaysPastSinceLastMonday = eval(d1.getDay()- 1);
    d1.setDate(d1.getDate() - numOfdaysPastSinceLastMonday);
    var weekNoToday = d1.getWeek();
    var weeksInTheFuture = eval( weekNo - weekNoToday );
    d1.setDate(d1.getDate() + eval( 7 * weeksInTheFuture ));
    var rangeIsFrom = eval(d1.getMonth()+1) +"/" + d1.getDate() + "/" + d1.getFullYear();
    d1.setDate(d1.getDate() + 6);
    var rangeIsTo = eval(d1.getMonth()+1) +"/" + d1.getDate() + "/" + d1.getFullYear() ;
    return rangeIsFrom + " to "+rangeIsTo;
};

getDateRangeOfWeek(10)
"3/6/2017 to 3/12/2017"

getDateRangeOfWeek(30)
"7/24/2017 to 7/30/2017"
Aathi
  • 2,599
  • 2
  • 19
  • 16
  • 2
    How do you know the required year without allowing user to pass the year? @Aathi – tharindu Jul 31 '19 at 08:18
  • I think this is more easily done with the accepted answer passed into this with `6` to get the end of the week: ```function addDays(date = new Date(), days) { var end = new Date(date); end.setDate(end.getDate() + days); return end; }``` – notsodev Apr 22 '20 at 14:34
2
function getDateOfWeek(weekNumber,year){
    //Create a date object starting january first of chosen year, plus the number of days in a week multiplied by the week number to get the right date.
    return new Date(year, 0, 1+((weekNumber-1)*7));
}
var myDate = getDateOfWeek(20,2013);
Salketer
  • 14,263
  • 2
  • 30
  • 58
  • 1
    Month needs to start from 0: http://stackoverflow.com/questions/1208519/javascript-date-objects-month-index-begins-with-0 – Elle May 16 '13 at 15:04
1

ISO week date (e.g. 2017-W32-3) to normal date:

const getZeroBasedIsoWeekDay = date => (date.getDay() + 6) % 7
const getIsoWeekDay = date => getZeroBasedIsoWeekDay(date) + 1

function weekDateToDate(year, week, weekDay) {
  const zeroBasedWeek = week - 1
  const zeroBasedWeekDay = weekDay - 1
  let days = (zeroBasedWeek * 7) + zeroBasedWeekDay

  // Dates start at 2017-01-01 and not 2017-01-00
  days += 1

  const firstDayOfYear = new Date(year, 0, 1)
  const firstIsoWeekDay = getIsoWeekDay(firstDayOfYear)
  const zeroBasedFirstIsoWeekDay = getZeroBasedIsoWeekDay(firstDayOfYear)

  // If year begins with W52 or W53
  if (firstIsoWeekDay > 4) days += 8 - firstIsoWeekDay
  // Else begins with W01
  else days -= zeroBasedFirstIsoWeekDay

  return new Date(year, 0, days)
}

const expectedAndActual = [
  [new Date('2007-01-01'), weekDateToDate(2007,  1, 1)],
  [new Date('2015-11-24'), weekDateToDate(2015, 48, 2)],
  [new Date('2015-12-31'), weekDateToDate(2015, 53, 4)],
  [new Date('2016-01-03'), weekDateToDate(2015, 53, 7)],
  [new Date('2017-01-01'), weekDateToDate(2016, 52, 7)],
  [new Date('2017-01-02'), weekDateToDate(2017,  1, 1)],
  [new Date('2017-05-07'), weekDateToDate(2017, 18, 7)],
  [new Date('2018-12-31'), weekDateToDate(2019,  1, 1)],
]

expectedAndActual
  .forEach(value => {
    const expected = value[0].toISOString()
    const actual = value[1].toISOString()
    const isEqual = actual === expected
    console.assert(isEqual, '%s !== %s', actual, expected)
    console.log(actual, '===', expected)
  })
adius
  • 13,685
  • 7
  • 45
  • 46
  • This one was the one that worked best for me. Strange that it was downvoted. Only change I did was const zeroBasedWeekDay = weekDay; – Johansrk Jan 19 '21 at 21:53
1

@adius function worked for me but I made some improvements for people who are looking for a simple copy paste solution:

/**
 * get date by week number
 * @param  {Number} year 
 * @param  {Number} week 
 * @param  {Number} day of week (optional; default = 0 (Sunday)) 
 * @return {Date}      
 */

  function weekToDate(year, week, weekDay = 0) {
    const getZeroBasedIsoWeekDay = date => (date.getDay() + 6) % 7;
    const getIsoWeekDay = date => getZeroBasedIsoWeekDay(date) + 1;
    const zeroBasedWeek = week - 1;
    const zeroBasedWeekDay = weekDay - 1;
    let days = (zeroBasedWeek * 7) + zeroBasedWeekDay;
        // Dates start at 2017-01-01 and not 2017-01-00
        days += 1;
  
    const firstDayOfYear = new Date(year, 0, 1);
    const firstIsoWeekDay = getIsoWeekDay(firstDayOfYear);
    const zeroBasedFirstIsoWeekDay = getZeroBasedIsoWeekDay(firstDayOfYear);
  
    // If year begins with W52 or W53
    if (firstIsoWeekDay > 4) {
      days += 8 - firstIsoWeekDay; 
    // Else begins with W01
    } else {
      days -= zeroBasedFirstIsoWeekDay;
    }
    
    return new Date(year, 0, days);
  }


// test: 
const x = [
  {year: 2001, week: 10},
  {year: 2019, week: 7},
  {year: 2020, week: 5},
  {year: 2020, week: 1},
  {year: 2020, week: 12}, 
  {year: 2020, week: 2},
  {year: 2020, week: 40},
  {year: 2021, week: 4},
  {year: 2021, week: 3},
  {year: 2021, week: 2},
  {year: 2032, week: 1}
]

for (let i = 0; i < x.length; i++) {
  let date = weekToDate(x[i].year, x[i].week, 0);
  let d = new Date(date).toLocaleDateString('en-US', { 
    year: 'numeric',
    month: 'long',
    day: 'numeric' 
  })

  console.log(d);
}
Dorbn
  • 277
  • 4
  • 11
0

This is for getting the first monday of a week in the current year (ISO 8601):

function getFirstMondayOfWeek(weekNo) {
    var firstMonday = new Date(new Date().getFullYear(), 0, 4, 0, 0, 0, 0);

    while (firstMonday.getDay() != 1) {
        firstMonday.setDate(firstMonday.getDate() - 1);
    }
    if (1 <= weekNo && weekNo <= 52)
        return firstMonday.setDate(firstMonday.getDate() + 7 * (weekNo - 1));

    firstMonday.setDate(firstMonday.getDate() + 7 * (weekNo - 1));
    if (weekNo = 53 && firstMonday.getDate() >= 22 && firstMonday.getDate() <= 28)
        return firstMonday;
    return null;
}
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Up Gxy
  • 31
  • 3
0

I just created this one:

//Returns monday and saturday of the week
function getWeekRange(weekNo,YearNo) {
    let firstDayofYear = new Date(yearNo, 0, 1);

    if (firstDayofYear.getDay() > 4)  {
        let weekStart = new Date(yearNo, 0, 1 + (weekNo - 1) * 7 - firstDayofYear.getDay() + 8);
        let weekEnd = new Date(yearNo, 0, 1 + (weekNo - 1) * 7 - firstDayofYear.getDay() + 8 + 5);
        return { startDay: weekStart, endDay: weekEnd }
    }
    else {
        let weekStart = new Date(yearNo, 0, 1 + (weekNo - 1) * 7 - firstDayofYear.getDay() + 1);
        let weekEnd = new Date(yearNo, 0, 1 + (weekNo - 1) * 7 - firstDayofYear.getDay() + 1 + 5);
        return { startDay: weekStart, endDay: weekEnd }
    }
}
0

This is a short way

 function addWeeks(numOfWeeks, date = new Date()) {
  date.setDate(date.getDate() + numOfWeeks * 7); 
  return date;
 }

Ex: Today is 2022-08-02

addWeeks(1)

the result will be today + 7

Tue Aug 09 2022 21:36:08 GMT+0100 (GMT+02:00)

but you may want only date without all info

addWeeks(1).toISOString().split('T')[0]

the result will be: 2022-08-09

Rachid Loukili
  • 623
  • 6
  • 15
0

ISO weeks (https://en.wikipedia.org/wiki/ISO_week_date):

const y = 2023;
const jan1 = new Date(y, 0, 1);
const jan1Day = jan1.getDay();

const daysToMonday =  jan1Day === 1? 0 : jan1Day === 0? 1 :  8 - jan1Day

console.log('jan1', jan1)
console.log('jan1Day', jan1Day)
console.log('daysToMonday', daysToMonday)

// first Monday of the year
const firstMonday = daysToMonday === 0 ? jan1 : new Date(+jan1 + daysToMonday * 86400e3);

console.log('firstMonday', firstMonday)

// get monday of a specific week (20)
console.log('monday of week 20', new Date(+firstMonday + (20 - 1) * 7 * 86400e3))
// get sunday of a specific week (20)
console.log('sunday of week 20', new Date(+firstMonday + ((20 - 1) * 7 * 86400e3) + (86400e3 * 6) ))
mazz
  • 423
  • 1
  • 4
  • 11
0

The following function is adapted from https://en.wikipedia.org/wiki/ISO_week_date

It takes an ISO week date like the one you can retrieve from an input type="week" value (ie: 2023-W28) and returns you the date of that week's monday. It should be equal to valueAsDate of the same input.

It may be used as a polyfill in browser that doesn't support valueAsDate and will return an invalid date object for invalid values.


/** return date object for monday of given iso week number (\d\d\d\d-W\d\d) */
export const isoWeekDate = (isoWeek:string) => {
    // alogrythm adapted from https://en.wikipedia.org/wiki/ISO_week_date
    const [, Y, W] = isoWeek.match(/^(\d{4})-W(\d{2})$/) || [];
    if (!Y || !W || Number(W) > 53 || Number(W) < 1) {
        return new Date('x'); // Return an invalid date
    }
    const date = new Date(`${Y}-01-01T00:00Z`);
    const jan4th = new Date(`${Y}-01-04T00:00Z`);
    const jan4thDay = (jan4th.getDay() + 6) % 7;
    const ordinalDate = 1 + (Number(W)-1) * 7 - jan4thDay + 3;
    date.setUTCDate(ordinalDate);
    if (date.getUTCFullYear() > Number(Y)) {
        return new Date('x'); // Return an invalid date
    }
    return date
}

hope this will make someone's life easier in the future (probably me ).

malko
  • 2,292
  • 18
  • 26
-1

Current accepted answer is close but not entirely correct. Here is the correct function:

function weekToDate(year, week) {
    const days = 4 + 7 * (week - 1);
    const date = new Date(year, 0, days);
    return date;
}

This will yield a date that is guaranteed to be in the ISO week you asked for.

Then if you want a specific day in the week modify the date like so:

    const dayOfWeek = 1 // monday
    date.setDate(date.getDate() - date.getDay() + dayOfWeek) 

Where dayOfWeek is the day of the week you want to get the date of. (1-7, 1 = monday)

  • This results 2023-01-03T22:00:00.000Z when I enter weekToDate(2023, 1), which is far from correct. The new Date() probably takes my local timezone into account as well, which shouldn't be the case. – Joonas Vali Jan 09 '23 at 14:00
  • @JoonasVali. 2023-01-03T22:00:00.000Z is a date in week 1 of 2023. Maybe I didn't understand what your concern was? – Karl Blixt Jan 09 '23 at 23:40
  • Ok, maybe I misunderstood, I kind of expected that it would return the start date of the week, not just any date of the week. – Joonas Vali Jan 10 '23 at 14:13
  • then simply add date.setDate(date.getDate() - date.getDay() + 1) to the end of the function to always get monday. That's part two of my reply. Personally, If I wished to return a date in a week then I'd return thursday since it's in the middle of the week and thus the year of the returned date will always be the same as the year of the week. That's why I left that part outside the core issue at hand. – Karl Blixt Jan 10 '23 at 19:29