Skip to content

Instantly share code, notes, and snippets.

@markthiessen
Last active August 9, 2024 13:52
Show Gist options
  • Save markthiessen/3883242 to your computer and use it in GitHub Desktop.
Save markthiessen/3883242 to your computer and use it in GitHub Desktop.
JavaScript - get weeks in a month as array of start and end days
//note: month is 0 based, just like Dates in js
function getWeeksInMonth(year, month) {
const weeks = [],
firstDate = new Date(year, month, 1),
lastDate = new Date(year, month + 1, 0),
numDays = lastDate.getDate();
let dayOfWeekCounter = firstDate.getDay();
for (let date = 1; date <= numDays; date++) {
if (dayOfWeekCounter === 0 || weeks.length === 0) {
weeks.push([]);
}
weeks[weeks.length - 1].push(date);
dayOfWeekCounter = (dayOfWeekCounter + 1) % 7;
}
return weeks
.filter((w) => !!w.length)
.map((w) => ({
start: w[0],
end: w[w.length - 1],
dates: w,
}));
}
exports.getWeeksInMonth = getWeeksInMonth;
const getWeeksInMonth = require("./getWeeksInMonth").getWeeksInMonth;
describe("getWeeksInMonth", () => {
test("June 2019 (starts on Saturday)", () => {
const weeks = getWeeksInMonth(2019, 5);
expect(weeks.length).toBe(6);
expect(weeks[0].start).toBe(1);
expect(weeks[0].end).toBe(1);
});
test("Feb 2021 (starts on Monday)", () => {
const weeks = getWeeksInMonth(2021, 1);
expect(weeks.length).toBe(5);
expect(weeks[0].start).toBe(1);
expect(weeks[0].end).toBe(6);
expect(weeks[4].start).toBe(28);
expect(weeks[4].end).toBe(28);
});
test("Aug 2021 (starts on Sunday)", () => {
const weeks = getWeeksInMonth(2021, 7);
expect(weeks.length).toBe(5);
expect(weeks[0].start).toBe(1);
expect(weeks[0].end).toBe(7);
expect(weeks[4].start).toBe(29);
expect(weeks[4].end).toBe(31);
});
});
@itzikbenh
Copy link

If you want to support starting with Monday, I believe this should work.

function getWeeksStartAndEndInMonth(month, year, start) {
    let weeks = [],
        firstDate = new Date(year, month, 1),
        lastDate = new Date(year, month + 1, 0),
        numDays = lastDate.getDate();

    let start = 1;
    let end = 7 - firstDate.getDay();
    if (start === 'monday') {
        if (firstDate.getDay() === 0) {
            end = 1;
        } else {
            end = 7 - firstDate.getDay() + 1;
        }
    }
    while (start <= numDays) {
        weeks.push({start: start, end: end});
        start = end + 1;
        end = end + 7;
        end = start === 1 && end === 8 ? 1 : end;
        if (end > numDays) {
            end = numDays;
        }
    }
    return weeks;
}

@itzikbenh
Copy link

itzikbenh commented Oct 9, 2017

This one will allow you to start from any day of the week.

function endFirstWeek(firstDate, firstDay) {
    if (! firstDay) {
        return 7 - firstDate.getDay();
    }
    if (firstDate.getDay() < firstDay) {
        return firstDay - firstDate.getDay();
    } else {
        return 7 - firstDate.getDay() + firstDay;
    }
}

function getWeeksStartAndEndInMonth(month, year, start) {
    let weeks = [],
        firstDate = new Date(year, month, 1),
        lastDate = new Date(year, month + 1, 0),
        numDays = lastDate.getDate();

    let start = 1;
    let end = endFirstWeek(firstDate, 2);
    while (start <= numDays) {
        weeks.push({start: start, end: end});
        start = end + 1;
        end = end + 7;
        end = start === 1 && end === 8 ? 1 : end;
        if (end > numDays) {
            end = numDays;
        }
    }
    return weeks;
}

