Validate ISO 8601 Date/Time in JavaScript [duplicate] - javascript

This question already has answers here:
Regex validate correct ISO8601 date string with time
(7 answers)
Closed 3 years ago.
I have a DateTime string ISO8601 formated
2012-10-06T04:13:00+00:00
and the following Regex which does not match this string
#(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})\+(\d{2})\:(\d{2})#
I can't figure out why it does not match.
I escaped metacharacters, for me it seems to be OK.
http://jsfiddle.net/5n5vk/2/
EDIT :
The right way: http://jsfiddle.net/5n5vk/3/

Incomplete Regex
It's incomplete as it matches invalid date such as 2013-99-99T04:13:00+00:00.
Better solution
The regex below won't match this kind of invalid date (cf. ISO 8601 Date Validation That Doesn’t Suck). You can test with the following code :
re = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/
var testDates = {
'date' : "2012-10-06T04:13:00+00:00",
'validDate' : "0785-10-10T04:13:00+00:00",
'invalidDate' : "2013-99-99T04:13:00+00:00",
'1234Date': '1234'
}
for (var d in testDates) {
if (re.test(testDates[d])) { console.info('[valid]: '+testDates[d]); }
else { console.error('[invalid]: '+testDates[d]); }
}

I found the RegExp that also tries to validate the date a bit overkill for me. I Just wanted to know if a string contains an ISO 8601 date string. I'll check if the date is actually valid after I have converted it to a Date object.
Here are 2 versions of the RegExp. This first checks if the string is a valid ISO 8601 date string. The other tests for a full date string including the hours/minutes/seconds (Commonly used in API's)
/**
* RegExp to test a string for a ISO 8601 Date spec
* YYYY
* YYYY-MM
* YYYY-MM-DD
* YYYY-MM-DDThh:mmTZD
* YYYY-MM-DDThh:mm:ssTZD
* YYYY-MM-DDThh:mm:ss.sTZD
* #see: https://www.w3.org/TR/NOTE-datetime
* #type {RegExp}
*/
var ISO_8601 = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i
/**
* RegExp to test a string for a full ISO 8601 Date
* Does not do any sort of date validation, only checks if the string is according to the ISO 8601 spec.
* YYYY-MM-DDThh:mm:ss
* YYYY-MM-DDThh:mm:ssTZD
* YYYY-MM-DDThh:mm:ss.sTZD
* #see: https://www.w3.org/TR/NOTE-datetime
* #type {RegExp}
*/
var ISO_8601_FULL = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i
// Usage:
ISO_8601_FULL.test( "2016-05-24T15:54:14.876Z" ) // true
ISO_8601_FULL.test( "2002-12-31T23:00:00+01:00" ) // true
ISO_8601_FULL.test( "2016-02-01" ) // false
ISO_8601_FULL.test( "2016" ) // false
ISO_8601.test( "2016-02-01" ) // true
ISO_8601.test( "2016" ) // true
ISO_8601.test( "2002-12-31T23:00:00+01:00" ) // true

Don't quote the regex when specifying a regex in js. Forward slash is enough.
alert($('#datepicker').val());
if($('#datepicker').val().match(
/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/
)) {
alert('ok');
} else {
alert('not ok');
}​

JavaScript date.toISOString() regex
This only attempts to solve the basic pattern of 2017-06-17T00:00:00.000Z that you expect from Javascript doing it.
const isoPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
One of the most annoying things about JSON is one cannot simply pass a date through and expect it to convert properly. Since most people use JavaScript, this is probably practical.
Here's a demo snippet if you have to pass to mongo and need to convert.
if (isoPattern.test(json.startDate))
json.startDate = new Date(json.startDate);
I argue this is a better approach as you can be assured the date will parse, then you can check desired range, all being pretty straight forward and easy to maintain as regex is great but to a point.

How about only testing if you can create a Date object of the string, if that is the purpose of the test?
new Date("2016-05-24T15:54:14.876Z").toString() === 'Invalid Date' // false
new Date("Invalid date").toString() === 'Invalid Date' // true

To add to all these good answers, I found this one to be working quite good for just ISO dates (no time)
(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))
(v = pass x = does not pass)
2016-12-30 v
2016-13-31 x
2016-01-32 x
2016-02-29 v
2016-02-30 x
2017-02-29 v -> that's a false positive
1889-01-01 x -> you can add accepted centuries in the list: (?:18|19|20)
2099-01-01 v

