Momentjs : How to prevent "Invalid date"? - javascript

I have the following code :
var fomattedDate = moment(myDate).format("L");
Sometimes moment(myDate).format("L") returns "Invalid date", I want to know if there is a way to prevent that and return an empty string instead.

TL;DR
If your goal is to find out whether you have a valid date, use Moment's isValid:
var end_date_moment, end_date;
jsonNC.end_date = jsonNC.end_date.replace(" ", "T");
end_date_moment = moment(jsonNC.end_date);
end_date = end_date_moment.isValid() ? end_date_moment.format("L") : "";
...which will use "" for the end_date string if the date is invalid.
Details
There are two very different things going on here.
First:
0000-00-00T00:00:00 is an invalid date. There's no month prior to January (which is month #1 in that format), nor a day of a month prior to day #1. So 0000-00-00 makes no sense.
0000-01-01T00:00:00 would be valid — and moment("0000-01-01T00:00:00").format("L") happily returns "01/01/0000" for it.
If you use a valid date (such as your 2015-01-01T00:00:00 example), the code is fine.
Second:
console.log(Object.prototype.toString.call(end_date));
It returns [object String] even with a valid date, so the if condition doesn't working in my case.
Of course it does: format returns a string, and you're using format to get end_date.
If you want to know if a MomentJS object has an invalid date, you can check like this:
if (theMomentObject.isValid()) {
// It has as valid date
} else {
// It doesn't
}
If you want to know if a Date object has an invalid date:
if (!isNaN(theDateObject)) {
// It has as valid date
} else {
// It doesn't
}
...because isNaN will coerce the date to its primitive form, which is the underlying number of milliseconds since Jan 1 1970 00:00:00 GMT, and when a date has an "invalid" date, the number it contains is NaN. So isNaN(theDateObject) is true when the date is invalid.

Related

Moment converting digit into date

Trying to understand how moment.js is converting a string to date, I've bounced into this issue.
let date = "User has logged in to more than 10 .";
console.log(moment(date)); //output date
let invalid = "User has logged in to more than 10 a";
console.log(moment(invalid)); //output invalid date
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js
"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/2.2.0/moment-range.js"></script>
can someone explain it to me ??
CodePen link
When you pass the string moment checks whether it is a valid date format, and if not, it falls back to the built-in javascript Date.parse() method.
The moment.js docs say:
When creating a moment from a string, we first check if the string
matches known ISO 8601 formats, we then check if the string matches
the RFC 2822 Date time format before dropping to the fall back of new
Date(string) if a known format is not found.
Date.parse does not recognize anything useful in your string until it encounters 10; it drops the rest. A default date format is assumed, which will depend on your location and language. In my own case, here in the US, the format is MM/DD. The result is that the string is parsed to a date of Oct. 1st (10th month, no day specified defaults to the 1st). And then (for Y2K-ish reasons, I suspect) it assumes a year of 2001, since no year is given.
We get the same behavior from javascript's built-in Date methods:
new Date(Date.parse('User has logged in to more than 10.'))
// Mon Oct 01 2001 00:00:00 GMT-0400 (EDT) <- As printed from Michigan.
In your second case, you tried ending the string with 10 a instead of 10 . and you will notice the same behavior (invalid date) if you pass the same to the built-in Date methods.

Determine if string is Date or Number

