What's the best way to get the previous business day's date with moment.js? A business day is Monday through Friday.
Some expectations:
If today is Satuday, Sunday or Monday, return last Friday's date
If today is Tuesday, return last Monday's date (yesterday)
function getPreviousWorkday(){
let workday = moment();
let day = workday.day();
let diff = 1; // returns yesterday
if (day == 0 || day == 1){ // is Sunday or Monday
diff = day + 2; // returns Friday
}
return workday.subtract(diff, 'days');
}
Updated Approach (without looping)
You could actually take advantage of the day() function that would allow you to set the current day of the week in moment.js to find the previous Friday based on certain days :
function getPreviousWorkday(){
// Based on the current day, handle accordingly
switch(moment().day())
{
// If it is Monday (1),Saturday(6), or Sunday (0), Get the previous Friday (5)
// and ensure we are on the previous week
case 0:
case 1:
case 6:
return moment().subtract(6,'days').day(5);
// If it any other weekend, just return the previous day
default:
return moment().day(today - 1);
}
}
which can be seen here and demonstrated below :
Looping Approach
You could simply subtract days from your current moment instance via the subtract() function from the current day until you reached a non-weekend day:
function getPreviousWorkday(){
// Get today
var today = new moment().subtract(-1,'days');;
// If today isn't a weekend, continue iterating back until you hit a non-weekend
while([0,6].indexOf(today.day()) !== -1){
today = today.subtract(1, 'days');
}
// Return the non-weekend day
return today;
}
You can see an example of this in action here and demonstrated below :
There is a npm module for that!
https://github.com/kalmecak/moment-business-days
From documentation:
prevBusinessDay() : Will retrieve the previous business date as moment date object:
//Previous busines day of Monday 02-02-2015
moment('02-02-2015', 'DD-MM-YYYY').prevBusinessDay()._d // Fri Jan 30 2015 00:00:00 GMT-0600 (CST)
//Previous busines day of Tuesday 03-02-2015
moment('03-02-2015', 'DD-MM-YYYY').prevBusinessDay()._d //Mon Feb 02 2015 00:00:00 GMT-0600 (CST)
P.S: Important node. Why to use dependency? If all you need is prev business day - no reason to use 3-d party lib. But for real application all that stuff will be useful for more complex operations like importing dates, formatting and calculations based on calendars, holidays, etc.
function getPreviousWorkday() {
return [1, 2, 3, 4, 5].indexOf(moment().subtract(1, 'day').day()) > -1 ?
moment().subtract(1, 'day') : moment(moment().day(-2));
}
If the previous day is a weekday, return the previous day / weekday. Otherwise return the previous Friday since, if the previous day is a Saturday or Sunday it should return the previous Friday.
If you need to check only for Saturday or Sunday, this snippet can be used. I'm getting last day of month first then checking for business day (so basically last business day of a month)
getLastDayofMonth() {
let date = moment(this.selectedDate).endOf("month").format("MM-DD-YYYY");
// console.log(moment(date).day());
// check if last day of selected month is Saturday or Sunday, assign last friday if true
if (moment(date).day() === 0 || moment(date).day() === 6)
this.selectedDate = moment(date)
.subtract(6, "days")
.day(5)
.format("MM-DD-YYYY");
else this.selectedDate = date;
},
Related
Im trying to get the first day of first week by given day
Correct results :
2017 = 2 Jan (Monday)
2016 = 4 Jan (Monday)
2015 = 1 Jan (Thursday)
2014 = 1 Jan (Wednesday)
2013 = 1 Jan (Tuesday)
I can get the first day of the year by :
moment().year(year).startOf('year') // All result is 1. jan XXXX
Then I tried : (correct)
moment().day(1).year(2017).week(1) // 2 Jan (Monday) (correct)
But when changed to 2016 : (wrong)
moment().day(1).year(2016).week(1) // 10 Jan (Sunday) (wrong)
Any know how to get correct results ? (Im open for pure JS date() also)
PS: Week number is based in Norway
Playground : https://jsfiddle.net/6sar7eb4/
There is no need to use loop, you can simply test if the week number is not 1 using week() that gives localized output
The output of moment#week will depend on the locale for that moment.
You have to set the locale to moment using locale() method to get start of week locale aware. If you have to show result in english you can change locale locally.
Here a working sample:
function getFirstDayOfFirstWeekByYear( year ) {
// Create moment object for the first day of the given year
let func = moment({year:year})
// Check if 1st of January is in the first week of the year
if( func.week() !== 1 ){
// If not, add a week to the first day of the current week
func.startOf('week').add(1, 'week');
}
// Return result using english locale
return func.locale('en').format('D. MMMM YYYY (dddd)')
}
// Set Norwegian Bokmål locale globally
moment.locale('nb');
// Tester
[2017, 2016, 2015, 2014, 2013].forEach(function ( year ) {
let s = '<li>' + getFirstDayOfFirstWeekByYear( year ) + '</li>'
document.getElementsByTagName('BODY')[0].innerHTML += s
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.min.js"></script>
Anyway if your happy to do it within a loop this works
function getFirstDayOfFirstWeekByYear( year ){
let D = 1;
x = 0;
while(x !== 1){
x = moment(`${year}-01-${D}`).isoWeek();
if(x === 1 ){
return moment(`${year}-01-${D}`).format('D. MMMM YYYY (dddd)')
}
D++;
};
}
results
2. January 2017 (Monday)
4. January 2016 (Monday)
1. January 2015 (Thursday)
1. January 2014 (Wednesday)
1. January 2013 (Tuesday)
Im trying to get the first day of first week by given day
Using moment.js to get the first day of the first week of the year based on the ISO 8601 scheme, you can just use the first day of the first week of the year since the ISO week starts on Monday:
// Return a moment.js object for the first weekday of the first week
// of the year using ISO 8601 scheme
function firstDay(year) {
return moment(year + '011', 'GGGGWWE');
}
// Examples
['2015', '2016', '2017', '2018', '2019', '2020']
.forEach(function(year) {
console.log('ISO First day of ' + year + ': ' +
firstDay(year).format('dddd D MMMM, YYYY'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
However you seem to not want to use the ISO scheme, so if you just want to get the first day of the year that isn't a Saturday or Sunday (i.e. ignore the ISO 8601 scheme), you can do (without moment.js):
// Return Date for first day of year that is one of
// Monday to Friday
function firstDay(year) {
var d = new Date(year, 0, 1);
var day = d.getDay();
d.setDate(d.getDate() + (day%6? 0 : (++day%4)));
return d;
}
// Examples
['2015', '2016', '2017', '2018', '2019', '2020']
.forEach(function(year) {
console.log('First weekday of ' + year + ': ' + firstDay(year).toString());
});
Discussion
There are many different schemes for first day of the week and first day of the year. A commonly used scheme is ISO 8601, where the first day of the week is Monday and the first week of the year is the one in which the first Thursday appears (or the first that contains at least 4 days of the week, it's the same result).
According to ISO 8601 rules, the first day of the first week of 2019 is Monday 31 December, 2018.
If you decide to support different schemes (e.g. in Saudi Arabia the week starts on Saturday and ends on Friday, with work days Saturday to Wednesday and in the US a week is typically Sunday to Saturday with work days Monday to Friday), then you should clearly state which scheme you support and not simply assume a scheme based on the language the user has chosen. Schemes may also be based on other cultural factors such as religion, so are not necessarily region or language-based.
Which scheme should be used for an English person in Saudi Arabia? An Islamic person in Bhutan? In Saudi the official language for commerce is French, but most international discussion is in English, while the national language is Arabic. But they use the Hijri calendar, which does not align with the Georgian calendar commonly used elsewhere and is not defined by language but by religion.
There may also be differences even in the same place, with departments of the same government choosing different schemes so even locale (in the correct meaning of the term) is not a definitive indicator of which scheme to use.
If you decide to support different schemes, far better to adopt a standard scheme (like ISO 8601) and let the user change it to the one they prefer if they wish (and which the preferences in my computer and calendar application allow me to do).
I am trying to make a function that can check if a given date is in a specified week ago.
For example, if the input is <1, date object>, then it asks, if the given date is from last week. If the input is <2, date object>, then it asks if the given date is from 2 weeks ago, etc.. (0 is for current week).
Week is Sun-Sat.
this.isOnSpecifiedWeekAgo = function(weeks_ago, inputDate) {
return false;
};
But I don't want to use any libraries, and also I am not sure how to change the week of a date object. Does anyone know how to begin?
Thanks
If you want to find out a date that was a week ago, you can simply subtract 7 days from the current date:
var weekAgo = new Date();
weekAgo.setDate(weekAgo.getDate() - 7);
console.log(weekAgo.toLocaleString());
If you want to find out if a date is in a specific week, you'll need to:
Work out the start date for that week
Work out the end date for that week
See if the date is on or after the start and on or before the end
Since your weeks are Sunday to Saturday, you can get the first day of the week from:
var weekStart = new Date();
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
console.log(weekStart.toLocaleString());
The time should be zeroed, then a new date created for 7 days later. That will be midnight at the start of the following Sunday, which is identical to midnight at the end of the following Saturday. So a function might look like:
function wasWeeksAgo(weeksAgo, date) {
// Create a date
var weekStart = new Date();
// Set time to 00:00:00
weekStart.setHours(0,0,0,0);
// Set to previous Sunday
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
// Set to Sunday on weeksAgo
weekStart.setDate(weekStart.getDate() - 7*weeksAgo)
// Create date for following Saturday at 24:00:00
var weekEnd = new Date(+weekStart);
weekEnd.setDate(weekEnd.getDate() + 7);
// See if date is in that week
return date >= weekStart && date <= weekEnd;
}
// Test if dates in week before today (1 Nov 2016)
// 1 Oct 24 Oct
[new Date(2016,9,1), new Date(2016,9,24)].forEach(function(date) {
console.log(date.toLocaleString() + ' ' + wasWeeksAgo(1, date));
});
Use moment.js http://momentjs.com/docs/#/manipulating/subtract/
We use it a lot and its a great lib.
I have this code:
var nextDate = new Date("2016 01 31");
nextDate.setMonth(nextDate.getMonth() + 1);
I'm expecting the result to be Feb 28 2016, but it shows Mar 02 2016 instead.
Why? Is there any solution for it?
There is only 29 day in February, therefore, February 31 February will translate to Mars 2.
You need to update the days in your date object to the last day of that month. You can get the last day of the month by specifying a function that sets the date to 0:
function daysInMonth(month,year) {
return new Date(year, month, 0).getDate();
}
This is because February has 29 days, and when you set new month from January, which has 31 day, to February then the difference of the days are transferred to another month.
Easy way to do it is just create new Date instance.
You might need to implement some logic to get corresponding dates right
Possible work around with a helper function: after setMonth, check if the results doesn't contain a month equal to the expected month and if so, use setDate(0), which sets the date to last day of the previous month. e.g.
Date.prototype.addMonths = function(months){
var m = this.getMonth() + (months || 1);
this.setMonth(m);
if(this.getMonth() !== (m % 11)) //11: month is 0 based
this.setDate(0);
}
var nextDate = new Date("2016 01 31");
nextDate.addMonths(1);
document.writeln(nextDate);
months || 1 only is meant to have a default value if no month was submitted. m % 11 is needed in case of year transitions. 11 and not 12 because javascripts month (and thus getMonth) is 0 based.
I seem to have a bit of a problem getting the previous Monday given a particular date. I'm trying to use Moment js for the task. Obviously, I can do it by hand, but found it curious that I couldn't get it to work using the example in the moment.js documentation on their website: http://momentjs.com/docs/#/get-set/day/.
I was trying something like:
moment([2013, 08, 15, 15, 20]).day(-1).format('ddd, MMM DD')
which results in the 'two days ago' date, that being September 13 instead of the expected September 9th.
Does anybody have a clue here? Thanks.
Here is how it works:
moment().day(1) // this monday
moment().day(-6) // last monday, think of it as this monday - 7 days = 1 - 7 = -6
Same applies in other direction:
moment().day(8) // next monday, or this monday + 7 days = 1 + 7 = 8
Your code moment().day(-1) can be explained as this Sunday - 1 day = 0 - 1 = -1
or this Saturday - 7 days = 6 - 7 = -1
The accepted answer only works if you already know whether the day in question is in this week or next week. What if you don't know? You simply need the next available Thursday following some arbitrary date?
First, you want to know if the day in question is smaller or bigger than the day you want. If it's bigger, you want to use the next week. If it's smaller, you can use the same week's Monday or Thursday.
const dayINeed = 4; // for Thursday
if (moment().isoWeekday() <= dayINeed) {
return moment().isoWeekday(dayINeed);
} else...
If we're past the day we want already (if for instance, our Moment is a Friday, and we want the next available Thursday), then you want a solution that will give you "the Thursday of the week following our moment", regardless of what day our moment is, without any imperative adding/subtracting. In a nutshell, you want to first go into the next week, using moment().add(1, 'weeks'). Once you're in the following week, you can select any day of that week you want, using moment().day(1).
Together, this will give you the next available day that meets your requirements, regardless of where your initial moment sits in its week:
const dayINeed = 4; // for Thursday
// if we haven't yet passed the day of the week that I need:
if (moment().isoWeekday() <= dayINeed) {
// then just give me this week's instance of that day
return moment().isoWeekday(dayINeed);
} else {
// otherwise, give me next week's instance of that day
return moment().add(1, 'weeks').isoWeekday(dayINeed);
}
See also: https://stackoverflow.com/a/27305748/800457
function nextWeekday (day, weekday) {
const current = day.day()
const days = (7 + weekday - current) % 7
return day.clone().add(days, 'd')
}
// example: get next Friday starting from 7 Oct 2019
nextWeekday(moment('2019-10-07'), 5)) // 2019-10-11
I think the point is that using day() or isoWeekday() you get a date in the current week, no matter which day of the week is today. As a consequence, the date you get can be past, or still to come.
Example:
if today is Wednesday, moment().isoWeekday(5).format() would return the date of the upcoming Friday.
While
moment().isoWeekday(1).format() would return the previous Monday.
So when you say you want the date of, let's say, "last Tuesday", this date could belong to the current week or to the previous week, depending on which day is today.
A possible function to get the date of the last dayOfTheWeek is
function getDateOfPreviousDay(dayOfTheWeek) {
currentDayOfTheWeek = moment().isoWeekday();
if ( currentDayOfTheWeek >= dayOfTheWeek ) {
return moment().isoWeekday(dayOfTheWeek).format(); // a date in the current week
}
else {
return moment().add(-1,'weeks').isoWeekday(dayOfTheWeek).format(); // a date in the previous week
}
}
const upcomingDay = (dayIndex, format = "DD MMMM YYYY") => {
if (
Number(moment().format("D")) >= Number(moment().day(dayIndex).format("D"))
) {
return moment()
.day(7 + dayIndex)
.format(format);
}
return moment().day(dayIndex).format(format);
};
How can I create a date object which is less than n number of months from another date object? I am looking for something like DateAdd().
Example:
var objCurrentDate = new Date();
Now using objCurrentDate, how can I create a Date object having a date which is six months older than today's date / objCurrentDate?
You can implement very easily an "addMonths" function:
function addMonths(date, months) {
date.setMonth(date.getMonth() + months);
return date;
}
addMonths(new Date(), -6); // six months before now
// Thu Apr 30 2009 01:22:46 GMT-0600
addMonths(new Date(), -12); // a year before now
// Thu Oct 30 2008 01:20:22 GMT-0600
EDIT: As reported by #Brien, there were several problems with the above approach. It wasn't handling correctly the dates where, for example, the original day in the input date is higher than the number of days in the target month.
Another thing I disliked is that the function was mutating the input Date object.
Here's a better implementation handling the edge cases of the end of months and this one doesn't cause any side-effects in the input date supplied:
const getDaysInMonth = (year, month) => new Date(year, month, 0).getDate()
const addMonths = (input, months) => {
const date = new Date(input)
date.setDate(1)
date.setMonth(date.getMonth() + months)
date.setDate(Math.min(input.getDate(), getDaysInMonth(date.getFullYear(), date.getMonth()+1)))
return date
}
console.log(addMonths(new Date('2020-01-31T00:00:00'), -6))
// "2019-07-31T06:00:00.000Z"
console.log(addMonths(new Date('2020-01-31T00:00:00'), 1))
// "2020-02-29T06:00:00.000Z"
console.log(addMonths(new Date('2020-05-31T00:00:00'), -6))
// "2019-11-30T06:00:00.000Z"
console.log(addMonths(new Date('2020-02-29T00:00:00'), -12))
// "2019-02-28T06:00:00.000Z"
Create date object and pass the value of n, where n is number(add/sub) of month.
var dateObj = new Date();
var requiredDate= dateObj.setMonth(dateObj.getMonth() - n);
var oldDate:Date = new Date();
/*
Check and adjust the date -
At the least, make sure that the getDate() returns a
valid date for the calculated month and year.
If it's not valid, change the date as per your needs.
You might want to reset it to 1st day of the month/last day of the month
or change the month and set it to 1st day of next month or whatever.
*/
if(oldDate.getMonth() < n)
oldDate.setFullYear(oldDate.getFullYear() - 1);
oldDate.setMonth((oldDate.getMonth() + n) % 12);
You have to be careful because dates have a lot of edge cases. For example, merely changing the month back by 6 doesn't account for the differing number of days in each month. For example, if you run a function like:
function addMonths(date, months) {
date.setMonth((date.getMonth() + months) % 12);
return date;
}
addMonths(new Date(2020, 7, 31), -6); //months are 0 based so 7 = August
The resulting date to return would be February 31st, 2020. You need to account for differences in the number of days in a month. Other answers have suggested this in various ways, by moving it to the first of the month, or the last of the month, or the first of the next month, etc. Another way to handle it is to keep the date if it is valid, or to move it to the end of the month if it overflows the month's regular dates. You could write this like:
function addMonths(date, months) {
var month = (date.getMonth() + months) % 12;
//create a new Date object that gets the last day of the desired month
var last = new Date(date.getFullYear(), month + 1, 0);
//compare dates and set appropriately
if (date.getDate() <= last.getDate()) {
date.setMonth(month);
}
else {
date.setMonth(month, last.getDate());
}
return date;
}
This at least ensures that the selected day won't "overflow" the month that it is being moved to. Finding the last day of the month with the datePart = 0 method is documented here.
This function still leaves a lot to be desired, as it doesn't add years and you can't subtract more than a year (or you will run into a new issue with negatives being involved). However, fixing those and the other issues you may run into (namely timezones) will be left as an exercise for the reader.