Refactor (and redesign?) parseDate()
See original GitHub issue@iamkun Here is the issue with my comments, following the discussion in #417.
https://github.com/iamkun/dayjs/blob/a7e05e0b7fa529e8d81ebec3f007eb817d970fdd/src/index.js#L53-L61
Here I want to get rid of the warning eslint-disable-next-line no-cond-assign
, I think that is not good style. Also, the check whether there is a z
in the end of the string or not does not need to be a regex, which is also hinted by the comment looking for a better way
. I propose these changes:
if (typeof date === 'string' && !date.toLowerCase().endsWith('z')) {
const d = date.match(C.REGEX_PARSE)
if (d) {
return new Date(d[1], d[2] - 1, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, d[7] || 0)
}
}
this also gets rid of the let reg
in the first line of parseDate
, moving the variable down where it is needed, renaming it to just d
as reg
was also quite inprecise as this is not a regex but rather matched parts of a date.
https://github.com/iamkun/dayjs/blob/a7e05e0b7fa529e8d81ebec3f007eb817d970fdd/src/index.js#L63
Here the comment is misleading. This is not the default return for timestamps only, but all of the following inputs will end up in this last return statement:
parseDate({}) // objects
(invalid)parseDate(function() {}) // function
(invalid)parseDate(Infinity) // non-finite number
(invalid)parseDate(12345) // finite number
(valid, interpreted as unix timestamp)parseDate('Mon Jan 01 2018 00:00:00 GMT+0100 (Mitteleuropäische Normalzeit)') // RFC 2822 date string
(valid)parseDate(() => '2018-01-01') // arrow func
(valid in Chrome, invalid in Firefox)parseDate([2018, 1, 1]) // Array
(valid in both Firefox and Chrome!)
So I got two issues with this:
- The comment is misleading and most of the cases I mention above are not explicitly tested by the dayjs test suite
- We do not abstract the Date constructor default behavior, even causing incosistencies between different browsers
In my opinion, the second point is what I expect dayjs to do - provide a clear and straightforward API to create dates without any weird special cases. Instead almost everything is forwarded to the Date constructor, and adding more complexity even:
new Date(null)
is fine in standard Javascript (and equivalent tonew Date(0)
, so 1970-01-01T00:00:00.000, butnull
is not allowed with dayjs- dayjs also allows for all the moment.js special strings like
20180313
or20180313 12:24:33
- … but in other cases dayjs is not compatible with moment.js (e.g.
moment({})
is now, wheredayjs({})
is invalid) - most of the special cases (RFC2822 strings, momentjs-like-strings etc.) are not documented in the API documentation
So what is the overall design goal here? Should it be a 100% compatible with moment.js? Or should it abstract from weird browser behavior? Both is not given, and it might be confusing to the user.
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (8 by maintainers)
Top GitHub Comments
I pushed a PR to first refactor the code and write tests for everything that was not explicitly tested.
To make my second point clearer maybe: I have no specific proposal, I just think the dayjs parser specification has no clear specification.
a) You can parse almost anything the default
Date()
constructor defined in ECMASfript can parse, except for one value:null
(Javascript will treat it asnew Date(0)
). So we are not 100% consistent with Javascripts Date parsing functionality b) You can parse some special strings that are not default Javascript, the specification taken from moment.js (so for exampleparseDate('20180501')
orparseDate('2018-4-1 13:4:33')
work). But it is not 100% consistent with moment.js, as the kind of broken regex in dayjs also matches these values as valid:'2018-041 13:4:33'
(mixed dash and no-dash for month and day)'2018-041XXXXXXXXXXX13:4:33'
(between date and time, everything except for numbers is allowed with a*
) Those are not accepted by moment.js, so we have an incosistency. c) when falling through to the default constructor, we are again inconsistent with moment.js as moment.js for example treats the empty object as now (moment({})
), butdayjs({})
treats the empty object as invalidSo my point is: dayjs is neither completely consistent with the ECMAScript specification nor with moment.js. We should think about what is allowed and what is forbidden and find a design rationale that gives orientation here. I think it would be a good idea to be at least completely consistent with moment.js, but that requires some breaking changes and a lot of additional tests.
see my comments in #487 of why we can’t put everything into
new Date
pls