dreamRs / shinyWidgets

shinyWidgets : Extend widgets available in shiny
https://dreamrs.github.io/shinyWidgets/
GNU General Public License v3.0
828 stars 153 forks source link

airDatepicker shifts time by loosing timezone information #643

Open kotarak opened 1 year ago

kotarak commented 1 year ago

I'm using release 0.8.0 of shinyWidgets.

I encountered the following issue: I set the initial value of a airDatepicker with lubridate::now(). Then I immediately read out the value without interacting in any way with the widget. The returned value is different from the original value. Example (first line initial value, second line retrieved value):

[1] "2023-10-18 09:16:10 UTC"
[2] "2023-10-18 11:16:10 UTC"

Note the two hour shift.

I tracked this down to anytime::anytime. When setting the initial value, dayjs converts the time to the local time of the client, which seems desirable, because the user is not confused. When reading out the value, dayjs still returns a local time with a timezone offset.

> dayjs(dayjs("2023-10-18 09:16:10 UTC").toDate()).format()
'2023-10-18T11:16:10+02:00'

See here and here.

This string is then passed to anytime::anytime, which ignores the timezone offset and simply uses - I presume - the server timezone.

> anytime::anytime('2023-10-18T11:16:10+02:00')
[1] "2023-10-18 11:16:10 UTC"

See here.

lubridate on the other hand does the right thing.

> lubridate::ymd_hms('2023-10-18T11:16:10+02:00')
[1] "2023-10-18 09:16:10 UTC"

I have not found a way to make anytime::anytime respect the timezone shift. I would also not be in favour of changing the dayjs part to UTC, because I want my users to see their local time. If anytime cannot be coerced into proper cooperation, I would suggest a switch to another library like lubridate.

Disclaimer: I'm not familiar with the intricacy of date formating, but the timezone offset is also part of ISO8601. So I would take libraries, which silently ignore the timezone shift, with a lot of caution.

hdmm3 commented 5 months ago

I'm having a similar issue when calling updateAirDateInput(). The input datetime is never the one returned by the widget. This seems to happen only when the shiny server is running at a different timezone as the client. On the server side the timezone is picked through Sys.timezone() here and then that date is shifted to the client timezone. If both client and server timezones are the same they will coincide, but if they don't, the incorrect shifting will happen. A quick way to test this issue is by calling something like this:

updateAirDateInput(
   inputId = "theDateInput",
   value = input$theDateInput
)

Which should not change the value, but if the server and client timezones are different, the value will keep shifting the datetime at every call. Different timezones between server and client can be tested locally by running a rocker image with the app, which is set to UTC by default. The shiny client will pick your local timezone from the browser.

pvictor commented 1 month ago

Hello, I have added support for timezone through dayjs in dev version and added a tz = argument in airDatepickerInput() and updateAirDateInput(). I will try to make more tests with different timezones between server and client before releasing on CRAN.

Victor