I'm trying to determine if a string is a number or a date.
Here is my code:
this._getFieldFormat = (value) => {
// check if is date
let d = new Date(value);
if (!isNaN( d.getTime() ) ) {
return 'date';
}
// check if is boolean
// isNaN(false) = false, false is a number (0), true is a number (1)
if(typeof value === 'boolean'){
return 'boolean';
}
// check if a string is a number
if(!isNaN(value)){
return 'number';
}
return typeof value;
};
It works for a date like: 2016-04-19T23:09:10.208092Z.
The problem is that 1 look to be a valid date (Wed Dec 31 1969 16:00:00 GMT-0800 (PST)) and isNaN(new Date()) is return false (a date is a number).
Any idea on how to get out of this loop?
So what is happening is called coercion. Since javascript is dynamic typing when you give it two different types the js engine tries to coerce one of the types into something reasonable or what it thought you meant.
For instance:
isNan("37"); is false because "37" is converted to the number 37
isNaN(new Date()) is return false (a date is a number)
It converted Date to a number so this is correct.
However, invalid values in date strings not recognized as ISO format as defined by ECMA-262 may or may not result in NaN, depending on the browser and values provided
So
new Date('23/25/2014'); // NON-ISO string with invalid date values
So this will return NaN in all browsers that comply with ES5 and later.
Also to do a stricter check you can use:
Number.isNan(new Date()); // This should return true
So to recap make sure the date conform to the ISO standard or it will be NaN and use the stricter check. Hope this helps.
In general and from a Javascript design point of view, however, I don't think you can do it by design. Any number between 8640000000000000 and the earliest date in terms of a number -8640000000000000 can be converted to date (represented as time in milliseconds from 01 January, 1970 UTC).
Therefore, any number not falling is this range cannot be a date. And any number falling in range would be a valid date or a number and you gotta use context to determine if you want to interpret it as a number or a date.
You could however do a naive implementation to test if number is a valid date or not, but that's the best you can do, without context.
Determining whether a date is a number or not can be a bit easier. Because a human-readable representation of date will return true by isNaN() thereby determining that it's definitely not a number. Then you would go on and check if that string is a date or not, which you already did in your function.

Check if time format is valid in moment.js

