Thank you so much for taking the time to read. I have a calendar that allows booking and selecting dates, but I need to disable specific weekdays, months, but also third friday or second tuesday for certain trips. So I have this functions that #Thierry J. helped me to clean up, but i need to join it to the last function (activate only third friday, or second tuesday, and so on).
var daysToDisable = [1, 4, 6];
var monthsToDisable = [9];
function disableSpecificWeekDays(date) {
var day = date.getDay();
if ($.inArray(day, daysToDisable) != -1) {
return [false];
}
var month = date.getMonth();
if ($.inArray(month, monthsToDisable) != -1) {
return [false];
}
return [true];
}
To activate only third friday for the selected months I have this function:
var day = date.getDay();
var date = date.getDate();
return [(day == 5 && date >= 15 && date <= 21), ''];
So I was wondering if is possible to have all those functions together for beforeShowDay, but with the ability to select the trips that will have those restrictions. The "days to disable", and "months to disable" functions are ready and work with this variables:
var daysToDisable = [1, 4, 6];
var monthsToDisable = [9];
And i'll like to have the possibility to disable in the same way the specific week days:
var specificdaysToDisable = []
Also if there is a much better possibility to code it, so i'll be able to deactivate third friday for one trip, second tuesday for a different one, then i'm open to suggestions.
Thank you in advance!
To know if is the third week instead of check the day is not between 14 and 22, you can write your own Date.prototype.getWeekOfMonth function to get the week number of the month and than use it to check the condition.
Code:
Date.prototype.getWeekOfMonth = function(exact) {
var month = this.getMonth()
, year = this.getFullYear()
, firstWeekday = new Date(year, month, 1).getDay()
, lastDateOfMonth = new Date(year, month + 1, 0).getDate()
, offsetDate = this.getDate() + firstWeekday - 1
, index = 1 // start index at 0 or 1, your choice
, weeksInMonth = index + Math.ceil((lastDateOfMonth + firstWeekday - 7) / 7)
, week = index + Math.floor(offsetDate / 7)
;
if (exact || week < 2 + index) return week;
return week === weeksInMonth ? index + (weeksInMonth -1 ) : week;
};
jQuery("#datepicker").datepicker({
beforeShowDay: disableSpecificWeekDaysandMonths,
});
var daysToDisable = [0, 2, 3, 4, 6];
var monthsToDisable = [1, 2];
var specificDaysToDisable = [5];
function disableSpecificWeekDaysandMonths(date) {
var day = date.getDay();
if ($.inArray(day, daysToDisable) != -1) {
return [false];
}
var month = date.getMonth();
if ($.inArray(month, monthsToDisable) != -1) {
return [false];
}
var date2 = date.getDate();
var inArray = $.inArray(day, specificDaysToDisable)
if (inArray != -1 && date.getWeekOfMonth()!=3) {
return [false];
}
return [true]
}
Demo: http://jsfiddle.net/IrvinDominin/yFtLP/11/
I consider this will be the final code, but also I'm open to suggestions as I'm not sure if it's syntax is correct or if there could be other ways to improve the code.
Also in Fiddle and with short version with inArray var.
jQuery("#datepicker").datepicker({
beforeShowDay: disableSpecificWeekDaysandMonths,
});
var daysToDisable = [0, 2, 3, 4, 6];
var monthsToDisable = [1, 2 ];
var specificDaysToDisable = [5];
function disableSpecificWeekDaysandMonths(date) {
var day = date.getDay();
if ($.inArray(day, daysToDisable) != -1) {
return [false];
}
var month = date.getMonth();
if ($.inArray(month, monthsToDisable) != -1) {
return [false];
}
var date2 = date.getDate();
if ($.inArray(day, specificDaysToDisable) != -1 && date2 <= 14 || $.inArray(day, specificDaysToDisable) != -1 && date2 >= 22 ) {
return [false];
}
return [true]
}
Related
I'm trying to test to make sure a date is valid in the sense that if someone enters 2/30/2011 then it should be wrong.
How can I do this with any date?
One simple way to validate a date string is to convert to a date object and test that, e.g.
// Expect input as d/m/y
function isValidDate(s) {
var bits = s.split('/');
var d = new Date(bits[2], bits[1] - 1, bits[0]);
return d && (d.getMonth() + 1) == bits[1];
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate(s))
})
When testing a Date this way, only the month needs to be tested since if the date is out of range, the month will change. Same if the month is out of range. Any year is valid.
You can also test the bits of the date string:
function isValidDate2(s) {
var bits = s.split('/');
var y = bits[2],
m = bits[1],
d = bits[0];
// Assume not leap year by default (note zero index for Jan)
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// If evenly divisible by 4 and not evenly divisible by 100,
// or is evenly divisible by 400, then a leap year
if ((!(y % 4) && y % 100) || !(y % 400)) {
daysInMonth[1] = 29;
}
return !(/\D/.test(String(d))) && d > 0 && d <= daysInMonth[--m]
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate2(s))
})
Does first function isValidDate(s) proposed by RobG will work for input string '1/2/'?
I think NOT, because the YEAR is not validated ;(
My proposition is to use improved version of this function:
//input in ISO format: yyyy-MM-dd
function DatePicker_IsValidDate(input) {
var bits = input.split('-');
var d = new Date(bits[0], bits[1] - 1, bits[2]);
return d.getFullYear() == bits[0] && (d.getMonth() + 1) == bits[1] && d.getDate() == Number(bits[2]);
}
I recommend to use moment.js. Only providing date to moment will validate it, no need to pass the dateFormat.
var date = moment("2016-10-19");
And then date.isValid() gives desired result.
Se post HERE
This solution does not address obvious date validations such as making sure date parts are integers or that date parts comply with obvious validation checks such as the day being greater than 0 and less than 32. This solution assumes that you already have all three date parts (year, month, day) and that each already passes obvious validations. Given these assumptions this method should work for simply checking if the date exists.
For example February 29, 2009 is not a real date but February 29, 2008 is. When you create a new Date object such as February 29, 2009 look what happens (Remember that months start at zero in JavaScript):
console.log(new Date(2009, 1, 29));
The above line outputs: Sun Mar 01 2009 00:00:00 GMT-0800 (PST)
Notice how the date simply gets rolled to the first day of the next month. Assuming you have the other, obvious validations in place, this information can be used to determine if a date is real with the following function (This function allows for non-zero based months for a more convenient input):
var isActualDate = function (month, day, year) {
var tempDate = new Date(year, --month, day);
return month === tempDate.getMonth();
};
This isn't a complete solution and doesn't take i18n into account but it could be made more robust.
var isDate_ = function(input) {
var status = false;
if (!input || input.length <= 0) {
status = false;
} else {
var result = new Date(input);
if (result == 'Invalid Date') {
status = false;
} else {
status = true;
}
}
return status;
}
this function returns bool value of whether the input given is a valid date or not. ex:
if(isDate_(var_date)) {
// statements if the date is valid
} else {
// statements if not valid
}
I just do a remake of RobG solution
var daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
var isLeap = new Date(theYear,1,29).getDate() == 29;
if (isLeap) {
daysInMonth[1] = 29;
}
return theDay <= daysInMonth[--theMonth]
This is ES6 (with let declaration).
function checkExistingDate(year, month, day){ // year, month and day should be numbers
// months are intended from 1 to 12
let months31 = [1,3,5,7,8,10,12]; // months with 31 days
let months30 = [4,6,9,11]; // months with 30 days
let months28 = [2]; // the only month with 28 days (29 if year isLeap)
let isLeap = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
let valid = (months31.indexOf(month)!==-1 && day <= 31) || (months30.indexOf(month)!==-1 && day <= 30) || (months28.indexOf(month)!==-1 && day <= 28) || (months28.indexOf(month)!==-1 && day <= 29 && isLeap);
return valid; // it returns true or false
}
In this case I've intended months from 1 to 12. If you prefer or use the 0-11 based model, you can just change the arrays with:
let months31 = [0,2,4,6,7,9,11];
let months30 = [3,5,8,10];
let months28 = [1];
If your date is in form dd/mm/yyyy than you can take off day, month and year function parameters, and do this to retrieve them:
let arrayWithDayMonthYear = myDateInString.split('/');
let year = parseInt(arrayWithDayMonthYear[2]);
let month = parseInt(arrayWithDayMonthYear[1]);
let day = parseInt(arrayWithDayMonthYear[0]);
My function returns true if is a valid date otherwise returns false :D
function isDate (day, month, year){
if(day == 0 ){
return false;
}
switch(month){
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if(day > 31)
return false;
return true;
case 2:
if (year % 4 == 0)
if(day > 29){
return false;
}
else{
return true;
}
if(day > 28){
return false;
}
return true;
case 4: case 6: case 9: case 11:
if(day > 30){
return false;
}
return true;
default:
return false;
}
}
console.log(isDate(30, 5, 2017));
console.log(isDate(29, 2, 2016));
console.log(isDate(29, 2, 2015));
It's unfortunate that it seems JavaScript has no simple way to validate a date string to these days. This is the simplest way I can think of to parse dates in the format "m/d/yyyy" in modern browsers (that's why it doesn't specify the radix to parseInt, since it should be 10 since ES5):
const dateValidationRegex = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
function isValidDate(strDate) {
if (!dateValidationRegex.test(strDate)) return false;
const [m, d, y] = strDate.split('/').map(n => parseInt(n));
return m === new Date(y, m - 1, d).getMonth() + 1;
}
['10/30/2000abc', '10/30/2000', '1/1/1900', '02/30/2000', '1/1/1/4'].forEach(d => {
console.log(d, isValidDate(d));
});
Hi Please find the answer below.this is done by validating the date newly created
var year=2019;
var month=2;
var date=31;
var d = new Date(year, month - 1, date);
if (d.getFullYear() != year
|| d.getMonth() != (month - 1)
|| d.getDate() != date) {
alert("invalid date");
return false;
}
function isValidDate(year, month, day) {
var d = new Date(year, month - 1, day, 0, 0, 0, 0);
return (!isNaN(d) && (d.getDate() == day && d.getMonth() + 1 == month && d.getYear() == year));
}
I'm trying to test to make sure a date is valid in the sense that if someone enters 2/30/2011 then it should be wrong.
How can I do this with any date?
One simple way to validate a date string is to convert to a date object and test that, e.g.
// Expect input as d/m/y
function isValidDate(s) {
var bits = s.split('/');
var d = new Date(bits[2], bits[1] - 1, bits[0]);
return d && (d.getMonth() + 1) == bits[1];
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate(s))
})
When testing a Date this way, only the month needs to be tested since if the date is out of range, the month will change. Same if the month is out of range. Any year is valid.
You can also test the bits of the date string:
function isValidDate2(s) {
var bits = s.split('/');
var y = bits[2],
m = bits[1],
d = bits[0];
// Assume not leap year by default (note zero index for Jan)
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// If evenly divisible by 4 and not evenly divisible by 100,
// or is evenly divisible by 400, then a leap year
if ((!(y % 4) && y % 100) || !(y % 400)) {
daysInMonth[1] = 29;
}
return !(/\D/.test(String(d))) && d > 0 && d <= daysInMonth[--m]
}
['0/10/2017','29/2/2016','01/02'].forEach(function(s) {
console.log(s + ' : ' + isValidDate2(s))
})
Does first function isValidDate(s) proposed by RobG will work for input string '1/2/'?
I think NOT, because the YEAR is not validated ;(
My proposition is to use improved version of this function:
//input in ISO format: yyyy-MM-dd
function DatePicker_IsValidDate(input) {
var bits = input.split('-');
var d = new Date(bits[0], bits[1] - 1, bits[2]);
return d.getFullYear() == bits[0] && (d.getMonth() + 1) == bits[1] && d.getDate() == Number(bits[2]);
}
I recommend to use moment.js. Only providing date to moment will validate it, no need to pass the dateFormat.
var date = moment("2016-10-19");
And then date.isValid() gives desired result.
Se post HERE
This solution does not address obvious date validations such as making sure date parts are integers or that date parts comply with obvious validation checks such as the day being greater than 0 and less than 32. This solution assumes that you already have all three date parts (year, month, day) and that each already passes obvious validations. Given these assumptions this method should work for simply checking if the date exists.
For example February 29, 2009 is not a real date but February 29, 2008 is. When you create a new Date object such as February 29, 2009 look what happens (Remember that months start at zero in JavaScript):
console.log(new Date(2009, 1, 29));
The above line outputs: Sun Mar 01 2009 00:00:00 GMT-0800 (PST)
Notice how the date simply gets rolled to the first day of the next month. Assuming you have the other, obvious validations in place, this information can be used to determine if a date is real with the following function (This function allows for non-zero based months for a more convenient input):
var isActualDate = function (month, day, year) {
var tempDate = new Date(year, --month, day);
return month === tempDate.getMonth();
};
This isn't a complete solution and doesn't take i18n into account but it could be made more robust.
var isDate_ = function(input) {
var status = false;
if (!input || input.length <= 0) {
status = false;
} else {
var result = new Date(input);
if (result == 'Invalid Date') {
status = false;
} else {
status = true;
}
}
return status;
}
this function returns bool value of whether the input given is a valid date or not. ex:
if(isDate_(var_date)) {
// statements if the date is valid
} else {
// statements if not valid
}
I just do a remake of RobG solution
var daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
var isLeap = new Date(theYear,1,29).getDate() == 29;
if (isLeap) {
daysInMonth[1] = 29;
}
return theDay <= daysInMonth[--theMonth]
This is ES6 (with let declaration).
function checkExistingDate(year, month, day){ // year, month and day should be numbers
// months are intended from 1 to 12
let months31 = [1,3,5,7,8,10,12]; // months with 31 days
let months30 = [4,6,9,11]; // months with 30 days
let months28 = [2]; // the only month with 28 days (29 if year isLeap)
let isLeap = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
let valid = (months31.indexOf(month)!==-1 && day <= 31) || (months30.indexOf(month)!==-1 && day <= 30) || (months28.indexOf(month)!==-1 && day <= 28) || (months28.indexOf(month)!==-1 && day <= 29 && isLeap);
return valid; // it returns true or false
}
In this case I've intended months from 1 to 12. If you prefer or use the 0-11 based model, you can just change the arrays with:
let months31 = [0,2,4,6,7,9,11];
let months30 = [3,5,8,10];
let months28 = [1];
If your date is in form dd/mm/yyyy than you can take off day, month and year function parameters, and do this to retrieve them:
let arrayWithDayMonthYear = myDateInString.split('/');
let year = parseInt(arrayWithDayMonthYear[2]);
let month = parseInt(arrayWithDayMonthYear[1]);
let day = parseInt(arrayWithDayMonthYear[0]);
My function returns true if is a valid date otherwise returns false :D
function isDate (day, month, year){
if(day == 0 ){
return false;
}
switch(month){
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
if(day > 31)
return false;
return true;
case 2:
if (year % 4 == 0)
if(day > 29){
return false;
}
else{
return true;
}
if(day > 28){
return false;
}
return true;
case 4: case 6: case 9: case 11:
if(day > 30){
return false;
}
return true;
default:
return false;
}
}
console.log(isDate(30, 5, 2017));
console.log(isDate(29, 2, 2016));
console.log(isDate(29, 2, 2015));
It's unfortunate that it seems JavaScript has no simple way to validate a date string to these days. This is the simplest way I can think of to parse dates in the format "m/d/yyyy" in modern browsers (that's why it doesn't specify the radix to parseInt, since it should be 10 since ES5):
const dateValidationRegex = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
function isValidDate(strDate) {
if (!dateValidationRegex.test(strDate)) return false;
const [m, d, y] = strDate.split('/').map(n => parseInt(n));
return m === new Date(y, m - 1, d).getMonth() + 1;
}
['10/30/2000abc', '10/30/2000', '1/1/1900', '02/30/2000', '1/1/1/4'].forEach(d => {
console.log(d, isValidDate(d));
});
Hi Please find the answer below.this is done by validating the date newly created
var year=2019;
var month=2;
var date=31;
var d = new Date(year, month - 1, date);
if (d.getFullYear() != year
|| d.getMonth() != (month - 1)
|| d.getDate() != date) {
alert("invalid date");
return false;
}
function isValidDate(year, month, day) {
var d = new Date(year, month - 1, day, 0, 0, 0, 0);
return (!isNaN(d) && (d.getDate() == day && d.getMonth() + 1 == month && d.getYear() == year));
}
I would like to limit users to selecting only the first and third Monday of each month. We have a volunteer intake only on these days, so I want to limit incorrect date selections as much as possible.
I'm not a js coder, but have managed to adapt some code I found online to allow the first or third Monday of each month, but I can't work out how to allow both of them.
Here's the code I have for the first Monday:
var firstMonday = new Date(date);
var mondays=0;
firstMonday.setDate(1);
while (mondays < 1) {
firstMonday.setDate(firstMonday.getDate() + 1);
if (firstMonday.getDay() == 1) {
mondays++;
}
}
var result = date.getDate() != firstMonday.getDate();
I think this is what you are asking. Credit to jabclab for the getMondays() function.
// test: first monday of this month
// result: true
//var dates = [new Date(2017,8,4)];
// test: third monday of this month
// result: true
//var dates = [new Date(2017,8,18)];
// test: first and third monday of this month
// result: true
var dates = [new Date(2017,8,4), new Date(2017,8,18)];
// test: first monday, third monday, and random day from this month
// result: false
//var dates = [new Date(2017,8,4), new Date(2017,8,18), new Date(2017,8,22)];
alert(validate(dates));
function validate(dates) {
var valid = true;
var mondays = getMondays();
var firstMonday = mondays[0].setHours(0,0,0,0);
var thirdMonday = mondays[2].setHours(0,0,0,0);
if (dates && dates.length > 0) {
for (var i = 0; i < dates.length; i++) {
// Zero out time so only year, month, and day is compared
var d = dates[i].setHours(0,0,0,0);
if (d != firstMonday && d != thirdMonday) {
return false;
}
}
}
else {
valid = false;
}
return valid;
}
function getMondays() {
var d = new Date(),
month = d.getMonth(),
mondays = [];
d.setDate(1);
// Get the first Monday in the month
while (d.getDay() !== 1) {
d.setDate(d.getDate() + 1);
}
// Get all the other Mondays in the month
while (d.getMonth() === month) {
mondays.push(new Date(d.getTime()));
d.setDate(d.getDate() + 7);
}
return mondays;
}
Thanks, but I'm not sure if the above works or not as I was looking for a js code answer - I'll leave that for someone else to work out.
...which I've found in the meantime. Many thanks to Hugh at Fabrik for the following:
var thisdate = new Date(date);
thisdate.setHours(0,0,0,0);
var day = 1; // monday
var nth = 1; // first
var first = new Date(thisdate.getFullYear(), thisdate.getMonth(), 1),
add = (day - first.getDay() + 7) % 7 + (nth - 1) * 7;
first.setDate(1 + add);
nth = 3; // third
var third = new Date(thisdate.getFullYear(), thisdate.getMonth(), 1),
add = (day - third.getDay() + 7) % 7 + (nth - 1) * 7;
third.setDate(1 + add);
//console.log(thisdate + ', ' + first + ', ' + third);
var result = (first.getTime() !== thisdate.getTime()) && (third.getTime() !== thisdate.getTime());
Wondering if anyone has a solution for checking if a weekend exist between two dates and its range.
var date1 = 'Apr 10, 2014';
var date2 = 'Apr 14, 2014';
funck isWeekend(date1,date2){
//do function
return isWeekend;
}
Thank you in advance.
EDIT Adding what I've got so far. Check the two days.
function isWeekend(date1,date2){
//do function
if(date1.getDay() == 6 || date1.getDay() == 0){
return isWeekend;
console.log("weekend")
}
if(date2.getDay() == 6 || date2.getDay() == 0){
return isWeekend;
console.log("weekend")
}
}
Easiest would be to just iterate over the dates and return if any of the days are 6 (Saturday) or 0 (Sunday)
Demo: http://jsfiddle.net/abhitalks/xtD5V/1/
Code:
function isWeekend(date1, date2) {
var d1 = new Date(date1),
d2 = new Date(date2),
isWeekend = false;
while (d1 < d2) {
var day = d1.getDay();
isWeekend = (day === 6) || (day === 0);
if (isWeekend) { return true; } // return immediately if weekend found
d1.setDate(d1.getDate() + 1);
}
return false;
}
If you want to check if the whole weekend exists between the two dates, then change the code slightly:
Demo 2: http://jsfiddle.net/abhitalks/xtD5V/2/
Code:
function isFullWeekend(date1, date2) {
var d1 = new Date(date1),
d2 = new Date(date2);
while (d1 < d2) {
var day = d1.getDay();
if ((day === 6) || (day === 0)) {
var nextDate = d1; // if one weekend is found, check the next date
nextDate.setDate(d1.getDate() + 1); // set the next date
var nextDay = nextDate.getDay(); // get the next day
if ((nextDay === 6) || (nextDay === 0)) {
return true; // if next day is also a weekend, return true
}
}
d1.setDate(d1.getDate() + 1);
}
return false;
}
You are only checking if the first or second date is a weekend day.
Loop from the first to the second date, returning true only if one of the days in between falls on a weekend-day:
function isWeekend(date1,date2){
var date1 = new Date(date1), date2 = new Date(date2);
//Your second code snippet implies that you are passing date objects
//to the function, which differs from the first. If it's the second,
//just miss out creating new date objects.
while(date1 < date2){
var dayNo = date1.getDay();
date1.setDate(date1.getDate()+1)
if(!dayNo || dayNo == 6){
return true;
}
}
}
JSFiddle
Here's what I'd suggest to test if a weekend day falls within the range of two dates (which I think is what you were asking):
function containsWeekend(d1, d2)
{
// note: I'm assuming d2 is later than d1 and that both d1 and d2 are actually dates
// you might want to add code to check those conditions
var interval = (d2 - d1) / (1000 * 60 * 60 * 24); // convert to days
if (interval > 5) {
return true; // must contain a weekend day
}
var day1 = d1.getDay();
var day2 = d2.getDay();
return !(day1 > 0 && day2 < 6 && day2 > day1);
}
fiddle
If you need to check if a whole weekend exists within the range, then it's only slightly more complicated.
It doesn't really make sense to pass in two dates, especially when they are 4 days apart. Here is one that only uses one day which makes much more sense IMHO:
var date1 = 'Apr 10, 2014';
function isWeekend(date1){
var aDate1 = new Date(date1);
var dayOfWeek = aDate1.getDay();
return ((dayOfWeek == 0) || (dayOfWeek == 6));
}
I guess this is the one what #MattBurland sugested for doing it without a loop
function isWeekend(start,end){
start = new Date(start);
if (start.getDay() == 0 || start.getDay() == 6) return true;
end = new Date(end);
var day_diff = (end - start) / (1000 * 60 * 60 * 24);
var end_day = start.getDay() + day_diff;
if (end_day > 5) return true;
return false;
}
FIDDLE
Whithout loops, considering "sunday" first day of week (0):
Check the first date day of week, if is weekend day return true.
SUM "day of the week" of the first day of the range and the number of days in the lap.
If sum>5 return true
Use Date.getDay() to tell if it is a weekend.
if(tempDate.getDay()==6 || tempDate.getDay()==0)
Check this working sample:
http://jsfiddle.net/danyu/EKP6H/2/
This will list out all weekends in date span.
Modify it to adapt to requirements.
Good luck.
How could I calculate the last friday of this month using the momentjs api?
Correct answer to this question:
var lastFriday = function () {
var lastDay = moment().endOf('month');
if (lastDay.day() >= 5)
var sub = lastDay.day() - 5;
else
var sub = lastDay.day() + 2;
return lastDay.subtract(sub, 'days');
}
The previous answer returns the next to last friday if the last day of the month is friday.
Given a moment in the month you want the last Friday for:
var lastFridayForMonth = function (monthMoment) {
var lastDay = monthMoment.endOf('month').startOf('day');
switch (lastDay.day()) {
case 6:
return lastDay.subtract(1, 'days');
default:
return lastDay.subtract(lastDay.day() + 2, 'days');
}
},
E.g.
// returns moment('2014-03-28 00:00:00');
lastFridayForMonth(moment('2014-03-14));
Sorry guys but I tested previous answers and all of them are wrong.
Check all of them for
moment([2017,2])
And you will find that the result is incorrect.
I wrote this solution which is working so far:
let date = moment([2017,2]).endOf('month');
while (date.day() !== 5) {
date.subtract(1,'days')
}
return date;
Shorter answer :
var lastFridayForMonth = function (monthMoment) {
let lastDay = monthMoment.endOf('month').endOf('day');
return lastDay.subtract((lastDay.day() + 2) % 7, 'days');
}
I tried testing multiple months and for few months above answer by #afternoon did not work. Below is the test code.(one such test is for Aug 2018)
var moment = require('moment')
var affirm = require("affirm.js")
var cc = moment(Date.now())
for (var i = 0; i < 100000; i++) {
lastFridayForMonth(cc)
var nextWeek = moment(cc).add(7, 'days')
console.log(cc.format("ddd DD MMM YYYY"), nextWeek.format('MMM'))
affirm((cc.month() - nextWeek.month()) === -1 || (cc.month() - nextWeek.month()) === 11, "1 month gap is not found")
affirm(cc.day() === 5, "its not friday")
cc.add(1, "months")
}
I have put another solution
function lastFridayForMonth(monthMoment) {
var month = monthMoment.month()
monthMoment.endOf("month").startOf("isoweek").add(4, "days")
if (monthMoment.month() !== month) monthMoment.subtract(7, "days")
}