Related

How to convert JavaScript Date object to string that is compatible with datetime-local input?

Basically I have a Date object. How can convert it to a string compatile with datetime-local format yyyy-MM-ddThh:mm?
I tried Date.toISOString method, but it doesn't work as it appends .SSSZ at the end. Gives me the following output The specified value "2017-04-10T17:02:00.320Z" does not conform to the required format. The format is "yyyy-MM-ddThh:mm" followed by optional ":ss" or ":ss.SSS"..
Does anyone have any clean solution to this problem?
I used moment.js library to format the date accordingly. This line of code does the trick moment(date).format("YYYY-MM-DDTkk:mm").
Either theDate.toISOString().substring(0, 16), or build the string yourself with the getFullYear, getUTCDate, getUTCMonth (remember it starts at 0), etc. methods. Or use a library to do it.
I'm running into the same problem, but I didn't want to use moment or any other big lib just for a simple calculation.
I just used the ISO date but added the timezone offset, so the input doesn't go crazy when using the arrows to navigate the date values.
const offset = new Date().getTimezoneOffset() * 1000 * 60
const getLocalDate = value => {
const offsetDate = new Date(value).valueOf() - offset
const date = new Date(offsetDate).toISOString()
return date.substring(0, 16)
}
basically it adds the timezone offset and converts that to an ISO date, but then we strip the timezone with the substring(0, 16)
this gives us the correct "timezoned ISO" date.
I'm giving it a try but so far it works okay. I wish this gets resolved natively, it is weird that it doesn't work out of the box.
use moment.js to format the date to the corresponding one:
moment(new Date()).format('YYYY-MM-DDTHH:mm')
but not: moment(date).format("YYYY-MM-DDTkk:mm")
the previous answer is wrong !!
kk is between 1 - 24 (which is not compatible with the textfield DateTime local)

Convert from dateTime string to javascript date object

I use this method in order to convert a date string to a javascript date object:
function convertToDateOrUndefined(dateString) {
if (dateString instanceof Date || dateString == null) {
return undefined;
}
return new Date(dateString.replace(/(\d{2})\.(\d{2})\.(\d{4})/,'$3-$2-$1'));
}
Currently I have this dateTime string 'dd.MM.yyyy HH:mm' and I would need also a function to convert this string into a js date obejct.
I am not really good in regex therefore I would need help - Thanks!
Look at the current regex. You know it returns a date from your dd.MM.yyyy format, right? So you can assume that the three (\d{n}) represent the day, month and year (\d means a digit, {n} means n times, so \d{2} mean two digits; the () groups each part so we can refer to them later).
In the second string, we take the parts the we got from the 1st one, and reorder them. $1 is the 1st group (the part of the regex inside the ()), $2 is the 2nd group, etc.
From there, the way to the solution is simple. We just need to add the time part:
new Date(dateString.replace(/(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2})/,'$3-$2-$1 $4:$5'));
A non regex solution. Hope this helps
var dateString = '25.12.2016 00:00';
var formattedDateString = dateString.split(' ')[0].split('.').reverse().join('-');
var dateObj = new Date(formattedDateString);
console.log(dateObj);

Regular Expression Pattern match for Date

