bootstrap
bootstrap copied to clipboard
Datepicker popup UTC Timezone issue
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
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
+1
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.
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 this sounds correct - pushing change shortly.
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.
Reopening to investigate.
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...
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');
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.
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.
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):
We have ng-model-options="{ timezone: 'UTC' }"
on our body element and are using UTC Date objects in our application.
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)
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
the second is in a timezone offset that screws it up
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());
Any news here?
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]);
};
}]);
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!