Moment converting digit into date - javascript

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.

Related

new Date() producing valid date from invalid input string [duplicate]

This question already has answers here:
Detecting an "invalid date" Date instance in JavaScript
(52 answers)
Closed 3 years ago.
When I pass "test 2" string in new Date(), I am getting an actual date, how?
I am trying to whether it is a date or not.
console.log(new Date("test 2"));
Passing a string to new Date is the same as using Date.parse.
When a non-standard date string is passed, the result is implementation-dependent; the browser can do whatever it wants, including guessing. On Chrome, your input results in a date, but not on Firefox (NaN is returned).
test isn't part of a date string, so it looks like Chrome just parses the 2:
console.log(new Date('2'));
console.log(new Date('1'));
console.log(new Date('0'));
Essentially, this is undefined behavior, so strange results aren't surprising. Unless the passed string conforms to the format defined in the specification - that is, something like "2011-10-10" or "2011-10-10T14:48:00" or "2011-10-10T14:48:00.000+09:00", the results are unpredictable.
Consider instead figuring out what sort of string format you'd be expecting as an input, and then checking if the format is followed with a regular expression. If so, pass to new Date and see if it gives you a meaningful results; otherwise, don't.
As per MDN:
The ECMAScript specification states: If the String does not conform to the standard format the function may fall back to any implementation–specific heuristics or implementation–specific parsing algorithm.
Google Chrome tries to parse your date and picks up the number as a month. Other browsers may reject the passed value or return something totally different.
Hence please consider the following note:
Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies.
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Parameters
From mdn:
A string representing a simplification of the ISO 8601 calendar date extended format (other formats may be used, but results are implementation-dependent).
You're encountering an implementation-specific attempt to parse your string as a date. It is not recommended to depend on this behaviour.
Because your test text includes a number. See, it's interpreting a number like 1 as January, 2 as February,3 as March, and so on.
new Date( "3")
will give you
Thu Mar 01 2001 00:00:00 GMT+0530 (India Standard Time)
If you use text with no number, e.g. new Date("test") it will throw invalid date.

Initialize JS date object from HTML date picker: incorrect date returned

How do you correctly intitialize a timezone-independent date (or I guess a date that is fixed to a single timezone across the html side and the JS side) from a html datepicker?
I have the following simple code, which is producing incorrect dates:
function printDate(){
let d = new Date(document.getElementById("date").value)
alert(d)
}
document.getElementById("printDate").addEventListener("click", e => printDate())
<html>
<body>
Print Date: <br><input type="date" id="date"> <button id="printDate">Add</button>
</body>
</html>
But at least on my computer, currently sitting in U.S. mountain time, it produces incorrect dates. I give it today's date (March 9, 2019), and it alerts yesterday's date in the following format: Fri Mar 08 2019 17:00:00 GMT-0700 (MST). How do I make it not do that?
I really just want it to assume that all input and all output are in GMT.
In a <input type="date" /> element, the selected date is displayed in the locale format, but the value property is always returned in yyyy-mm-dd format, as described in the MDN docs.
In other words, when you choose March 9, 2019, you may see 03/09/2019 from the US or 09/03/2019 in other parts of the world, but value is 2019-03-09 regardless of any time zone or localization settings. This is a good thing, as it allows you to work with the selected date in a standard ISO 8601 format, without trying to apply a time.
However, when you parse a date string in that format with the Date object's constructor (or with Date.parse), you run up against a known issue: The date is not treated as local time, but as UTC. This is the opposite of ISO 8601.
This is described in the MDN docs:
Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
It's also in the ECMAScript specification (emphasis mine):
... When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.
There was a debate about this in 2015, but ultimately it was decided that maintaining compatibility with existing behaviors was more important than being ISO 8601 compliant.
Going back to your question, the best thing to do would be to not parse it into a Date object if you don't need one. In other words:
function printDate(){
const d = document.getElementById("date").value;
alert(d);
}
If you really need a Date object, then the easiest option is to parse the value yourself:
function printDate(){
const parts = document.getElementById("date").value.split('-');
const d = new Date(+parts[0], parts[1]-1, +parts[2], 12);
alert(d);
}
Note the ,12 at the end sets the time to noon instead of midnight. This is optional, but it avoids situations of getting the wrong day when midnight doesn't exist in the local time zone where DST transitions at midnight (Brazil, Cuba, etc.).
Then there's your last comment:
I really just want it to assume that all input and all output are in GMT.
That's a bit different than what you showed. If really that's what you want, then you can construct the Date object as you previously did, and use .toISOString(), .toGMTString(), or .toLocaleString(undefined, {timeZone: 'UTC'})
function printDate(){
const d = new Date(document.getElementById("date").value); // will treat input as UTC
// will output as UTC in ISO 8601 format
alert(d.toISOString());
// will output as UTC in an implementation dependent format
alert(d.toGMTString());
// will output as UTC in a locale specific format
alert(d.toLocaleString(undefined, {timeZone: 'UTC'}));
}

