-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
feat(datepicker): add DateAdapter and NativeDateAdapter #4148
Conversation
* @param date The date to extract the day of the week from. | ||
* @returns The month component (0-indexed, 0 = Sunday). | ||
*/ | ||
abstract getDay(date: D): number; |
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.
Call this getDayOfTheWeek
so that it can't possibly be mixed up with getDate
?
|
||
/** | ||
* Gets a list of names for the months. | ||
* @param style The naming style (e.g. long = 'January', short = 'Jan', narrow = 'J'). |
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.
style
-> maybe format
?
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 called it style
because I don't want people confusing it with the format: any
that they would pass to the parse
or format
functions
* @param date The date of month of the date. | ||
* @returns The new date. | ||
*/ | ||
abstract create(year: number, month: number, date: number): D; |
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.
Make this createDate
so that in the future we can add createTime
and createDatetime
?
* @param locale The locale of the value. | ||
* @returns The parsed date, or null if date could not be parsed. | ||
*/ | ||
abstract parse(value: any, fmt?: any, locale?: any): D | null; |
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.
Should value
not always be a string?
Can you elaborate more on what the format is meant to be here?
* @param amount The number of years, months, and days to add (may be negative). | ||
* @returns A new date equal to the original with the given amount of time added. | ||
*/ | ||
abstract add(date: D, amount: {years?: number, months?: number, days?: number}): D; |
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.
Related: https://momentjs.com/guides/#/lib-concepts/date-time-math/
amount
-> timespan
?
It's worth thinking about whether we want to separate the logic for adding "date spans" (years, months, days) versus "time spans" (maybe be hours, minutes, seconds, but eventually boils down to milliseconds). If not, then the single add
could surprise people because the order of operations will affect the outcome. E.g., adding "1 month" will be a variable number of days based on where you are in the year. If it's broken up, then this method should probably be something like addDateSpan
with addTimeSpan
being added later.
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.
Hmm interesting... I assumed moment added years first then months then days, like how I do for Date
, but it seems it does the opposite order. Do you think I should add largest unit first, smallest unit first, or only allow adding 1 unit at a time and force the user to determine the order?
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.
Only adding one unit at a time is probably the only way to ensure that it does exactly what the user expects (e.g., addYears
, addMonths
, etc.). If we assume any kind of order of operations, I'd want to run a quick question by Google's i18n experts as to how they would say it should behave.
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'm also noticing that moment and closure seem to add what I'm calling 'calendarDays', 'calendarMonths', and 'calendarYears' here: https://github.com/angular/material2/blob/datepicker/src/lib/datepicker/calendar.ts#L271 I think I'll make add do that to be more in line with these other libraries
} | ||
|
||
|
||
/** Adapts the native JS Date for use with material components that work with dates. */ |
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.
Don't mention material specifically here since this will go in the cdk.
} | ||
|
||
getMonthNames(style: 'long' | 'short' | 'narrow', locale?: any): string[] { | ||
let dtf = new Intl.DateTimeFormat(locale, {month: style}); |
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.
Since NativeDateAdapter
will be the default if the user does nothing, we still have to support Intl
not being available for Safari 9 (...probably? We should ask devrel for an opinion on this, since omitting the strings would be nice for payload size).
* @returns {boolean} Whether the two dates are equal. | ||
* Null dates are considered equal to other null dates. | ||
*/ | ||
equals(first: D | null, second: D | null): boolean { |
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.
Similar comment as above for equals
and compare
: you'll want different things for the time variants. Maybe just call them compareDate
and sameDate
?
expect(adapter.create(50, -12 * 51, 1).getFullYear()).toBe(-1); | ||
}); | ||
|
||
it('should get today\'s date', () => { |
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.
optional: you can use double quotes (or template string backticks) when it's to avoid escaping single quotes
* @returns `min` if `date` is less than `min`, `max` if date is greater than `max`, | ||
* otherwise `date`. | ||
*/ | ||
clamp(date: D, min?: D | null, max?: D | null): D { |
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.
Same thing about date vs. time/datetime
00c94de
to
d5aa3f3
Compare
comments addressed, PTAL |
* @param fmt The format to use for the result string. | ||
* @returns The parsed date, or null if date could not be parsed. | ||
*/ | ||
abstract format(date: D, fmt?: any): string; |
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.
With this one format method, are we going to be able to get the different formats we need for date / time / datetime?
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 think this should be ok Intl.DateTimeFormat
, moment.js
, and goog.date.Date
all support this
* @returns A new date equal to the given date. | ||
*/ | ||
clone(date: D): D { | ||
return this.createDate(this.getYear(date), this.getMonth(date), this.getDate(date)); |
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.
Would it be better to leave this without an implementation here so that the method can be used for all of date/time/datetime?
'October', 'November', 'December' | ||
], | ||
'short': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], | ||
'narrow': ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'] |
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.
By hard-coding the values into the return, you'll end up creating a new instance of these arrays each time the method is called. Move this object into a constant?
@@ -0,0 +1,242 @@ | |||
import {NativeDateAdapter} from './native-date-adapter'; | |||
|
|||
|
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.
In the material1 tests, I used constants for month indices to make the tests easier to read:
// When constructing a Date, the month is zero-based. This can be confusing, since people are
// used to seeing them one-based. So we create these aliases to make reading the tests easier.
var JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9,
NOV = 10, DEC = 11;
Then your tests look like
expect(adapter.getYear(new Date(2017, JAN, 1))).toBe(2017);
Make a similar change here?
comments addressed |
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
* added DateAdapter and NativeDateAdapter * add tests * addressed some comments * more comments addressed * another round of comments addressed * add default formats
* added DateAdapter and NativeDateAdapter * add tests * addressed some comments * more comments addressed * another round of comments addressed * add default formats
* added DateAdapter and NativeDateAdapter * add tests * addressed some comments * more comments addressed * another round of comments addressed * add default formats
* added DateAdapter and NativeDateAdapter * add tests * addressed some comments * more comments addressed * another round of comments addressed * add default formats
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
No description provided.