0

I need a JS function to get the last date of the month. as an example, I need to get the last Wednesday of this month.

I will pass Year, Month and day as a arguments.

getLastDayOfMonth('2022', '02', 'Wednesday');

function getLastDayOfMonth(year, month, day){

     // Output should be like this

       2022-02-23    

    (this is last Wednesday of the month, according to the arguments- Year, month and Day)
}
Niranga
  • 105
  • 10
  • Does it have to be the day name string? A number (0-6) would be easier to match against [Date.prototype.getDay()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay) – Phil Jan 19 '22 at 05:41
  • I recommend using a date library like [momentjs](https://momentjs.com) or [date-fns](https://date-fns.org) – knicholas Jan 19 '22 at 05:42
  • 1
    @knicholas stop recommending Moment.js. Even they don't recommend themselves these days – Phil Jan 19 '22 at 05:42
  • @knicholas Brother Do you know function for that? in the date-fns library. Currently, I'm using date-fns library. but I couldn't find a way to do that. – Niranga Jan 19 '22 at 05:45
  • @Niranga is this duplicated question of https://stackoverflow.com/questions/222309/calculate-last-day-of-month ? – nart Jan 19 '22 at 05:47
  • @nosnart OP wants the last nominated day-of-week in the month, so not quite – Phil Jan 19 '22 at 05:53

2 Answers2

1

Create a Date instance with the last day of the month then work backwards one day at a time until you match the day of the week you're after

const normaliseDay = day => day.trim().toLowerCase()
const dayIndex = new Map([
  ["sunday",    0],
  ["monday",    1],
  ["tuesday",   2],
  ["wednesday", 3],
  ["thursday",  4],
  ["friday",    5],
  ["saturday",  6],
])

const getLastDayOfMonth = (year, month, dow) => {
  const day = dayIndex.get(normaliseDay(dow))
  
  // init as last day of month
  const date = new Date(Date.UTC(parseFloat(year), parseFloat(month), 0))
  
  // work back one-day-at-a-time until we find the day of the week
  while (date.getDay() != day) {
    date.setDate(date.getDate() - 1)
  }
  
  return date
}

console.log(getLastDayOfMonth("2022", "02", "Wednesday"))

The numeric values are parsed as numbers so we don't run into problems with zero-padded octal numbers.

Phil
  • 157,677
  • 23
  • 242
  • 245
1

You can get the last day of the month then subtract the required number of days based on the difference between the end of month day and required day, e.g.

/* Return last instance of week day for given year and month
 * @param {number|string} year: 4 digit year
 * @param {number|string} month: calendar month number (1=Jan)
 * @param {string} day: English week day name, e.g. Sunday,
 *                      Sun, su, case insensitive
 * @returns {Date} date for last instance of day for given
 *                      year and month
 */
function getLastDayOfMonth(year, month, day) {
  // Convert day name to index
  let i = ['su','mo','tu','we','th','fr','sa'].indexOf(day.toLowerCase().slice(0,2));
  // Get end of month and eom day index
  let eom = new Date(year, month, 0);
  let eomDay = eom.getDay();
  // Subtract required number of days
  eom.setDate(eom.getDate() - eomDay + i - (i > eomDay? 7 : 0));
  return eom;
}

// Examples - last weekdays for Feb 2022
['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'].forEach(day => 
  console.log(day.slice(0,3) + ': ' + getLastDayOfMonth('2022', '02', day).toLocaleDateString('en-GB',{
    year:'numeric',
    month:'short',
    day:'numeric',
    weekday:'short'
  })
));

In the above:

new Date(year, month, 0)

leverages the fact that the month is calendar month whereas the date constructor months are 0 indexed, so the above sets the date to the zeroth day of March, which resolves to the last day in February.

The part:

eom.getDate() - eomDay + i - (i > eomDay? 7 : 0)

subtracts the eomDay index to get to the prior Sunday, then i adds days to get the required day. However, if that goes beyond the end of the month (i.e. i is greater than eomDay so adds more days that eomDay subtracts), it subtracts 7 days.

RobG
  • 142,382
  • 31
  • 172
  • 209