moment.js can format time according to a given format.
Some formats however seem invalid. For instance the website provides the YYYY [escaped] YYYY format. When one however specifies YYYY [escape, the time is formatted like 2014 [121campe its clear that e and s are converted according to the formatting guidelines, but the format is quite invalid.
Is there a way to check if the format provided is valid and for instance if some aspects will be shown in the resulting string (example format.containsHours, note this should also return true if not HH is part of the format string, but for instance LLLL will print the hours implicitly).
I've found nothing in the documentation thus far.
Moment's validation functions are limited to validating whether a given date/time input string is valid according to a given format. It is assumed that the format(s) are known to the developer. It's not intended to accept the format string itself from a variable source such as the end user.
So no, there are no methods for confirming that the format string is valid.
This could work:
function isValidDate(date) {
return (moment(date).toDate().toString() !== "Invalid Date")
}
Use this function
function checkIfDateIsValidUsingMoment(dateString,format)
{
var m=moment(dateString,format);
return m._pf.charsLeftOver ==0 && m._pf.unusedTokens.length==0 && m._pf.unusedInput.length==0 && m.isValid();
}
Above function takes datestring and format, Moment object has isvalid method but its less usable for strict date validation.
Moment Object has _pf which stores info about parsed date.
charsLeftOver: no of chars that do not match (Means extra character, invalid date)
unusedInput: array containing details about unused inputs
unusedTokens: array containing details about unused tokens
For ex :
moment("25 october 2016aaaa","DD MMM YYYY")
This object has "aaaa" as invalid character so it is available in _pf object
You can validate date using these details.

Check if the given string is a date object

I need to check whether the given string is date object or not.
Initially I used
Date.parse(val)
If you check Date.parse("07/28/2014 11:23:29 AM"), it'll work.
But if you check Date.parse("hi there 1"), it'll work too, which shouldn't.
So I changed my logic to
val instanceof Date
But for my above date string, "07/28/2014 11:23:29 AM" instanceof Date it returns false.
So, is there any way with which I can appropriately validate my string against Date?
You can use Date.parse to check if it is a date or not using below code. Date.parse() return number if valid date otherwise 'NaN' -
var date = Date.parse(val);
if(isNaN(date))
alert('This is not date');
else
alert('This is date object');
For more information - Date Parse()
function isDate(val) {
var d = new Date(val);
return !isNaN(d.valueOf());
}
Hope helps you

Is this a good way to check for a valid date in JavaScript?

Please correct or explain how my over-simplification is incorrect as I am not a JavaScript expert.
But I just need to know if an object is a valid date. This will only come from user input (ie, text box).
var is_valid_date = function(date) {
try {
var d = new Date(date);
return true;
}
catch(e) {
return false;
}
}
YOU have to decide what form of dates you want to accept.
Then, once you know what forms you want to accept, you can then check the spec for new Date(str) or date.parse() on MDN and see if it supports exactly what you want and if it does the right things on error conditions (it probably will not). If not, then you will have to do some manual parsing.
If you want further help from us, you will need to specify what forms of date you want to accept.
There are also some browser differences as javascript has moved to support additional date formats and earlier browsers had some inconstencies between them which all means you'll want to build yourself a simple test script with a bunch of legal and illegal date format strings and see if your validity detection does what you want in several browsers. This isn't rocket science to get it right, but it's not trivial either and requires some work unless you only want to accept what the original date object supported (which is unlikely).
If this were my code, I'd probably decide that it's far less work to do manual parsing of your desired input format that you know with 100% certainty will work in all browsers because it's your own manual parsing. I'd probably use a regex to parse the date and then convert each component to a number and check each component for validity. You can then feed those numeric components to the Date constructor to create the Date object.
If you can tell by now, the built-in date class isn't very useful for user entered input. If you're willing to use a library for this, the date.js library has a ton of useful functionality in this regard.
Here's an example of a manual parsing function that accepts these US formats:
mm-dd-yyyy
mm dd yyyy
mm/dd/yyyy
JS Code:
function checkDate(str) {
var matches = str.match(/(\d{1,2})[- \/](\d{1,2})[- \/](\d{4})/);
if (!matches) return;
// parse each piece and see if it makes a valid date object
var month = parseInt(matches[1], 10);
var day = parseInt(matches[2], 10);
var year = parseInt(matches[3], 10);
var date = new Date(year, month - 1, day);
if (!date || !date.getTime()) return;
// make sure we have no funny rollovers that the date object sometimes accepts
// month > 12, day > what's allowed for the month
if (date.getMonth() + 1 != month ||
date.getFullYear() != year ||
date.getDate() != day) {
return;
}
return(date);
}
And a demo with some test cases: http://jsfiddle.net/jfriend00/xZmBY/
If you want the Euro format, it's a trivial matter to switch the code to that. In either case, you have to decide which format you accept, code for it and then communicate to the user which format is required. If you think this is messy, then perhaps you will see why so many sites use a date calendar picker that doesn't have this complexity.
Please correct or explain how my over-simplification is incorrect as I am not a JavaScript expert.
But I just need to know if an object is a valid date. This will only come from user input (ie, text box).
Here's why it's an oversimplification.
First of all, it sounds like you really want to check the validity of a string representation of a Date object. This is not particularly useful by itself, because you are going to want to use the date for something in your script, send it to the server, etc.
If you want to use the date in your script, there are caveats.
new Date('2020-10-10') // Fri Oct 09 2020 20:00:00 GMT-0400 (EDT)
If you want to pass it to the server, you'll need to do more than just check validity– you'll need to use a format that your server side code can interpret.
If that's the case, you could consider normalizing the string into a format of your choice. You'd want to be able to create equivalent dates from the normalized strings in both your client and server side code. For simplicity, the format can be human-readable (not a timestamp), and you can replace the value of the text input with the normalized string.
Checking the validity of the string can simply be a part of normalization... have the function return false or an empty string if the input was bad, don't change the text input's value, and instead show a message indicating that the value is invalid:
// assume `birthday` is a text input.
birthday.onblur = function() {
var dateString = normalizeDate(birthday.value);
if (dateString) {
validator.style.display = 'none';
birthday.value = dateString;
} else {
validator.style.display = 'block';
}
};
Here's an example of what the normalizeDate function might look like. This example uses the format 'yyyy-mm-dd', you can change it to suit your needs.
function normalizeDate(dateString) {
// If it's not at least 6 characters long (8/8/88), give up.
if (dateString.length && dateString.length < 6) {
return '';
}
var date = new Date(dateString),
month, day;
// If input format was in UTC time, adjust it to local.
if (date.getHours() || date.getMinutes()) {
date.setMinutes(date.getTimezoneOffset());
}
month = date.getMonth() + 1;
day = date.getDate();
// Return empty string for invalid dates
if (!day) {
return '';
}
// Return the normalized string.
return date.getFullYear() + '-' +
(month > 9 ? '' : '0') + month + '-' +
(day > 9 ? '' : '0') + day;
}
Here's the obligatory live demo.
new Date() doesn't throw an exception if month>12 for example, you can use Date.parse() and test the returned value with isNaN()

Categories

Resources