@Chriskuang
Copy link

thks

@leorcvargas
Copy link

Thank you! This are really useful for me. <3

@ghidhawidhekra
Copy link

ghidhawidhekra commented Feb 13, 2018

Thank you for the Share! Could you please add week number too? @itzikbenh

Copy link

ghost commented Apr 15, 2018

@itzikbenh solution worked out best.

@BorisTB
Copy link

BorisTB commented Jun 18, 2018

@itzikbenh why is there "start" in arguments and then you define it again with "let start = 1" ? Not sure how you made that work

@NerdGr8
Copy link

NerdGr8 commented Jul 11, 2018

function getWeeksStartAndEndInMonth(month, year, _start) {
    let monthNames = ["January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
        ],
        d = new Date();
    console.log("The current month is " + monthNames[d.getMonth()]);
    let weeks = [],
        firstDate = new Date(year, month, 1),
        lastDate = new Date(year, month + 1, 0),
        numDays = lastDate.getDate();
    var c = Date()
    let start = 1;
    let end = 7 - firstDate.getDay();
    if (_start == 'monday') {
        if (firstDate.getDay() === 0) {
            end = 1;
        } else {
            end = 7 - firstDate.getDay() + 1;
        }
    }
    while (start <= numDays) {
        var businessWeekEnd = end-2
        if(businessWeekEnd > 0){
            if(businessWeekEnd > start){
                weeks.push({start: start, end: businessWeekEnd});
            }
            else{
                //Check for last day else end date is within 5 days of the week.
                weeks.push({start: start, end: end});
            }
        }
        start = end + 1;
        end = end + 7;
        end = start === 1 && end === 8 ? 1 : end;
        if (end > numDays) {
            end = numDays;
        }
    }

    weeks.forEach(week => {
        var _s = parseInt(week.start, 10)+1,
            _e = parseInt(week.end,10)+1;
        console.log(new Date(year, month, _s).toJSON().slice(0,10).split('-').reverse().join('/') + " - " + new Date(year, month, _e).toJSON().slice(0,10).split('-').reverse().join('/'));
        console.log(((_e-_s)+1)*8)
    });
    return weeks;
}
console.table(getWeeksStartAndEndInMonth(6, 2018, 'monday'));

@anantl05
Copy link

Thanks a ton!

@kingqi
Copy link

kingqi commented Dec 3, 2018

Thanks a lot, here is some code to get full weeks ( like first week will be like '26-2'), also allow you to start from any day of the week.
Any suggestion will be appreciated

// _start is 0 based
getFullWeeksStartAndEndInMonth = (month, year, _start) => {
    let weeks = [],
      firstDate = new Date(year, month, 1),
      lastDate = new Date(year, month + 1, 0),
      numDays = lastDate.getDate()

    let start = 1
    let end = 7 - firstDate.getDay()
    if (firstDate.getDay() === _start) {
      end = 7
    } else {
      preMonthEndDay = new Date(year, month, 0)
      start = preMonthEndDay.getDate() + 1 - firstDate.getDay() + _start
      end = 7 - firstDate.getDay() + _start
      weeks.push({ start: start, end: end })
      start = end + 1
      end = end + 7
    }
    while (start <= numDays) {
      weeks.push({ start: start, end: end })
      start = end + 1
      end = end + 7
      if (end > numDays) {
        end = end - numDays + _start
        weeks.push({ start: start, end: end })
        break
      }
    }
    return weeks
  }

@abcx
Copy link

abcx commented Mar 15, 2019