JavaScript displaying correct date from dates stored as UTC on server

I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing. How do I go about displaying the correct time from UTC?
It appears that your json response contains a string valued which are in ISO8601 format in UTC, and then you are creating Date objects from them.
This part of your code is fine:
if (element.createdDate) element.createdDate = new Date(element.createdDate.toString());
You parse the string, and the resulting Date object is correct.
However, you don't need to use .toString() here, as the value is already a string. That is redundant.
This part of your code is the problem:
console.log("javascript date: " + new Date(element.depositDate.getUTCDate().toString()));
The getUTCDate function returns just the date of the month. Don't use that.
No matter what you do to create the Date object, ultimately you create a Date object and you're relying upon an implicit string conversion to output it. This will have different behavior in different browsers.
Consider console.log(new Date()):
In Chrome, this logs something like Fri Mar 17 2017 12:14:29 GMT-0700 (Pacific Daylight Time) on my computer. This is as if I called console.log(new Date().toString()); It is in an RFC 2822 like format (but not quite), and is represented in local time.
In Firefox, this logs something like 2017-03-17T19:14:46.535Z. This is as if I called console.log(new Date().toISOString()); It is in ISO8601 format, and is represented in UTC.
The point is, don't rely on implicit undefined behavior. If you must work with Date objects, then you should use console.log(element.createdDate.toISOString()) to see the ISO8601 representation of the UTC time.
If you're going to be doing a lot of things with dates and times, you may prefer to use a library, such as Moment.js, which can make tasks such as this more clear.
I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
2016-10-11T00:00:00Z and Mon Oct 10 2016 20:00:00 GMT-04:00 (EDT) are exactly the same moment in time. The only difference is that one is displayed in ISO 8601 extended format with timezone offset 00:00 and the other is displayed in an RFC 2822 (like) format with timezone offset -04:00 (and assumes a locality in the EDT region).
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing.
That is unusual. Typically it would return either a string or an error, but without a working example or any code to provide context it's impossible to say why.
How do I go about displaying the correct time from UTC?
You haven't specified what "correct" is. You are displaying a date and time for the same moment in time, just in a different format and time zone.

MomentJS - isValid() method is not validating correctly

