-
Notifications
You must be signed in to change notification settings - Fork 15
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: Javascript DatePicker Implementation #667
Changes from 45 commits
6d8433e
72fdecf
70a3886
f5b48ef
73131cc
8f86f73
1bc8a2b
5f7663d
fbdf5c8
924c795
863e20d
cbf58d2
79b1ee4
438e1ba
c0ca90e
0d6f1a9
e3bf54b
8e9be6c
25a92ea
8461dce
4480e6b
150db78
9e87c6a
c489445
fe4f2f0
e6650b3
82c1425
2733b1e
53a50cd
f9b4978
44b6ce5
e5d65e1
b1c1fba
4784e12
afdf9a4
d97643e
84ea457
3b1bc5e
a68597d
ea349ce
dac5a6f
c2f00c5
4fd4365
910d544
5462e82
7a86f21
183b620
9c6a007
c399f1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Note: I have a PR to introduce a new format string that is ZDT specific, but there has been enough arguing that I have not pushed it forward. deephaven/deephaven-core#5069 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per discussion, we are going to default datetime strings to ZDT. Then update the documentation to clarify which value input types will produce which output types. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the widget has a way to select a time zone via clicking. I can imagine that this would be useful. The adobe docs don't seem to mention it, so it might not be available. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the DatePicker will display a timezone but does not allow to change it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The key java time type that is not included in this widget is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a question about what return values should result from string inputs. There was a very long discussion around this topic when we created the query language time and calendar library. Ultimately, we decided to make everything as java time centric as possible. As a result, almost all return types are Java time types. There are a few cases where local-date-strings can be provided as inputs and they will return local-date-strings as outputs, but I think these were only included to make it easier to work with tables using strings as date columns -- which is very common. As a result, I think it is least confusing to always return a java time value. If there is a compelling case to do something different, we should discuss that specific case. Having said that, it doesn't look like we have exposed the string formatting methods (e.g. https://github.com/deephaven/deephaven-core/blob/main/engine/time/src/main/java/io/deephaven/time/DateTimeUtils.java#L4273) in python. (https://deephaven.io/core/pydoc/code/deephaven.time.html). Do we need to do this? Notes:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per discussion, we are going to stick with Java date types. User can convert to python / strings as needed. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
# Date Picker | ||
|
||
Date Pickers allow users to select a Date and Time from a pop up Calendar. | ||
|
||
## Example | ||
|
||
```python | ||
from deephaven import ui | ||
|
||
dp = ui.date_picker( | ||
label="Date Picker", | ||
default_value="2024-01-02T10:30:00 UTC", | ||
on_change=print, | ||
) | ||
mofojed marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
## Date types | ||
|
||
The date picker accepts the following date types as inputs: | ||
`None`, `LocalDate`, `ZoneDateTime`, `Instant`, `int`, `str`, `datetime.datetime`, `numpy.datetime64`, `pandas.Timestamp` | ||
|
||
The input will be converted to one of three Java date types: | ||
|
||
1. `LocalDate`: A LocalDate is a date without a time zone in the ISO-8601 system, such as "2007-12-03" or "2057-01-28". | ||
This will create a date picker with a granularity of days. | ||
2. `Instant`: An Instant represents an unambiguous specific point on the timeline, such as 2021-04-12T14:13:07 UTC. | ||
This will create a date picker with a granularity of seconds in UTC. The time zone will be rendered as the time zone in user settings. | ||
3. `ZonedDateTime`: A ZonedDateTime represents an unambiguous specific point on the timeline with an associated time zone, such as 2021-04-12T14:13:07 America/New_York. | ||
This will create a date picker with a granularity of seconds in the specified time zone. The time zone will be rendered as the specified time zone. | ||
|
||
The input is coverted according to the following rules: | ||
|
||
1. If the input is one of the three Java date types, use that type. | ||
2. A date string such as "2007-12-03" will parse to a `LocalDate` | ||
3. A string with a date, time, and timezone such as "2021-04-12T14:13:07 America/New_York" will parse to a `ZonedDateTime` | ||
4. All other types will attempt to convert in this order: `Instant`, `ZonedDateTime`, `LocalDate` | ||
|
||
The format of the date picker and the type of the value passed to the `on_change` handler | ||
is determined by the type of the following props in order of precedence: | ||
|
||
1. `value` | ||
2. `default_value` | ||
3. `placeholder_value` | ||
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do they get an error if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried this in various permutations.
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be good to have more specifics on these parameters here. They are included in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In
There needs to be a discussion about which is most appropriate and for what reason. The docs then need to be very clear on the default. Notes: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comes from the Spectrum docs:
So it must be defaulting to the local machine time zone. |
||
|
||
If none of these are provided, the `on_change` handler will be passed an `Instant`. | ||
|
||
## Controlled mode with value | ||
|
||
Setting the `value` prop will put the date_picker in controlled mode. Selecting a new date will call the `on_change` callback. | ||
Then `value` must be updated programatically to render the new value. This can be done using the `use_state` hook. | ||
|
||
```python | ||
from deephaven import ui | ||
from deephaven.time import to_j_local_date, dh_today, to_j_instant, to_j_zdt | ||
|
||
zoned_date_time = to_j_zdt("1995-03-22T11:11:11.23142 America/New_York") | ||
instant = to_j_instant("2022-01-01T00:00:00 ET") | ||
local_date = to_j_local_date(dh_today()) | ||
|
||
|
||
@ui.component | ||
def date_picker_test(value): | ||
date, set_date = ui.use_state(value) | ||
return [ui.date_picker(on_change=set_date, value=date), ui.text(str(date))] | ||
|
||
|
||
zoned_date_picker = date_picker_test(zoned_date_time) | ||
instant_date_picker = date_picker_test(instant) | ||
local_date_picker = date_picker_test(local_date) | ||
``` | ||
|
||
## Uncontrolled mode with default_value | ||
|
||
If the `value` prop is omitted, the date_picker will be in uncontrolled mode. It will store its state internally and automatically update when a new date is selected. | ||
In this mode, setting the `default_value` prop will determine the initial value displayed by the date_picker. | ||
|
||
```python | ||
from deephaven.time import dh_now | ||
from deephaven import ui | ||
|
||
dp = ui.date_picker( | ||
label="Date Picker", | ||
default_value=dh_now(), | ||
on_change=print, | ||
) | ||
``` | ||
|
||
## Uncontrolled mode with placeholder_value | ||
|
||
If both `value` and `default_value` are omitted, the date_picker will be in uncontrolled mode displaying no date selected. When opened, the date picker will suggest the date from the `placeholder_value` prop. | ||
Omitting `placeholder_value` will default it to today at the current time on the server machine time zone. | ||
|
||
```python | ||
from deephaven import ui | ||
|
||
dp1 = ui.date_picker( | ||
label="Date Picker", | ||
placeholder_value="2022-10-01T08:30:00 ET", | ||
on_change=print, | ||
) | ||
|
||
dp2 = ui.date_picker( | ||
label="Date Picker", | ||
on_change=print, | ||
) | ||
``` | ||
|
||
## Events | ||
|
||
Date Pickers accept a value to display and can trigger actions based on events such as setting state when changed. See the [API Reference](#api-reference) for a full list of available events. | ||
|
||
## Variants | ||
|
||
Date Pickers can have different variants to indicate their purpose. | ||
|
||
```python | ||
from deephaven import ui | ||
|
||
|
||
@ui.component | ||
def date_picker_variants(): | ||
return [ | ||
ui.date_picker(description="description"), | ||
ui.date_picker(error_message="error", validation_state="valid"), | ||
ui.date_picker(error_message="error", validation_state="invalid"), | ||
ui.date_picker(min_value="2024-01-01", max_value="2024-01-05"), | ||
ui.date_picker(value="2024-07-27T16:10:10 America/New_York", hour_cycle=24), | ||
ui.date_picker(granularity="YEAR"), | ||
ui.date_picker(granularity="MONTH"), | ||
ui.date_picker(granularity="DAY"), | ||
ui.date_picker(granularity="HOUR"), | ||
ui.date_picker(granularity="MINUTE"), | ||
ui.date_picker(granularity="SECOND"), | ||
] | ||
|
||
|
||
date_picker_variants_example = date_picker_variants() | ||
``` | ||
mofojed marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+112
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be split into timezone, validation and granulariy sections. Docs are expected to be exhaustive and there are several concepts and sections from: https://react-spectrum.adobe.com/react-spectrum/DatePicker.html that are missing |
||
|
||
## Time table filtering | ||
|
||
Date Pickers can be used to filter tables with time columns. | ||
|
||
```python | ||
from deephaven.time import dh_now | ||
from deephaven import time_table, ui | ||
|
||
|
||
@ui.component | ||
def date_table_filter(table, start_date, end_date, time_col="Timestamp"): | ||
after_date, set_after_date = ui.use_state(start_date) | ||
before_date, set_before_date = ui.use_state(end_date) | ||
return [ | ||
ui.date_picker(label="Start Date", value=after_date, on_change=set_after_date), | ||
ui.date_picker(label="End Date", value=before_date, on_change=set_before_date), | ||
table.where(f"{time_col} >= after_date && {time_col} < before_date"), | ||
] | ||
|
||
|
||
SECONDS_IN_DAY = 86400 | ||
today = dh_now() | ||
_table = time_table("PT1s").update_view( | ||
["Timestamp=today.plusSeconds(SECONDS_IN_DAY*i)", "Row=i"] | ||
) | ||
date_filter = date_table_filter(_table, today, today.plusSeconds(SECONDS_IN_DAY * 10)) | ||
``` | ||
|
||
## API Reference | ||
|
||
```{eval-rst} | ||
.. dhautofunction:: deephaven.ui.date_picker | ||
``` |
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 interface feels like it has an incomplete integration with the existing time libraries. In particular, business calendars are not supported. Business calendars could be used to limit selected dates or times, they can be used to get a appropriate time zone, etc. Business calendars could be added as a future enhancement, but I wanted to note it here.
https://deephaven.io/core/pydoc/code/deephaven.calendar.html
https://github.com/deephaven/deephaven-core/blob/main/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java
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.
We're looking at adding the unavailable dates afterwards: #698
Didn't want that to hold up the the rest of the date picker.