Unable to validate double digit month using Javascript - javascript

I have an HTML form where I am allowing users to enter a date to print out a report. However, if that date is within 3 days of the current date, I have it set to tell the user that they must wait 3 days. For some reason the code works when I enter something like "09/30/2012" but when I enter "10/01/2012", the error check skips. It seems at though, if it's a double digit month (10, 11, and 12), it complete skips the error check. Please let me know if you have any ideas. Thanks
JS Code:
var date = myForm.SC_date.value;
var d = new Date(date);
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
if (myForm.SC_date.value == "")
window.alert("Please enter the requested date of variance. NOTE: Date must be 3 days prior to today's date.")
//Here is where I am having issues
/*else if(new Date(date) > new Date(varBegin))
window.alert("Invalid date. You must wait at least 3 days before you can request a report.")*/
else if(!myForm.SC_date.value.match(re))
window.alert("Invalid date. Please enter the date as follows: mm/dd/yyyy.")
HTML Code:
<td>Date of Variance </td>
<td colspan="2"><input name="SC_date:*" id="SC_date" type="text" tabindex="06">
</textarea><b><span class="style3">*</span> </b><span class="style2">(mm/dd/yyyy)</span>
</td>

I don't think you want to construct your "3 days ago" date by manipulating a string. I.e., this snippet here:
var varBegin = (d.getMonth()+1) + "-" + (d.getDate()-3) + "-" + d.getFullYear()
First, I'm not sure why you're using hyphens as delimiters here, when you are using forward-slashes as delimiters in your input field?
In any case, that's not a reliable way to construct the date. When you feed a string into the constructor of a Date object, you are effectively calling Date.parse(). That behaves differently on different browsers.
Check this out:
> new Date('1-1-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('01-01-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
> new Date('2012-1-1');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
Looks pretty good, right? But that's on Chrome.
Now check out what happens in an up-to-date version of Firefox, with the exact same calls:
> new Date('1-1-2012');
Date {Invalid Date}
> new Date('01-01-2012');
Date {Invalid Date}
> new Date('2012-1-1');
Date {Invalid Date}
> new Date('2012-01-01');
Date {Sat Dec 31 2011 16:00:00 GMT-0800 (PST)}
Furthermore, look at this behavior, in both browsers:
> new Date('2012-01-01');
Sat Dec 31 2011 16:00:00 GMT-0800 (PST)
Simply prepending zeroes to the month and date digits causes a time warp! You have to set the time and a timezone (for me, PST) to make that go away:
> new Date('2012-01-01T00:00:00-08:00')
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)
Basically, dealing with date string parsing is a headache. You don't want to have to digest and account for specs like this, this, and this.
So, here's a better alternative -- pass the year, month, and date values (in that order) to the constructor of the Date object. That will reliably create the date for you, so your comparisons are valid.
Like this, for your specific example:
var WARNING_PERIOD_IN_DAYS = 3;
// Extract month, day, year from form input, 'trimming' whitespace.
var re = /^\s*(\d{1,2})\/(\d{1,2})\/(\d{4})\s*$/;
var match = re.exec(inputVal); // from "myForm.SC_date.value".
if (match) {
var month = parseInt(match[1]) - 1; // Zero-indexed months.
var date = parseInt(match[2]);
var year = parseInt(match[3]);
var inputDate = new Date(year, month, date);
var currentDate = new Date();
var threeDaysAgo = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDay() - WARNING_PERIOD_IN_DAYS);
console.log((inputDate > threeDaysAgo) ? 'Within warning period' : 'No warning needed');
}
Speaking of specs, there's one cool thing to note here, which is that in JavaScript, you can "wrap" the date value (it can be too large, or negative), and the resulting Date will still be valid and correct. Here's why:
From the ECMAScript 262 spec, here's what happens when you call setDate():
**15.9.5.36 Date.prototype.setDate (date)**
1. Let t be the result of LocalTime(this time value).
2. Let dt be ToNumber(date).
3. Let newDate be MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t)).
4. Let u be TimeClip(UTC(newDate)).
5. Set the [[PrimitiveValue]] internal property of this Date object to u.
6. Return u.
This is the key bit: MakeDay(YearFromTime(t), MonthFromTime(t), dt)
MakeDay gets the year and the month from the current time value of the Date object (in milliseconds of epoch time), and does this:
**15.9.1.12 MakeDay (year, month, date)**
The operator MakeDay calculates a number of days from its three arguments, which must be ECMAScript Number values. This operator functions as follows:
1. If year is not finite or month is not finite or date is not finite, return NaN.
2. Let y be ToInteger(year).
3. Let m be ToInteger(month).
4. Let dt be ToInteger(date).
5. Let ym be y + floor(m /12).
6. Let mn be m modulo 12.
7. Find a value t such that YearFromTime(t) == ym and MonthFromTime(t) == mn and DateFromTime(t) == 1;
but if this is not possible (because some argument is out of range), return NaN.
8. Return Day(t) + dt - 1.
This looks rather involved, but basically it's:
The floor, modulo, and date==1 bits handle month rollovers (months that are negative or greater than 12).
The resulting instant in epoch time is converted to a number of days.
Your date value is added to that number of days. If your date value is negative, that's fine, it will just be subtracted.
The result is passed back to setDate().
setDate calls MakeDate(), which converts the number of days plus the intra-day time into milliseconds in epoch time.
The Date object's internal time is set to this new epoch time.
That's why you can do stuff like this (comments taken from the MakeDay() function in the V8 JS engine project):
// MakeDay(2007, -4, 20) --> MakeDay(2006, 8, 20)
// MakeDay(2007, -33, 1) --> MakeDay(2004, 3, 1)
// MakeDay(2007, 14, -50) --> MakeDay(2007, 8, 11)
Ok, so that was almost certainly too much detail for this particular problem... but I just wanted to make clear what's really going on behind the scenes. Thanks for your patience.
And... just one last thing...
You have a random </textarea> hanging out in that HTML snippet. If there is an opening <textarea> somewhere before it, then it's incorrectly enclosing some of your other elements. If there is no opening <textarea>, then delete it.

