Angular UI DatePicker adjusting for timezone

AngularjsDatepickerTimezoneAngular Ui

Angularjs Problem Overview


I have a date stored as a Date in SQL Server. The date shows 4/24/2014 when I query in SQL. That is correct. The date is correctly brought over to the client side in UTC. To edit that date we're using the Angular UI DatePicker. The DatePicker is adjusting that date based on my local timezone and so it is always off by one day.

I can see that it's happening. If we were editing a DateTime instead of a Date, then it would be correct to adjust for the timezone. However, in this case, I just have a Date, so I don't care about timezone and I just want to edit the date as it was in the database.

I can verify that it's adjusting for timezone. If I change the timezone on my windows machine to be UTC then the DatePicker does show the correct date.

So, the question is, is there a way to tell the DatePicker to turn off the timezone adjustments and just manage dates in UTC format so that it will work with a SQL Date instead of a SQL Datetime?

Angularjs Solutions


Solution 1 - Angularjs

I had a very similar problem a while ago: I wanted to store local dates on the server side (i.e. just yyyy-mm-dd and no timezome/time information) but since the Angular Bootstrap Datepicker uses the JavaScript Date object this was not possible (it serializes to a UTC datetime string in the JSON as you found out yourself).

I solved the problem with this directive: https://gist.github.com/weberste/354a3f0a9ea58e0ea0de

Essentially, I'm reformatting the value whenever a date is selected on the datepicker (this value, a yyyy-mm-dd formatted string, will be stored on the model) and whenever the model is accessed to populate the view, I need to wrap it in a Date object again so datepicker handles it properly.

Solution 2 - Angularjs

Solution found here: https://github.com/angular-ui/bootstrap/issues/4837#issuecomment-203284205

> The timezone issue is fixed. > > You can use: > > ng-model-options="{timezone: 'utc'}" > > To get a datepicker without timezone calculation.

EDIT: This solution does not work since version 2.x, however it did perfectly fine until then. I couldn't find a workaround and still am using version 1.3.3.

EDIT 2: As Sébastien Deprez pointed out in the comments below, this has been fixed in version 2.3.1. I just tested it and it works great.

<input
 uib-datepicker-popup
 ng-model="$ctrl.myModel"
 ng-model-options="{timezone: 'utc'}">

Solution 3 - Angularjs

First I'd like to point out that the bootstrap's localized date picker is stupid and useless, nobody needs something like this, all you really want is a date yyyy-MM-dd, I see no point in localizing a date when you don't need time.

I don't try to bend the client side to fit the server's timezone, that's overkill and doesn't work. What I do instead is let the user work in it's timezone and format the date before sending it to the server like this:

fields.date = dateFilter(trans.date, 'MM/dd/yy');

This ensures that whatever the user sees in the date picker I receive on the server side. Crucial if you ask me. If you need to set min and max dates, again, just set them in the user's timezone like this:

$scope.datepickerOptions.minDate = new Date(dateFilter(minDate, 'yyyy-MM-dd\'T\'00:00:00', serverTimezone));
$scope.datepickerOptions.maxDate = new Date(dateFilter(maxDate, 'yyyy-MM-dd\'T\'00:00:00', serverTimezone));

minDate and maxDate are server localized dates and the serverTimezone is the server's timezone offset ('+0500' for example).

Hope this helps!

Solution 4 - Angularjs

Setting timezone to null worked like a charm for me. It just keeps the selected date as it is.

ng-model-options="{timezone: null}"

Note: Tested on all timezones & the uib version I'm using is 1.3.3

Solution 5 - Angularjs

Hope below directive is useful to you

app.directive('datetimepickerNeutralTimezone', function () {
    return {
        restrict: 'A',
        priority: 1,
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$formatters.push(function (value) {
                if (typeof value === "undefined") {
                    var date = new Date();
                    //date = new Date(date.getTime() + (60000 * date.getTimezoneOffset()));
                    return date;
                } else {
                    var date = new Date(Date.parse(value));
                    //date = new Date(date.getTime() + (60000 * date.getTimezoneOffset()));
                    return date;
                }
            });

            ctrl.$parsers.push(function (value) {
                var date = new Date(value.getTime() - (60000 * value.getTimezoneOffset()));
                return date;
            });
        }
    };
});

app.directive('timepickerNeutralTimezone', function () {
    return {
        restrict: 'A',
        priority: 1,
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$formatters.push(function (value) {
                if (typeof value === "undefined") {
                } else {
                    var date = new Date(Date.parse(value));
                    date = new Date(date.getTime() + (60000 * date.getTimezoneOffset()));
                    return date;
                }
            });

            ctrl.$parsers.push(function (value) {
                var date = new Date(value.getTime() - (60000 * value.getTimezoneOffset()));
                return date;
            });
        }
    };
});

Solution 6 - Angularjs

For me, because we use a very old version of the library, and given an object expiration_date returned by the datepicker, I had to find a workaround and tweaked it like that :

expiration_date.setMinutes(-expiration_date.getTimezoneOffset());

Which will set the requested date to its corresponding UTC date but still expressed in local timezone format.

For me it worked well. Hope it can help someone.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrianView Question on Stackoverflow
Solution 1 - AngularjswebersteView Answer on Stackoverflow
Solution 2 - AngularjsThomasView Answer on Stackoverflow
Solution 3 - AngularjsvalmarvView Answer on Stackoverflow
Solution 4 - AngularjsTushar WalzadeView Answer on Stackoverflow
Solution 5 - AngularjsPranav LabheView Answer on Stackoverflow
Solution 6 - AngularjsBastien AlexandreView Answer on Stackoverflow