This TypeScript function returns date ranges for all weeks in given month:

    getWeeksInMonth(year: number, month: number) {

        const weeks = [];
        const firstDay: Date = new Date(year, month, 1);
        const lastDay: Date = new Date(year, month + 1, 0);
        const daysInMonth: number = lastDay.getDate();
        let dayOfWeek: number = firstDay.getDay();
        let start: number;
        let end: number;

        for (let i = 1; i < daysInMonth + 1; i++) {

            if (dayOfWeek === 0 || i === 1) {
                start = i;
            }

            if (dayOfWeek === 6 || i === daysInMonth) {

                end = i;

                if (start !== end) {

                    weeks.push({
                        start: start,
                        end: end
                    });
                }
            }

            dayOfWeek = new Date(year, month, i).getDay();
        }

        return weeks;
    }

Usage:

getWeeksInMonth(2019, 2);

Result for March 2019:

0: {start: 1, end: 3}
1: {start: 4, end: 10}
2: {start: 11, end: 17}
3: {start: 18, end: 24}
4: {start: 25, end: 31}

@junreyd
Copy link

junreyd commented Jun 20, 2019

Very helpful.

@baj9032
Copy link

baj9032 commented Aug 17, 2019

Thank you very useful.

@infomed92
Copy link

Hi abcx,
your function is not bad BUT it is not working correctly when we put year=2018 and month=Avril or July.
For example, result for Avril 2018 :
0: {start: 2, end: 8}
1: {start: 9, end: 15}
2: {start: 16, end: 22}
3: {start: 23, end: 29}

@infomed92
Copy link

infomed92 commented Oct 25, 2019

We should have for Avril 2018 :
0: {start: 1, end: 1}
1: {start: 2, end: 8}
2: {start: 9, end: 15}
3: {start: 16, end: 22}
4: {start: 23, end: 29}
5: {start: 30, end: 30}

@panchihpeng
Copy link

I used dayjs to write it. dayjs
It works !

const getWeekMonth = (year, month) => {
  const firstDay = dayjs(`${year}-${month}`).startOf('month').format('d')

  let startDay
  if (firstDay === 1) {
    startDay = dayjs(`${year}-${month}`).format('YYYY-MM-DD')
  } else {
    const diffDays = (8 - firstDay) % 7
    startDay = dayjs(`${year}-${month}`).startOf('month').add(diffDays, 'days').format('YYYY-MM-DD')
  }

  const lastDay = dayjs(`${year}-${month}`).endOf('month').format('d')

  let endDay
  if (lastDay === 0) {
    endDay = dayjs(`${year}-${month}`).endOf('month').format('YYYY-MM-DD')
  } else {
    const lastDiffDays = 6 - lastDay
    endDay = dayjs(`${year}-${month}`).startOf('month').add(1, 'month').add(lastDiffDays, 'days').format('YYYY-MM-DD')
  }

  const weeks = (dayjs(endDay).diff(dayjs(startDay), 'days') + 1) / 7

  const weekList = []
  for (let i = 1; i <= weeks; i++) {
    weekList.push({
      weekName: `第${i}周`,
      num: i,
      startDay,
      endDay: dayjs(startDay).add(6, 'days').format('YYYY-MM-DD'),
      range: `${dayjs(startDay).format('MM-DD')}~${dayjs(startDay).add(6, 'days').format('MM-DD')}`
    })
    startDay = dayjs(startDay).add(7, 'days').format('YYYY-MM-DD')
  }
  return weekList
}

@gktgautam
Copy link

gktgautam commented Jan 19, 2020

If you want to support starting with Monday,
I believe this TypeScript function should work best.