If you don't care about the time of the day, I recommend you do the following:
var dUser = new Date(date); //just like you did before
var dVarBegin = new Date("10/05/2012"); //here you do whatever is the date you are setting.
var diff = dVarBegin.getTime() - dUser.getTime();
//now diff is the difference in milliseconds!
I don't fully understand your requirements in relation to the 3 days. However, if what you needed was to compare dates, now you can! I hope this works for you. If you need something more, please ellaborate a little bit on the 3 days thing.

Use a library that lets you control the date formats accepted, e.g. Globalize.js or Date.js. Then define the exact test you wish to carry out especially whether time of the day is significant and whether the test should be relative to current time in user’s system (which is what you get with new Date() without arguments). You can then e.g. calculate a time difference as outlined by #Mamsaac and convert milliseconds to days with simple arithmetic.
It is illogical to use Date() and then, without checking the result, start doing pattern matching on the input. Moreover, Date() is by definition system-dependent and should seldom be used. There is no guarantee that it will accept a format like mm/dd/yyyy at all.

Related

JavaScript date creation

Why does javaScript allow creation of dates such as
invalidDate = new Date(2015,3,31);
Here I am trying to create a date with April 31st. Instead JavaScript creates a date as Fri May 01 2015 00:00:00. Should we validate the date before creating it?
There are scenarios when we try to parse invalid dates and it does the same thing. How should one parse the date correctly when the given date may not be valid?
var invalidDate = new Date(2015, 3, 31);
alert(invalidDate);
You can use the Date API to create the date and check the result:
function makeDate(year, month, day) {
var d = new Date(year, month, day);
if (d.getFullYear() !== year || d.getMonth() !== month)
throw new Error("Invalid date");
return d;
}
If the day is not a valid day for the given month, then the month will be adjusted; that's a feature of the Date API that allows easy "date math". If the above code notices that the input values have been corrected, it throws an exception.
Because there is no 31st April, so it's giving you the nearest valid date...
For clarity, as below, any integer above a valid date will roll over to the following month.
i.e. Date(2016,0,1) is 1st Jan 2016.
Date(2016,0,61) adds 60 days on to that date, which rolls past the 29th Feb 2016 and into March, thus..
Date(2016,0,61) = 1st March 2016
As a result, Date(2015,3,31) = 30th April 2015 plus one day = 1st May 2015
You can validate the date with a function like this:
function isValidDate(year, month, day) {
var m = month - 1; // Note: the month is 0-based
var d = new Date(year, m, day);
/*
For invalid dates, either the day or month gets changed:
2015-04-31 -> 2015-05-01
2015-02-29 -> 2015-03-01
2015-13-10 -> 2016-01-10
2016-00-10 -> 2015-12-10
*/
return d.getDate() == day && d.getMonth() == m;
}
In general, you should never trust user input. As a result, you should try to put them in a situation where they can not enter bad data. This can be done through validation or thought a User interface that only enables them to select valid dates.
You can look around SO for some examples on validating dates: Detecting an "invalid date" Date instance in JavaScript. If you are using a javascript framework they might already have something built into it as well.
As for why it works and "lets you do it", I would suspect that is because javascript's parse function calculates the "milliseconds elapsed since January 1, 1970, 00:00:00 UTC". The resulting milliseconds is then used and javascript represents that as the correct date.

Javascript dates not shown as equal, despite getTime() function showing the dates ARE equal