I'm reading the document for MomentJS for validating a moment date created from a String.
The example they gave is:
1) moment("not a real date").isValid(); // false
but if I add 1 to the end of the String and validate it, I get:
2) moment("not a real date 1").isValid(); // true
Why is it that #2 is a valid moment date object?
Note that that constructor is now deprecated. But to answer the question:
This constructor turns around and passes the "not a real date 1" string into the Date constructor. Take a look at this:
In Chrome:
new Date("not a real date 1") --> Mon Jan 01 2001 00:00:00 GMT-0600 (Central Standard Time)
new Date("not a real date") --> Invalid Date
In IE11:
new Date("not a real date 1") --> [date] NaN[date] NaN
new Date("not a real date") --> [date] NaN[date] NaN
In FireFox 42:
new Date("not a real date 1") --> Invalid Date
new Date("not a real date") --> Invalid Date
So the answer is, it is validating correctly, and its a valid date object because the Date constructor successfully created a Date object. There's a bug in the Date constructor, at least in some browsers.
Edit:
Here's the relevant part of the ECMAScript 6 spec, emphasis mine:
If Type(v) is String, then
Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (20.3.3.2). If the parse resulted in an abrupt completion, tv is the Completion Record.
And then, section 20.3.3.2:
The function first attempts to parse the format of the String according to the rules (including extended years) called out in Date Time String Format (20.3.1.16). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats. Unrecognizable Strings or dates containing illegal element values in the format String shall cause Date.parse to return NaN.
So, since the spec explicitly allows the browser to creatively parse the string, I guess it's not a bug. Chrome just doesn't behave the same as the others.

javascript Date.parse assumes 31 days in February and all months?

It seems to me that Date.parse assumes all months have 31 days. Including months with 30 days and including February(which should only ever have 28/29 days).
I checked this question 31 days in February in Date object
But the answer there suggested there was nothing wrong with Date in his issue..Somebody said something to the questioner about zero indexing and he pretty much said "oh ok", and determined that it was his mistake and not a mistake of Date.
Another question Date is considering 31 days of month the guy was doing some subtraction was a number of lines of code and he seemed to not put the error down to Date in the end.
But this example that I have seems to be a bit different and more clear cut. It involves Date.parse and can be demonstrated with one/two lines of code.
Date.parse is aware that there are not 32 days in a month, that's good
Date.parse("2000-01-32");
NaN
But In February it thinks there can be 30 or 31 days
Date.parse("2013-02-30");
1362182400000
Date.parse("2013-02-31");
1362268800000
In fact it looks like it thinks all months have 31 days. That is really strange for a method that is meant to parse a date.
And there's no issue of zero indexing here. As Date.parse("...") doesn't use zero indexing (And even if it did, it wouldn't cause it tot make the error of thinking there are 31 days in February - that is more than one off!
Date.parse("01-00-2000");
NaN
Date.parse("00-01-2000");
NaN
According to the specification for Date.parse() (emphasis mine):
The function first attempts to parse the format of the String according to the rules called out in Date Time String Format. […] Unrecognisable Strings or dates containing illegal element values in the format String shall cause Date.parse to return NaN.
And according to the specification for Date Time String Format (emphasis mine):
ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 Extended Format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ
Where the fields are as follows: […] DDis the day of the month from 01 to 31.
Therefore, any date with a day of month greater than 31 is illegal and Date.parse() returns NaN.
Please notice that the standard defines a date format, not a date: the static method isn't required to make additional verifications, and everything else is implementation-specific. For instance, Date.parse('2013-02-30') and Date.parse('2013-04-31') both return NaN on Firefox.
The implementation differs between browsers. IE, Edge and Chrome will parse strings that doesn't represent actual dates, but Firefox will return NaN for those strings. The safe thing to do is to consider the result from Date.parse as undefined for date strings where the day falls outside the range of the month.
Browsers that allow parsing of non-existent dates will return a different date. Parsing "2015-04-31" will return the date 2015-05-01. This is the same behaviour as when using new Date(2015, 3, 31), where numbers out of range is allowed and will wrap around into a different month or year. That means that the result is still usable, if you don't mind that some invalid dates turn into other dates in some browsers.
The standard isn't very clear about what values are valid:
Illegal values (out-of-bounds as well as syntax errors) in a format
string means that the format string is not a valid instance of this
format.
The day component is defined as having a range from 1 to 31:
DD is the day of the month from 01 to 31.
However, the format is based on ISO 8601, and that is not a format for parsing strings into dates, that is a format for representing dates as string. Clearly you can't represent a date that doesn't even exist as a string.
Right, so how to check if a date string has a valid value?
with moment is very easy:
export function dateStringIsValid(aDateString){
return (moment(aDateString, "DD/MM/YYYY", true).isValid())
}

Categories

Resources