5

I implemented a CSV parser that guesses the type formats for each column but I have found that the JavaScript Date class believes "TG-1" is a valid date/time.

Is this some obscure date format I haven't seen before that Chrome supports? I wouldn't think this is a valid date and looking at different date ISO standards I haven't seen a reference to this.

Chrome 74 says it's valid.

Firefox 64 says it's not valid.

let validDate = true;
try{
   d = new Date("TG-1");
   d.toISOString()
}catch(e){
   validDate = false
}
console.log(validDate);

Any string followed by - and a number 1-12 is considered valid:

d = new Date("adsfadgag-12")//valid per V8
Boann
  • 48,794
  • 16
  • 117
  • 146
desean
  • 49
  • 6
  • 1
    No exception is thrown when you attempt to make a date with a nonsense string. You just get a Date object that doesn't work. – Pointy May 08 '19 at 16:06
  • It looks like the constructor is ignoring your `TG` bit and seeing `1` as `Jan` for `2001`. – Maximilian Burszley May 08 '19 at 16:07
  • See what `console.log(d)` shows you. – Pointy May 08 '19 at 16:07
  • Safari does not accept this either. – idmean May 08 '19 at 16:08
  • The "T" letter specify the following is time relative (cf ISO8601) – np42 May 08 '19 at 16:10
  • @Pointy It's an interesting question about Chrome's `Date` constructor. – Maximilian Burszley May 08 '19 at 16:10
  • 1
    @Nicolas it can be any arbitrary string followed by - d = new Date("adsfadgag-12") is valid – desean May 08 '19 at 16:11
  • @desean try looking at the Date object you get. – Pointy May 08 '19 at 16:12
  • https://stackoverflow.com/a/15110385/8188846 – Maximilian Burszley May 08 '19 at 16:13
  • It is extremely easy to explore this fascinating behavior in the browser console. Just type `var d = new Date("any string you care to type"); console.log(d)` and you'll see pretty much the same thing for any string that's not any sort of date. – Pointy May 08 '19 at 16:15
  • @desean you're really not reading these comments very closely. The dates you're making **are not valid**. You're expecting an exception that will **never** be thrown because that's not how the Date constructor behaves. – Pointy May 08 '19 at 16:16
  • @Pointy I missed a line in my code. I updated it to correctly throw the exception – desean May 08 '19 at 16:17
  • @desean ah OK, well the runtime is free to do whatever it wants with nonsense date strings. Firefox throws a `Range error` exception when you call `.toISOString()`. – Pointy May 08 '19 at 16:19
  • @Pointy Chrome also throws an exception when it is invalid d = new Date("TG1"); d.toISOString();//throws exception – desean May 08 '19 at 16:21
  • But `new Date("TG-1");` doesn't throw, it's a totally valid date in Chrome. – Keith May 08 '19 at 16:24
  • 1
    @Keith `d = new Date("adsfadgag-12")` // is also valid per V8 – desean May 08 '19 at 16:24
  • @desean right, and again, that's just what V8 does. The spec does not insist on any particular behavior when a Date is constructed from a non-ISO source string, so apparently V8 just makes something up. – Pointy May 08 '19 at 16:26
  • Yes, it's just trying it best to make a date, if the number is > 31, it's assuming that number is a year, if the number is below 13, it will assume it's a month.. Anthing between 13 & 31, is invalid. – Keith May 08 '19 at 16:27
  • @Pointy I opened a bug on chrome. In my opinion `d = new Date("NotAValidDate-1")` shouldn't be parsed as a valid date. I'm thinking they have a strange regex bug. – desean May 08 '19 at 16:28
  • @desean no they don't. Thats not a bug, thats a (legacy) feature. – Jonas Wilms May 08 '19 at 16:31

1 Answers1

1

To quote from the V8 sourcecode:

Legacy dates:

Any unrecognized word before the first number is ignored.

Parenthesized text is ignored.

An unsigned number followed by ':' is a time value, and is added to the TimeComposer. A number followed by '::' adds a second zero as well. A number followed by '.' is also a time and must be followed by milliseconds.

Any other number is a date component and is added to DayComposer. A month name (or really: any word having the same first three letters as a month name) is recorded as a named month in the Day composer. A word recognizable as a time-zone is recorded as such, as is (+|-)(hhmm|hh:).

Legacy dates don't allow extra signs ('+' or '-') or umatched ')' after a number has been read (before the first number, any garbage is allowed).

Intersection of the two: A string that matches both formats (e.g. 1970-01-01) will be parsed as an ES5 date-time string - which means it will default to UTC time-zone. That's unavoidable if following the ES5 specification.

After a valid "T" has been read while scanning an ES5 datetime string, the input can no longer be a valid legacy date, since the "T" is a garbage string after a number has been read.

In other words: This behaviour is not really planned, it's just that some browsers behaved like this somewhen, and therefore this weird behaviour has to be kept. Date(...) will try to parse nearly anything without complaining.

Community
  • 1
  • 1
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151