I read somewhere that you can't compare Javascript dates using the date objects, but that you could using the getTime().
This is mostly working for me, except for one date. This is my code:
if (d1.getTime() != d2.getTime()) {
// Dates are not equal, new data present
Logger.log(d1); // Fri Jul 17 08:15:14 GMT+02:00 2015
Logger.log(d2); // Fri Jul 17 08:15:14 GMT+02:00 2015
}
To me, these look exactly equal.
The other 308 rows on the spreadsheet being parsed also show as equal.
== EDIT ==
Comparing the milliseconds of the date, they are in fact not equal. This is absurd, as if they are not equal, then the new date is inserted into CouchDB and that becomes the date to compare to on the next script run (without changing the date). So CouchDB in this case must be truncating milliseconds.
There can be difference in milli seconds. Check following example for reference:
var d1 = new Date();
var d2 = new Date();
d2.setMilliseconds(d2.getMilliseconds() + 2);
console.log(+d1, +d2);
console.log(d1, d2);
console.log(+d1 === +d2);
When you use getTime you are getting a millisecond timestamps. So they would only be equal if they refer to the same millisecond timestamp. If you are interested in comparing their String representation:
d1.toString() === d2.toString()
Edit: Sorry, had wrong formats before.

Apply class to a column after date comparison in AngularJS + JavaScript

Following is the type of date I am getting from db - 2015-07-15T18:30:00.000Z . Now I am trying to add bootstap class btn-info if this date is 1 year before current date (Date.now()), if its less than or equals to 1 year but less than 3 months from current date then add class btn-warning, for 3 months or less add class btn-danger.
For this I am using ng-class on my field, like -
ng-class="calDateDiff(exp_date)"
In calDateDiff() method, I am trying to do the conversion, but unable to know which type of date format its represents.
I checked UTC in Js but its not that, also I tried Date.parse(Date.now()) but unable to know the format.
$scope.calDatediff = function(exp_date) {
// exp_date - Date.now()
// Here in calculation I am also not sure
// to handle leap years
}
Please let me know what type of date format is this and what is the right approach to handle this.
FYI- I don't want to use Moment.js as this is to be applied for only one column field, so it will be overhead just for one column to show.
EDIT 1 -
Ok I got this as its an ISO string -
so for current date I believe its going to be -
current date - new Date().toISOString()
let me know how I cam going to compare these two strings for an year, or 3 month condition ?
You can create a new date object and subtract.
Date.now() - new Date('2015-07-15T18:30:00.000Z')
1557113984
if you want to know if a year has elapsed one way to do it is to increment the date you got from the database and see if it is less than the current date:
var dbDate = new Date('2015-07-15T18:30:00.000Z');
dbDate
Wed Jul 15 2015 11:30:00 GMT-0700 (PDT)
dbDate.setMonth(dbDate.getMonth() + 12);
1468607400000
dbDate
Fri Jul 15 2016 11:30:00 GMT-0700 (PDT)
dbDate < Date.now()
false
That seems to me like an ISOString date. All you need to do is create a new object of type Date by passing that string to the constructor:
var dbDate = new Date("2015-07-15T18:30:00.000Z");
This will give you a Date object with which you can work with and easily compare it to Date.now(); I think you can do the rest of it by yourself.
Here's more info about Date: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date

Calculate difference between 2 dates considering Daylight Saving Time

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

ANSI date (COBOL Integer date) to current date

I need to translate an integer representing the number of days since 01.01.1601 (as of 6th November 2012: 150422) to a javascript Date object.
Each year has approximately 365.242199 days, so the calculation should be as follows:
var daysPerYear = 365.242199;
var daysSince = 150422;
var year = 1601 + Math.floor(daysSince / daysPerYear); // correct, gives me 2012
var days = Math.floor(daysSince % daysPerYear); // wrong, gives me 307
Now I create the Date object:
var date = new Date(year, 0);
date.setDate(days);
The date now points to 'Fri Nov 02 2012 00:00:00 GMT+0100 (CET)' which is off by about 4 days.
What is wrong with my calculation? Is there an easier way to obtain the Date object?
Clone out a copy of OpenCOBOL 1.1, and look through libcob/intrinsic.c for computations.
See cob_intr_date_of_integer in particular.
For an SVN readonly checkout
svn checkout svn://svn.code.sf.net/p/open-cobol/code/trunk open-cobol-code
or browse to
http://sourceforge.net/projects/open-cobol/files/open-cobol/1.1/open-cobol-1.1.tar.gz/download
JavaScript dates revolve from midnight on 1st January, 1970. If you do new Data().getTime(), for example, you'll be returned the number of milliseconds from that point. Therefore, to convert your dates from 1st January, 1601, you need to calculate the exact number of milliseconds between 1/1/1601 and 1/1/1970 and take the difference from your date (also converted into milliseconds).
This way, all you are doing is adding numbers together and won't suffer from any floating point inaccuracies or error from your approximations.

Categories