-
Notifications
You must be signed in to change notification settings - Fork 363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DateString type #1356
Add DateString type #1356
Conversation
I know there's been quite a bit of spitballing regarding this MySQL date issue, but it got me thinking about the idea of "DATE" type fields in databases, and how there's easily an argument for not wanting timezones to interfere with their use. If you were attempting to insert a birthday into a database, you wouldn't want the timezone offset to push that day forwards or backwards, right? This change would give users the ability to fall back on a string representation that still acts as a Date, and is still validated by the JS Date constructor, but without being converted to UTC. It would be on a per-property basis.
|
lib/model-builder.js
Outdated
@@ -526,10 +527,13 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett | |||
}; | |||
|
|||
// DataType for Date | |||
function DateType(arg) { | |||
function DateType(arg, props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the reasoning behind have this function both in dao
and modelBuilder
?
3f91003
to
eba167a
Compare
Still a work in progress. |
lib/date-string.js
Outdated
throw new Error('Input must be a string'); | ||
} | ||
// Preserve the reference for return via .toDate | ||
this.date = new Date(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows users to include the time in the value too, e.g. 2015-01-01T10:00:00.0Z
.
If we want to make this new type for dates only, then I am proposing to accept a single format yyyy-MM-dd
only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was calling it DateString to reflect that it's like a JS Date (which is actually a Date and Time), but in string form.
It's mostly meant to allow the passing of unmodified date/time strings to an underlying driver, which in MySQL's case just happens to be helpful for DATE.
lib/date-string.js
Outdated
* Return the equivalent Date object for this DateString. | ||
* @returns {Date} A JavaScript Date object | ||
*/ | ||
DateString.prototype.toDate = function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this function needs to be parameterized by the timezone we want to get the value in. Otherwise you can end up with the same problem when somebody calls toLocaleString
as you are trying to fix: if you were attempting to insert a birthday into a database, you wouldn't want the timezone offset to push that day forwards or backwards, right?
$ node
> new Date('2017-04-27').toLocaleString(undefined, {timeZone:'America/Toronto'})
'4/26/2017, 8:00:00 PM'
The snippet above shows what happens to value 2017-04-27
when it's displayed via toLocaleString()
by a computer located in Toronto (think of new DateString('2017-04-27').toDate().toLocaleString()
). Because my timezone is Europe/Prague
, I had to explicitly tell toLocaleString
to use a different one.
I think it may be better to not convert DateTime
values to Date
at all and let each connector to decide how to represent a date value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we avoid parsing the string into a Date object (at least internal to this structure) we then get saddled with the responsibility of validating the date string ourselves, don't we? I mostly added the .toDate function so that if anyone wants to get at the underlying date object, they can do so. In hindsight, it's probably an unnecessary gesture, since they can just say {instance}.date
to reference it.
@kjdelisle While I think it makes sense to have a special type representing values containing a date only, and then let each database connector to store them using a database-specific format, I personally don't think it's a fix for loopbackio/loopback-connector-mysql#149. |
BTW you should probably add at least You may want to consider adding |
It's not meant to fix the issue entirely by itself; it allows bypassing the Date issue on the forward pass. |
eba167a
to
709837b
Compare
lib/date-string.js
Outdated
|
||
DateString.prototype.toJSON = function() { | ||
return this.value; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bajtos Not sure about the best way to handle this currently. If I don't override this function with the implementation you see here, then the values that get passed along the chain end up feeding a stringified JSON object to the datasource layer (which explodes fantastically). This override does the trick, but it means no one can actually get the JSON representation of this object with this method (unless they util.inspect
it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand. Can you show some examples of what do you mean?
Here is my expectation:
expect(JSON.stringify({ when: new DateString('2017-04-28') }))
.to.equal('{"when": "2017-04-28T00:00:00Z"}');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add some unit-tests to cover .toJSON
and .toString
methods.
Is the anticipated use case for |
@bbito I'm hoping that this will be viable for any sort of datetime format that you don't want modified by LoopBack/JavaScript. It will still carry the backing Date object underneath if you really want the Date object that corresponds with it, but the default behaviour will just be validating that the string was any sort of valid date(time). |
That's tough because the timeless BTW, I pulled last night and I'm able to
|
709837b
to
5650d82
Compare
With the current iteration that I've pushed onto the PR branch, you could still compare the internal representations of the DateString objects if you really need to see a UTC-based comparison.
In this case, |
Currently struggling with this warning on app start, though: |
POST is working (sending the String only) after 5650d82, but GET without |
@kjdelisle it is Zero dates in MySQL that are crashing GET they are currently transformed to
I can push that, or if that Zero date handling will move to juggler or another module, I'll leave it alone. |
@bbito I think that will only apply to objects of type "Date"; this change will make them "DateString" instead. |
@kjdelisle Got it - this fixes my Zero date GET crashes, should I push it?
|
@bbito Go for it |
test/date-string.test.js
Outdated
var date = new DateString(theDate); | ||
date.value.should.eql(theDate); | ||
var d = new Date(theDate); | ||
date._date.toString().should.eql(d.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious: is there any difference if we compare with getTime()
instead of toString()
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getTime()
gives you the time in milliseconds; toString()
is the full datetime stamp that a Date object will generate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
In that case let's call it DateTimeString please. I am pretty sure I won't be the only person confused by the name |
I'm not sure why we would call it DateTime string if it's just the String representation of a JS Date object (literally, Date-String). Originally, I was going to call it DateAsString, but that seemed wordy and clumsy. |
I like DateAsString! |
84a432c
to
6938ce3
Compare
New type that preserves string input as a string, but ensures that the string is a valid Date. Additionally, provides a .toDate function to provide the Date object representation of the string.
6938ce3
to
5e80837
Compare
@slnode test please |
@kjdelisle To add JSdocs (apidocs.strongloop.com), you need to add Then just be aware that the API doc will not be published until this module is published to npm. |
Description
New type that preserves string input as a string, but ensures that
the string is a valid Date.
Additionally, provides a .toDate function to provide the Date
object representation of the string.
NOTE: This PR has changed from its original intent, so if you feel confused, you should know that you're not crazy. :)
Linked Issues
loopbackio/loopback-connector-mysql#149
Checklist
guide