Given a start date, and a number of days, I need to display the end date = start date + number of days.
So I did something like this:
var endDate=new Date(startDate.getTime()+ONE_DAY);
Everything works fine, except that for 25 and 26 October gives one day less.
Ex.:
2014-01-01 + 2 days = 2014-01-03
2014-10-25 + 2 days = 2014-10-26 (here is the case I need to treat).
This difference appear because of the clock going back 1 hour. Practically 2014-10-27 00:00:00 becomes 2014-10-26 23:00:00.
A simple solution would be to compute this at another hour (example 3 AM). But I want to just display a note when this happens.
For example, if user inputs 2014-10-25, I show a popup saying [something].
Now here is the real problem... I can't seem to find any algorithm that says when clocks goes back in year X.
Example... in 2014 the day is 26 October. In 2016 is 30 October (https://www.gov.uk/when-do-the-clocks-change). Why? This date looks random to be, but I don't think it is. So... when does clock go back/forward?
EDIT: All answers/comments are helpful related to how to fix the problem. But... I already passed that stage. Now I only have an itch about "how on earth are the days when clock is changed computed?".
To find the difference between two dates in whole days, create Date objects, subtract one from the other, then divide by the milliseconds in one day and round. The remainder will only be out by 1 hour for daylight saving so will round to the right value.
You may also need a small function to convert strings to Dates:
// Return Date given ISO date as yyyy-mm-dd
function parseISODate(ds) {
var d = ds.split(/\D/);
return new Date(d[0], --d[1], d[2]);
}
Get the difference in days:
function dateDiff(d0, d1) {
return Math.round((d1 - d0)/8.64e7);
}
// 297
console.log(dateDiff(parseISODate('2014-01-01'), parseISODate('2014-10-25')));
If you want to add days to a date, do something like:
// Add 2 days to 2014-10-25
var d = new Date(2014, 9, 25);
d.setDate(d.getDate() + 2);
console.log(d); // 2014-10-27
The built–in Date object takes account of daylight saving (thought there are bugs in some browsers).
I prefer adding days this way:
var startDate = //someDate;
var endDate = new Date(startDate.getFullYear(),
startDate.getMonth(),
startDate.getDate()+1);
This way you don't have to worry about the days in the calendar.
This code add 1 day, if you want to add more, change the startDate.getDate()+1 for startDate.getDate()+NUMBER_OF_DAYS it works fine even if you are on the last day of month i.e. October 31th.
But maybe you can use #RobG solution which is more elegant than mine
Related
I have an app where a user can select two dates (a from date and a to date) and the time between the dates should not exceed 4 months. A user can select the day, month and year for each date. Is there some kind of logic I could use to achieve this, so that an error is returned if the date range is over 4 months. Each input as an integer. For example, a start date of March 31st 2019 would be: from_date_day = 31 from_date_month = 3 and from_date_year = 2019
For example, I something like this would kind of work:
((Math.abs($('#to_date_month').val() - $('#from_date_month').val()) > 2) && $('#from_date_day').val() <= $('#to_date_day').val()
return "error"
The problem with this code is that it doesn't work when the dates straddle two different years. I'm using coffeescript, but a solution in jquery or js would also work.
I'd recommend creating two Javascript Date objects of those two dates. This can be done by feeding the year, the month and finally the day to the constructor of the Date object.
e.g.
var startDate = new Date(2019, 1, 16); // January the 16th
var endDate = new Date(2019, 3, 30); // March the 30th
Using the .getTime() function of the Date object you can get the number of milliseconds passed since 1.1.1970. If you calculate the difference between those two numbers, wrap it inside Math.abs() and divide that number by 1000, 60, 60 and finally 24 you get the number of days. If this number is bigger than ~120, the range is more than four months.
console.log(Math.abs(startDate.getTime() - endDate.getTime()) / 1000/60/60/24);
In your use case the Date object could be set like this:
var startDate = new Date(parseInt($('#from_date_year').val()), parseInt($('#from_date_month').val()), parseInt($('#from_date_day').val()));
I am using the following in moment.js to convert seconds to Days Hours Minutes Seconds format
moment().startOf('year').seconds(1209600).format('DD HH:mm:ss')
But instead of getting 14 00:00:00, I am getting 15 00:00:00
What am I missing here?
1209600 seconds is 14 days, so because the first day of the year is day 01 00:00:00, if you add 14 days you get 15 00:00:00.
You don't say exactly what you're trying to do, but what you're getting is the right answer for "what's the date/time for 1209600 seconds into the year."
You're attempting to work with the concept of duration, but you're using the calendar to do it. This isn't a good idea for several reasons. As others pointed out, the calendar starts on the 1st, which is throwing you off. But also, you could have local time zone discontinuities affect your results, such as if your duration went far enough into the year to be caught by the spring-forward daylight saving time transition.
If you want to use Moment to work with durations, there is a separate API for that:
var d = moment.duration(1209600, 'seconds');
var h = d.hours();
var m = d.minutes();
var s = d.seconds();
There is currently not a format method built-in for durations, so you'd have to assemble these into a string yourself, applying zero-padding where necessary. However, there is the moment-duration-format third-party plugin, which would let you do it like this:
moment.duration(1209600, 'seconds').format('DD HH:mm:ss')
moment().startOf('year'); // set to January 1st, 12:00 am this year
So, startOf('year') method set moment starting point to 1st January of current year from 12.00 AM
, which is start of the day. and you are adding 14 days on top of that. But as the initial date started at 12.00 AM, its still a whole day (ends at 11.50 PM) which adds one additional day in final result.
I have an interesting result from the javascript in an Acrobat PDF Form
I have a series of date form fields. The first field is for user entry and the remaining fields are calculated by javascript, each field incremented by one day.
The code is:
var strStart = this.getField("userField").value;
if(strStart.length > 0) {
var dateStart = util.scand("dd/mm/yy",strStart);
var dateStartMilli = dateStart.getTime();
var oneDay = 24 * 60 * 60 * 1000 * 1; // number of milliseconds in one day
var dateMilli = dateStartMilli + oneDay;
var date = new Date(dateMilli);
event.value = util.printd("dd/mm/yy",date);
} else { event.value = "" }
The issue is if I input 05/04/15 in to the user field the result is 05/04/15 (same, wrong) while any other date of the year correctly increments by one day (ie 25/10/15 gives 26/10/15, 14/2/15 gives 15/2/15 etc)
The same error occurs on the 3rd of April 2016, 2nd of April 2017, etc (ie each year)
I have a fortnight (14) of these incrementing fields, each incrementing the date from the previous calculated field with the same javascript as above ("userField" is changed to date2, date3, date4 etc). What is very strange is that the next field that increments off the second of the two 05/04/15 correctly returns 06/04/15 and there isn't an issue after that.
Does anyone know why this might be?!
That doesn't happen on my browser's JavaScript engine and/or in my locale, so it must be an Acrobat thing or that date may be special in your locale (e.g., DST).
In any case, that's not the correct way to add one day to a JavaScript date, not least because some days have more than that many milliseconds and some have less (transitioning to and from DST).
The correct way is to use getDate and setDate:
var strStart = this.getField("userField").value;
if(strStart.length > 0) {
var dateStart = util.scand("dd/mm/yy",strStart);
dateStart.setDate(dateStart.getDate() + 1); // Add one day
event.value = util.printd("dd/mm/yy",dateStart);
} else { event.value = "" }
setDate is smart enough to handle it if you go past the end of the month (per specification).
If it's DST-related, the above will fix it. If it's some weird Acrobat thing, perhaps it will work around it. Either way, it's how this should be done.
Let me guess, that's the day daylight savings starts in your locale? 24 hours after midnight is not always the next day, because some days have 25 hours.
Approaches that come to my head:
manipulate the day. (This is easy if Acrobat allows dates like the 32nd of January, because oyu can just increment the day. Otherwise, maybe don't bother because leap years aren't much better than DST.)
don't start from midnight. If you never use the hour and minute within the day, don't pin your day at the strike of midnight, but at, say, 3am. After a change in DST status, later days in your fortnight might register as 2am or 4am, but as long as you're only using the day…
I want to count down the days until a particular event using momentjs but I'm getting an unexpected result.
With today's date being 17th April, and the event date being 14th May, I want the resulting number of days to be 27, however my code gives me a result of 57. What's wrong?
function daysRemaining() {
var eventdate = moment([2015, 5, 14]);
var todaysdate = moment();
return eventdate.diff(todaysdate, 'days');
}
alert(daysRemaining());
When creating a moment object using an array, you have to take note that months, hours, minutes, seconds, and milliseconds are all zero indexed. Years and days of the month are 1 indexed. This is to mirror the native Date parameters.
Reference
So either change the month to 4 to reflect May or parse the date as an ISO 8601 string
function daysRemaining() {
var eventdate = moment("2015-05-14");
var todaysdate = moment();
return eventdate.diff(todaysdate, 'days');
}
alert(daysRemaining());
Just to add for anyone else that comes across this - there's actually a helper that does the phrasing etc for you:
https://momentjs.com/docs/#/displaying/to/
/* Retrieve a string describing the time from now to the provided date */
daysUntil: function(dateToCheckAgainst){
return new moment().to(moment(dateToCheckAgainst));
}
// Sample outputs
"in three months"
"in two months"
"in 25 days"
That's because months are zero indexed. So 5 is actually June ;)
I was just creating a simple calendar when users clicks next it gets the following day, very simple code:
var dateSelected = new Date('02/06/2013'); //any date
var day = new Date(dateSelected.getTime() + 24*60*60*1000);
alert(day.getDate());
that works great for all dates but for some reason it doesn't get the next day when the date is 27 Oct 2013
var dateSelected = new Date('10/27/2013');
I don't seem to be able to figure out why, if I go manually to the next day 28 Oct it keeps working fine.
Any ideas why this happens?
UPDATE:
I fixed it by adding the time as well as the date:
var dateSelected = new Date('10/27/2013 12:00:00');
I strongly suspect this is because of your time zone - which we don't know, unfortunately.
On October 27th 2013, many time zones "fall back" an hour - which means the day is effectively 25 hours long. Thus, adding 24 hours to your original value doesn't change day if it started within the first hour of the day.
Fundamentally, you need to work out whether you're actually trying to add a day or add 24 hours - they're not the same thing. You also need to work out which time zone you're interested in. Unfortunately I don't know much about Javascripts date/time API, but this is almost certainly the cause of the problem.
Rather than adding the number of milliseconds in a day, you can use the set date function directly.
var dateSelected = new Date('10/27/2013');
var daysToAdd = 1;
var nextDay = new Date(dateSelected.getTime());
nextDay.setDate(dateSelected.getDate() + daysToAdd);
This also works when rolling over to the next month, and should work well with different time zones.
As Jon Skeet already mentioned, the problem results from your local timezone. As a possible solution, you can use the setDate and getDate functions of the Date object:
var dateSelected = new Date('02/06/2013'); //any date
dateSelected.setDate(dateSelected.getDate() + 1);
alert(dateSelected.getDate());
And of course, no JavaScript Date question could be complete without a Moment.js answer:
var m = moment('10/27/2013','MM/DD/YYYY').add('days', 1);
Superior API every time. :-)