I am trying to extract the date from the following object (that has been stringified.)
I am new to regular expressions, and not sure how to go about it.
I tried /^(\d{4})\-(\d{1,2})\-(\d{1,2})$/gmi -> but it didnot work.
{"Date":"2016-05-16","Package Name":"com.myapp.mobile","Current Device Installs":"15912","Daily Device Installs":"41","Daily Device Uninstalls":"9","Daily Device Upgrades":"3","Current User Installs":"12406","Total User Installs":"23617","Daily User Installs":"27","Daily User Uninstalls":"8"}
Don't use a Regex here.
Do JSON.parse(str).Date, unless there is a really good reason not to (you haven't stated one in your question)
If you want to turn the string "2016-05-16" into 3 variables for Year, Month and day (without using a date library), I'd just use .split():
dateArray = "2016-05-16".split("-")
var year = dateArray[0], month = dateArray[1], day = dateArray[2];
Your regex matches fine, just don't use the /gmi flags
"2016-05-16".match(/^(\d{4})\-(\d{1,2})\-(\d{1,2})$/)
You can make it a bit simpler yet..
"2016-05-16".match(/(\d{4})-(\d{2})-(\d{2})/)
But, you really should be using a library for this, like moment.js, or at least Date which will work fine because this ISO-8601.
const date = new Date("2016-05-16");
date.getYear();
As suggested in comments, you can get the date by parsing the JSON (trimmed in the following for convenience):
var s = '{"Date":"2016-05-16","Package Name":"com.myapp.mobile"}';
var dateString = JSON.parse(s).Date;
document.write(dateString);
If you want a Date object, you can then parse the string. Note that using either the Date constructor or Date.parse for parsing strings is not recommended due to browser inconsistencies. Manually parsing an ISO date is fairly simple, you just need to decide whether to parse it as local or UTC.
Since ECMA-262 requires the date–only ISO format to be parsed as UTC, the following function will do that reliably (and return an invalid date for out of range values):
/* Parse an ISO 8601 format date string YYYY-MM-DD as UTC
** Note that where the host system has a negative time zone
** offset the local date will be one day earlier.
**
** #param {String} s - string to parse
** #returs {Date} date for parsed string. Returns an invalid
** Date if any value is out of range
*/
function parseISODate(s) {
var b = s.split(/\D/);
var d = new Date(Date.UTC(b[0], b[1]-1, b[2]));
return d && d.getMonth() == b[1]-1? d : new Date(NaN);
}
var d = parseISODate('2016-05-16');
document.write('UTC date: ' + d.toISOString() + '<br>' +
'Local date: ' + d.toString());

How to validate timestamp in javascript

How do you validate timestamp using javascript and timestamp to accept multiple formats
e.g. YYYY-MM-DD HH:mm:ss.S, YYYY-MM-DD HH:mm:ss AM/PM.
You can validate if a string is a valid timestamp like this:
var valid = (new Date(timestamp)).getTime() > 0;
var valid = (new Date('2012-08-09')).getTime() > 0; // true
var valid = (new Date('abc')).getTime() > 0; // false
Revisiting this answer after many years, validating dates can still be challenging. However, some of the argument is that the built in parser accepts a number of input format, many of which have little relevance.
The question here is to validate a timestamp of multiple formats, and unless the date parser can help you, there is a need to convert the timestamp into a generic format that is comparable. How to convert into this format depends on the format of the input, and in case of incompatible inputs, a tailored conversion algorithm will have to be developed.
Either use the built in date parser, as described above, otherwise, you will have to parse the input manually, and validate it accordingly.
The solution of #Jørgen is nice but if you have a date before January 1, 1970 your timestamp will be a negative number but also a valid timestamp.
function isValidTimestamp(_timestamp) {
const newTimestamp = new Date(_timestamp).getTime();
return isNumeric(newTimestamp);
}
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
The numeric validation I took from the following SO answer.
For example:
isValidTimestamp('12/25/1965') // true
Every valid number is a timestamp. If it satisfies the condition of valid integer number then it will also satisfy the condition of the valid timestamp.
Timestamp = The number of milliseconds since 1970/01/01
var d = Date.parse(your_timestamp);
d should be a valid number and not NaN.
ref: http://www.w3schools.com/jsref/jsref_parse.asp
You can't generically parse a date string without knowing beforehand what the format is, or at least that it is one of a limited number of formats.
If the date component is always in ISO8601 format (yyyy-mm-dd) and the time is either 24hr or 12hr with AM or PM, you should be able to easily split off the time, look for AM or PM, then treat the time as 12 or 24hr depending on whether it's present or not.
Timezones must be specified as either UTC (Z) or hours +/-UTC, abbreviations such as EST are ambiguous (and not standardised).
by using new Date().getTime(); you can do this
and doing something like this
var getDate="12-12-2012";
var myDate=getDate.split("-");
var getDate=myDate[1]+"/"+myDate[0]+"/"+myDate[2];
alert(new Date(getDate).getTime());
/**
* Determine whether string is timestamp
*
* #example
*
* isTimestamp('1606205966448'); // true
* isTimestamp(1606205966448); // true
* isTimestamp('1606205966448qwe'); // false
* isTimestamp('2020-11-24T08:19:26.448Z'); // false
*
* #param {string|number} n
* #returns {boolean}
*/
function isTimestamp(n) {
const parsed = parseFloat(n);
return !Number.isNaN(parsed) && Number.isFinite(parsed) && /^\d+\.?\d+$/.test(n);
}
export default isTimestamp;
Warning! The answer from Jørgen doesn't work before 1970.
getTime will return NaN (Not a Number) when it's not a valid date so we'll just use the built-in function isNaN to check, and inverse the value with !.
!isNaN(new Date("1969-02-13").getTime())
Working with dates can be a hassle. It's recommended to use libraries that are battle-tested. Something like date-fns or similar.

Javascript Date(dateString) returns NaN on specific server and browser

I'm using the Javascript Date(string) constructor with a date format of "yyyy-mm-dd". The constructor works just fine in IE 9 and Firefox unless the app is running on our testing VM which is running IIS. If it's on the VM, in IE 9 it returns 'NaN', but still works normally in Firefox.
var dateAsString = "2011-11-09";
var dateCreated = new Date(dateAsString);
I was under the assumption that the server had nothing to do with client-side Javascript. Any suggestions?
And for those of us who want to know how to replace hyphens (aka dashes) with slashes:
new Date(dashToSlash(string));
That uses this function:
function dashToSlash(string){
var response = string.replace(/-/g,"/");
//The slash-g bit says: do this more than once
return response;
}
In my case it's much easier to convert hyphens to slashes selectively (only where it's needed for the Date() function) than to replace the date format everywhere in my code.
Note: you really need to define a separate 'response' variable and assign it the value of the replace operation result. If you don't, the string is returned unaltered in Chrome. That's not a huge problem, since Chrome doesn't have a problem with hyphenated date strings to begin with. But still...
Just use slashes instead of hyphens if you can.
EDIT: Expanded clarification...
The ISO 8601 standard format uses the hyphen as a date separator. My answer does not mean you do not need to follow standards. You can use slashes only for the Date constructor if necessary.
It's because of the date format. For some reason, IE and Safari get tripped up with yyyy-mm-dd. Use another date format and you should be all set.
It's talked about here:
http://biostall.com/javascript-new-date-returning-nan-in-ie-or-invalid-date-in-safari
I suggest attempting a more reliable form of date parsing. The example below uses setFullYear(). Does IE produce a different result with the code below?
/**Parses string formatted as YYYY-MM-DD to a Date object.
* If the supplied string does not match the format, an
* invalid Date (value NaN) is returned.
* #param {string} dateStringInRange format YYYY-MM-DD, with year in
* range of 0000-9999, inclusive.
* #return {Date} Date object representing the string.
*/
function parseISO8601(dateStringInRange) {
var isoExp = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/,
date = new Date(NaN), month,
parts = isoExp.exec(dateStringInRange);
if(parts) {
month = +parts[2];
date.setFullYear(parts[1], month - 1, parts[3]);
if(month != date.getMonth() + 1) {
date.setTime(NaN);
}
}
return date;
}
Source: http://jibbering.com/faq/#parseDate

Categories

Resources