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.
Related
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;
},
In this sample code to convert a string to a date:
function stringToDate(){
var edate = "2015-06-01";
Logger.log(edate);
var input = edate.split('-');
var date = new Date();
date.setUTCFullYear(input[0],input[1] - 1,input[2]);
Logger.log(date);
}
Logging the date returns "Mon Jun 01 20:07:45 GMT+01:00 2015", which is correct, as the month '06' - 1 = 5 corresponds to the month of June for the this.
However, this almost identical function:
function stringToDate2(){
var edate = "2015-06-01";
Logger.log(edate);
var input = edate.split('-');
var date = new Date();
date.setUTCFullYear(input[0]);
date.setUTCMonth(input[1] - 1);
date.setUTCDate(input[2]);
Logger.log(date);
}
Returns "Wed Jul 01 20:10:04 GMT+01:00 2015". Some other values return equally screwy results. Why do I get a different result for 'setUTCMonth' then for 'setUTCFullYear'?
Set the Date before the Month
date.setUTCFullYear(input[0]);
date.setUTCDate(input[2]);
date.setUTCMonth(input[1] - 1);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCMonth
If a parameter you specify is outside of the expected range,
setUTCMonth() attempts to update the date information in the Date
object accordingly. For example, if you use 15 for monthValue, the
year will be incremented by 1, and 3 will be used for month.
Each of the UTC functions has a similar note about out of range values.
So because of this:
new Date() gets the current date, and thus today being 5/31 the date is 31.
There are some months without a 31st date, so 31 is outside the range for date so it is updated accordingly.
So if you try to set the month for say February without changing the date first,
The date would be 2/31/2015, but February only has 28 days this year so it rolls over to 3/03/2015
And in your case, if you try to set it for June, 6/31/2015, June never has a 31st date so again it rolls over to 7/01/2015. And so on.
So change the date first like I show above or set a default date when you create it:
new Date("01/01/2015")
Problem
I'm using AngularJS and in my view I have 7 days in a row like the pic below. The red, grey, and blue are based on a date (9/1/2013 Sunday). When I click Friday or Monday I want that date to be returned so I can reload the 0/3 with the stats for that date.
I don't need anything fancy for AngularJS I can't figure out the logic to take a base date and then switch the day out for the day that was clicked.
How do I get this to return a date?
Current base date: 9/1/2013 - Sunday
I click: Thursday
I receive: 8/29/2013 - Thursday
I click: Sunday
I receive: 9/1/2013
What it looks like
I'm currently trying to convert this function from:
JavaScript - get the first day of the week from current date
function getMonday(d) {
d = new Date(d);
var day = d.getDay(),
diff = d.getDate() - day + (day == 0 ? -6:1); // adjust when day is sunday
return new Date(d.setDate(diff));
}
getMonday(new Date()); // Mon Nov 08 2010
Solved!
I render the dates server side when I render my stats.
Using AngularJS:
My directives: http://paste.laravel.com/Nz9
My HTML template: http://paste.laravel.com/Nza
My PHP: http://paste.laravel.com/Nzc
Forget about what it looks like, let's focus on what data you have.
If I'm understanding you correctly, you have an associative array of something like:
[{'M',0},{'T',1},{'W',2},{'T',3},{'F',4},{'S',5},{'S',6}]
And you also have a base date
var base = moment('2013-09-01');
And the base is associated with the last value - the 6.
So then what you could do is something like this:
var x = 3; // I clicked on Thursday and got a 3
var target = base.subtract('days', 6-x); // move back 6-x days
That would work, but wouldn't it be much easier just to precalculate your associative array in the first place?
[{'M','2013-08-26'},
{'T','2013-08-27'},
{'W','2013-08-28'},
{'T','2013-08-29'},
{'F','2013-08-30'},
{'S','2013-08-31'},
{'S','2013-09-01'}]
Then you would already know what value to use when it was clicked.
The problem with moment's day() is that Sunday == 0, not Monday, so you have to jump one week back and use the range 1..7 for Monday..Sunday:
base = '9/1/2013'
console.log(moment(base).day(-7).day(4))
> Thu Aug 29 2013 00:00:00 GMT+0100
console.log(moment(base).day(-7).day(7))
> Sun Sep 01 2013 00:00:00 GMT+0100
Why do these two dates are differents :
var date1 = new Date();
date1.setFullYear(2012); // year (four digits)
date1.setMonth(10); // month (from 0-11)
date1.setDate(1); // day of the month (from 1-31)
var date2 = new Date(2012, 10, 1, 0, 0, 0, 0);
Result :
Date 1 : Sat Dec 01 2012 14:56:16 GMT+0100
Date 2 : Thu Nov 01 2012 00:00:00 GMT+0100
whereas these two dates are equals :
var date3 = new Date();
date3.setFullYear(2012); // year (four digits)
date3.setMonth(9); // month (from 0-11)
date3.setDate(1); // day of the month (from 1-31)
var date4 = new Date(2012, 9, 1, 0, 0, 0, 0);
Result :
Date 3 : Mon Oct 01 2012 14:56:16 GMT+0200
Date 4 : Mon Oct 01 2012 00:00:00 GMT+0200
Another question is why do date1.setMonth(10) gives a date in December (should be November).
Finally got it. new Date() sets the date to the current date and time. In other words, October 31st (at the time of this writing).
When you then try to set the month to November, what's it to do? November only has 30 days... so it wraps it round to December.
If you change the order so that you set the day-of-month before the month, it works:
var date1 = new Date();
date1.setFullYear(2012); // year (four digits)
date1.setDate(1); // day of the month (from 1-31)
date1.setMonth(10); // month (from 0-11)
Or as implied by jbabey's answer:
var date1 = new Date();
date1.setFullYear(2012); // year (four digits)
date1.setMonth(10, 1); // month (from 0-11) and day (1-31)
The documentation isn't terribly clear, but it's at least suggestive:
If a parameter you specify is outside of the expected range, setMonth attempts to update the date information in the Date object accordingly. For example, if you use 15 for monthValue, the year will be incremented by 1 (year + 1), and 3 will be used for month.
("Accordingly" is far from precise, but it means the implementation is at least arguably correct...)
setMonth accepts a second parameter:
If you do not specify the dayValue parameter, the value returned from the getDate method is used.
When you set the month to 10 (November), it grabs the current day value (31) and sets that as the day. Since there are only 30 days in November, it rolls you over to December 1st.
You're creating a var containing the current date (new Date()) and then you're changing some of it's keys (year, month and day).
On the other hand new Date(2012, 10, 1, 0, 0, 0, 0) means "create a date object with those exact values".
And that's why your date objects aren't equal.
function parseDate(s){
var parts = s.split('/')
return new Date(parts[2], parts[1], parts[0])
}
function calcDaysBetween(startDate, endDate){
return Math.floor((endDate-startDate)/86400000);
}
function yarro(){
var startDate = parseDate($('#pickupdate').val());
var endDate = parseDate($('#dropoffdate').val());
var days = calcDaysBetween(startDate, endDate);
$('#newp').html('Days Count: <b>'+days);
}
31/3/2012 , 1/4/2012
Days Count: 0 //wrong
or
31/1/2012 , 1/2/2012
Days Count: -1 //wrong
1/1/2012 , 2/1/2012
Days Count: 1 //ok
Why?
Knowing that JS months are 0-based is very important to this. Your code is parsing the date 31/1/2012 into 31 February 2012, which is technically an invalid date but is interpreted as 2 March 2012 (the 2nd because 2012 is a leap year). What you need to do is subtract 1 from the parts[1] value before passing it to the Date constructor.
You are getting -1 days between 31/1/2012 and 1/2/2012 because those dates are interpreted as 31 February 2012 (2 March 2012) and 1 March 2012. When you subtract those dates, you get a -1-day difference.
You are getting 0 days between 31/3/2012 and 1/4/2012 because those dates are interpreted as 31 April 2012 (1 May 2012) and 1 May 2012, which are the same date, resulting in a 0-day difference.
You are getting 1 day between 1/1/2012 and 2/1/2012 because those dates are interpreted as 1 February 2012 and 2 February 2012, resulting in a 1-day difference.