getWeeksInMonth(year: number, month: number) { const daysName = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const weeks=[];      
const  lastDate = new Date(year, month + 1, 0); 

let start: number=0;
let end: number; 

for (let i = 1; i < lastDate.getDate()+1; i++) {         
  if (daysName[Number(new Date(year, month, i).getDay())] =="Sunday" || i == lastDate.getDate()) {
    end= i;
    weeks.push({
        start:start+1,
        end:end
      }); 
      start = i;           
   }
 }         
 console.log(weeks);  }`

@brunolkatz
Copy link

I make this for get array of weeks:

function getWeeksStartAndEndInMonth(_month: number, _year: number, returnDate: boolean = false) {
    const lastDay = new Date(_year, _month + 1, 0);
    let weeks: Array<{start: number, end: number}> = [];
    let _days = [];
    for (let _day = 1; _day <= lastDay.getDate(); _day++){
        let _thisDay = new Date(_year, _month, _day);
        _days.push(returnDate ? _thisDay : _day);
        if(_thisDay.getDay() === 6){
            weeks.push({start: _days[0], end: _days[_days.length-1]});
            _days = [];
        }else if(_thisDay.getDate() === lastDay.getDate()){
            weeks.push({start: _days[0], end: _days[_days.length-1]});
        }
    }
    return weeks;
}

for(let i = 0; i <= 11; i++){
    let _month = getWeeksStartAndEndInMonth(i,2020);
    console.log(_month);
}

@bedirhanyildirim
Copy link

bedirhanyildirim commented Nov 27, 2020

If the week starts with 'Monday' as index 1:

// note: month is in range 0-11
function getFullWeeksStartAndEndInMonth (month, year) {
    let weeks = [],
        firstDate = new Date(year, month, 1),
        lastDate = new Date(year, month + 1, 0),
        numDays = lastDate.getDate()

    let start = 1
    let end
    if (firstDate.getDay() === 1) {
        end = 7
    } else if (firstDate.getDay() === 0) {
        let preMonthEndDay = new Date(year, month, 0)
        start = preMonthEndDay.getDate() - 6 + 1
        end = 1
    } else {
        let preMonthEndDay = new Date(year, month, 0)
        start = preMonthEndDay.getDate() + 1 - firstDate.getDay() + 1
        end = 7 - firstDate.getDay() + 1
        weeks.push({
            start: start,
            end: end
        })
        start = end + 1
        end = end + 7
    }
    while (start <= numDays) {
        weeks.push({
            start: start,
            end: end
        });
        start = end + 1;
        end = end + 7;
        end = start === 1 && end === 8 ? 1 : end;
        if (end > numDays && start <= numDays) {
            end = end - numDays
            weeks.push({
                start: start,
                end: end
            })
            break
        }
    }
    return weeks
}

@Sagargalande
Copy link

Sagargalande commented Feb 1, 2021

This code will start first day of month

Week start day Monday and end day Sunday

Last week end is month end day

function getWeeksStartAndEndInMonth(month, year) {
  let weeks = [],
      firstDate = new Date(year, month, 1),
      lastDate = new Date(year, month , 0),
      numDays = lastDate.getDate();

   start = 1;
  let end = GetfirstWeekEnd(month,year).getDate();
  while (start <= numDays) {
      weeks.push({start: start, end: end});
      start = end + 1;
      end = end + 7;
      end = start === 1 && end === 8 ? 1 : end;
      if (end > numDays) {
          end = numDays;
      }
  }
  return weeks;
  }

 function GetfirstWeekEnd(month,year) {
      var firstDay= new Date(year + "-" + month + "-" + 1);
      var first = firstDay;
      const lastDay = new Date(year, month, 0);
      const daysInMonth = lastDay.getDate();
      let dayOfWeek = firstDay.getDay();
      var endday="";
      var startCount = dayOfWeek;
      if (startCount != 0) {
           endday = new Date( firstDay.setDate( firstDay.getDate() + (7-dayOfWeek)));
      }
      else {
          endday = new Date(firstDay.setDate( firstDay.getDate() + 1));

      }
      return endday;
  } 
  
  function endFirstWeek(firstDate, firstDay) {
  if (! firstDay) {
      return 7 - firstDate.getDay();
  }
  if (firstDate.getDay() < firstDay) {
      return firstDay - firstDate.getDay();
  } else {
      return 7 - firstDate.getDay() + firstDay;
  }
}

### ### ### ###

Input :
getWeeksStartAndEndInMonth(1, 2021)
here is output
0: {start: 1, end: 3}
1: {start: 4, end: 10}
2: {start: 11, end: 17}
3: {start: 18, end: 24}
4: {start: 25, end: 31}

@pereira-a
Copy link

If you want a function to return a month's week based on business days this shall work:

function getWeeksInMonth(year: number, month: number) {
        const weeks = [],
            firstDate = new Date(year, month, 1),
            lastDate = new Date(year, month + 1, 0),
            numDays = lastDate.getDate();
        
        let offset = 0;

        if(firstDate.getDay() === 0) offset = 1;
        else if(firstDate.getDay() === 6) offset = 2;

        let start = 1 + offset;
        let end: number;

        if(offset === 0) end = 5 - firstDate.getDay() + 1;
        else end = 5 - start + 1 + (offset * 2);

        while(start <= numDays) {
            weeks.push({start: start, end: end});
            start = end + 3;
            end = end + 7;
            end = start === 1 && end === 8 ? 1 : end;
            if(end > numDays) end = numDays;
        }

        return weeks;
}

Results for Oct 2020:
image

Results for Feb 2020:
image

Results for March 2020:
image

@suryavi
Copy link

suryavi commented Jul 19, 2022

getWeekOfMonth
Screenshot (219)

@dllsystem
Copy link

dllsystem commented Jan 24, 2024

/**

  • It takes a year and a month as arguments, and returns an array of objects, each object containing
  • the start and end dates of the week, and an array of all the dates in that week
  • @param year - The year of the month you want to get the weeks for.
  • @param month - The month you want to get the weeks for.
  • @returns An array of objects.
    */

function getWeeksInMonth(year, month) {
const weeks = []

let firstDate = new Date(year, month, 1)
let lastDate = new Date(year, month + 1, 0)
let numDays = lastDate.getDate()

let dayOfWeekCounter = firstDate.getDay()

for (let date = 1; date <= numDays; date++) {
if (dayOfWeekCounter === 0 || weeks.length === 0) {
weeks.push([])
}
weeks[weeks.length - 1].push(date)
dayOfWeekCounter = (dayOfWeekCounter + 1) % 7
}

/* This is to add the last week of the previous month to the first week of the current month. */
if (weeks[0].length < 7) {
const beforeIndex1 = addMonth(year, month - 1, 1)
const indexRefactor = [...beforeIndex1, ...weeks[0]]
weeks[0] = indexRefactor
}

/* This is to add the first week of the next month to the last week of the current month. */
if (weeks[weeks.length - 1].length < 7) {
const afterIndex1 = addMonth(year, month + 1, 0)
const indexRefactor = [...weeks[weeks.length - 1], ...afterIndex1]
weeks[weeks.length - 1] = indexRefactor
}

return weeks
.filter((w) => !!w.length)
.map((w) => ({
start: w[0],
end: w[w.length - 1],
dates: w,
}))
}

/**

  • It takes a year, month, and flag, and returns the first or last week of the month, depending on the flag
  • @param year - the year of the month you want to get
  • @param month - The month you want to get the first or last week of.
  • @param flag - 0 for first week, 1 for last week, 2 for all weeks
  • @returns An array of arrays.
    */

const addMonth = (year, month, flag) => {
const weeks = [],
firstDate = new Date(year, month, 1),
lastDate = new Date(year, month + 1, 0),
numDays = lastDate.getDate()

let dayOfWeekCounter = firstDate.getDay()
for (let date = 1; date <= numDays; date++) {
if (dayOfWeekCounter === 0 || weeks.length === 0) {
weeks.push([])
}
weeks[weeks.length - 1].push(date)
dayOfWeekCounter = (dayOfWeekCounter + 1) % 7
}
if (flag === 0) {
return weeks[0]
}
if (flag === 1) {
return weeks[weeks.length - 1]
}
return []
}

console.table(getWeeksInMonth(2024, 0))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment