bootstrap icon indicating copy to clipboard operation
bootstrap copied to clipboard

Datepicker popup UTC Timezone issue

Open msosa opened this issue 8 years ago • 18 comments

Bug description:

I've noticed a weird issue when using the UTC timezone. For users west of UTC, like NY, adding the ng-model-options to UTC things work as they should.

However when you set your local timezone to something like UTC+2 and you open the popup that contains the ng-model-options, the date is highlighted incorrectly to the day before. The popup without the ng-model-options highlights the day correctly

Link to minimally-working plunker that reproduces the issue:

http://plnkr.co/edit/Y28iutmgkWkCINTUvRoq?p=preview

The first popup is the one without the ng model options, the second one contains it.

Version of Angular, UIBS, and Bootstrap

Angular: 1.5.8 UIBS: 2.1.3 Bootstrap: 3.3.6

msosa avatar Sep 13 '16 17:09 msosa

Another thing I just noticed is if you select a date from the popup X amount of times where X * (your offset) = more than 24 hours, on that click it will select the wrong date.

The offset seems to be constantly getting added and never zeroed out

msosa avatar Sep 13 '16 20:09 msosa

+1

mark-mccullough avatar Sep 20 '16 21:09 mark-mccullough

Unfortunately there seems to be some issues with the timezone handling since 2.0.0 but your first post sounds like the same root cause as this issue that I just filed: https://github.com/angular-ui/bootstrap/issues/6252

Try setting your ng-model-options on a parent element of the input (instead of on the input itself), and see if that works.

antch avatar Sep 21 '16 21:09 antch

Hi,

I tried to track down the origin of this issue. It seems to come from https://github.com/angular-ui/bootstrap/blob/997813f0eba41971c948d0ea4c9c9c21542bccd7/src/datepickerPopup/popup.js#L336

In UIBS 1.3.x the conversion was dateParser.toTimezone(...) and it is now dateParser.fromTimezone(...) in 2.2.0.

The date converted here was created by dateParser.parse, which used new Date(...)so the date uses the browser timezone. It makes no sense to read this date from the ngModelOptions timezone, but you probably want to convert it from the browser timezone to the ngModelOptions timezone.

Changing the line back to dateParser.toTimezone(...) does the trick for me.

It would be nice if someone from the UIBS team can look into this issue and review the workaround I suggest.

noullet avatar Oct 28 '16 13:10 noullet

@noullet this sounds correct - pushing change shortly.

wesleycho avatar Nov 27 '16 10:11 wesleycho

This did not seem to fix any of the two issues, am I doing something wrong? Here is new plunk with updated UIB code.

http://plnkr.co/edit/i2yg2cwHg7GC28Z7FhcC?p=preview

The date on the popup is still incorrect and clicking the date multiple times will still change the date.

msosa avatar Dec 12 '16 17:12 msosa

Reopening to investigate.

wesleycho avatar Dec 12 '16 17:12 wesleycho

I mistakenly believed that my issue had the same root as you @msosa, but it seems to be a third Timezone issue, independent from yours, sorry for the confusion...

noullet avatar Dec 12 '16 17:12 noullet

Seems that using ng-model-options="{timezone: 'utc'}" is not working with angular 1.6.x. Could be cause by this breaking change in angular:

ngModelOptions: Due to 296cfc, the programmatic API for ngModelOptions has changed. You must now read options via the ngModelController.$options.getOption(name) method, rather than accessing the option directly as a property of the ngModelContoller.$options object. One benefit of these changes, though, is that the ngModelControler.$options property is now guaranteed to be defined so there is no need to check before accessing.

This does not affect the usage in templates and only affects custom directives that might have been reading options for their own purposes. If you were programmatically accessing the options, you need to change your code as follows:

Before: var myOption = ngModelController.$options && ngModelController.$options['my-option']; After: var myOption = ngModelController.$options.getOption('my-option');

avainola avatar Jan 12 '17 11:01 avainola

Yes this is problem after this change. I debug the problem on example of Bootstrap Datepicker version 2.3.1. In file ui-bootstrap-tpls in line 3044 they use return dateParser.toTimezone(date, ngModelOptions.timezone) but the timezone is undefined so the date is parse invalid. We will must use ngModelOptions.getOption('timezone').

But it can be also a problem for other libraries that use access to model options directly by object not by getter.

ksiwak2e avatar Jan 27 '17 18:01 ksiwak2e

I'm not sure if it's related to any or all of the issues presented here but there's still definitely an issue with the latest version (v2.5) and ngModelOptions.timezone. I set ng-model-options="{ timezone: 'UTC' }" on the uib-datepicker-popup (and on a parent element as well so that it propagates to the picker), and if I set my system time to 1am in a TZ just east of the UTC line, the dates do not sync up from the popup to the input box. The input box appears correct, whereas the popup does not let me select the current day.

antch avatar Feb 24 '17 22:02 antch

We also see problems with the datepicker popup in 2.5.0 (2.4.0 is fine, we're thinking that https://github.com/angular-ui/bootstrap/commit/0d79005f8d1f4d674bb04ba93c41bb9c06280b4f is the cause):

screen shot 2017-03-07 at 11 14 08

We have ng-model-options="{ timezone: 'UTC' }" on our body element and are using UTC Date objects in our application.

robert-iddink avatar Mar 07 '17 10:03 robert-iddink

We also have a similar problem with datepicker and UTC settings.

When we're in GMT -X, then the value set for ng-model is correct, but value displayed in text box is incorrect, is shifted by X (e.g. if we select 10-10-2000 and we're in GMT-5 timezone, then in text box we received 09-10-2000, because the date is shifted by -5 hours, ng-model contains correct value)

datepicker

sygnowskip avatar May 12 '17 07:05 sygnowskip

I'm also having a similar problem.

on Angular 1.6.1 UIBS 2.5.0

I have defined ng-model-options in various places trying to get this to work. I have a desire to make all of my application show in UTC, so I configured that and it's working across all time zones.

The issue is if I set a time and move to another timezone then I have issues.

The first attachment is in the creation timezone image

the second is in a timezone offset that screws it up image

DakJack avatar May 25 '17 20:05 DakJack

I'm also having same @DakJack's problem, Angular 1.6.1 UIBS 2.5.0 and UIBS 2.4.0

My model come from Mysql, for example: 2017-06-23,

but I resolved parsing with uibDateParser.

$scope.dateTest = uibDateParser.parse($scope.dateTest , 'yyyy-MM-dd', new Date());

dynshon avatar Jun 06 '17 16:06 dynshon

Any news here?

kifirkin avatar Feb 15 '18 20:02 kifirkin

I am using global datefilter decorator for setting timezone. Also ng-model-options set to timezone: '+0300'.

If current local timezone differs from those above, datepicker active date doesnt work correct, cause it uses start and end of te day in local timezone

$provide.decorator('dateFilter', ['$delegate', '$injector', ($delegate, $injector) => {
    const delegate = $delegate;

    return function (date, format, timezone) {
        if (angular.isUndefined(timezone)) {
            timezone = '+0300';
        }

        return delegate.apply(this, [date, format, timezone]);
    };
}]);

kifirkin avatar Feb 16 '18 11:02 kifirkin

You'll find below how I found and solved my issues, hope this will help!

Problem The popover version of uib-datepicker doesn't work well in combination with ng-model-options timezone in some timezones (e.g. negative timezones such as EST), including the highlight of "today", the minDate option...

My context

  • All dates come from my server in UTC, stored at midnight since I'm interested only in the year/month/hour part of the date. Btw, I strongly recommend doing that.
  • I use the UIB datepicker popover with ng-model-options="{timezone: 'utc'}"
  • I use angular 1.5.8 and UIB 2.2.0
  • My application is used by browsers all around the world, so any browser timezone should be supported.

Investigation I decided to make it work. Thanks to #6671, I found out that the inline version seemed to work fine but not the popover, so I debugged the two.

The first step consisted in understand how the popover worked. For the inline version, the ng-model and the calendar are the same element, all managed by UibDatepickerController which directly accesses the model. For the popover version, it's different: the ng-model and the calendar are separated: the ng-model is managed by UibDatepickerPopupController, which "wraps" the inline version and its UibDatepickerController. In this case, the ng-model is not accessed directly by UibDatepickerController. UibDatepickerPopupController manages a local date variable in its scope to make the link between the ng-model and UibDatepickerController.

The first issue I found is that the ng-model-options are not passed in this process, so when using the inline version, UibDatepickerController uses the ng-model-options, while when using the popover version, UibDatepickerPopupController uses it but UibDatepickerController does not.

Fixing this is easy, great I'm done!

Actually, not so much... Indeed, I think the developers never got this "working" version, so they based their testing on erroneous premises. Thus, fixing the issue revealed all the code that did not take into account properly the conversion from and to the ng-model-options timezone.

Solution I tried to track down all these conversion mistakes and fix them. Here is the resulting commit, with an attempt to explain every change, including the option passing and the conversions: https://github.com/icescrum/iceScrum/commit/6b50b31d8ca665225b8006141abb737f3a5994b3#diff-27473a0b13f7d143a7153fb573f056c2

Disclaimer

  • Do not use my file as is, as it was already heavily customized before I commited that. I can't afford maintaining a fork that only adds these fixes to the latest UIB, but feel free to do that.
  • It fixes all my issues but I did not try using HTML5 date type, and I did not try the "today" button.
  • I am not sure this will work with angular 1.6 and UIB 2.5, but only minor adaptations should be required.

Let me know if it works for you!

noullet avatar Apr 05 '18 16:04 noullet