Skip to content

Instantly share code, notes, and snippets.

@weberste
Last active January 28, 2022 13:47
Show Gist options
  • Save weberste/354a3f0a9ea58e0ea0de to your computer and use it in GitHub Desktop.
Save weberste/354a3f0a9ea58e0ea0de to your computer and use it in GitHub Desktop.
Dates only with Angular-UI Bootstrap datepicker
app.directive('datepickerLocaldate', ['$parse', function ($parse) {
var directive = {
restrict: 'A',
require: ['ngModel'],
link: link
};
return directive;
function link(scope, element, attr, ctrls) {
var ngModelController = ctrls[0];
// called with a JavaScript Date object when picked from the datepicker
ngModelController.$parsers.push(function (viewValue) {
// undo the timezone adjustment we did during the formatting
viewValue.setMinutes(viewValue.getMinutes() - viewValue.getTimezoneOffset());
// we just want a local date in ISO format
return viewValue.toISOString().substring(0, 10);
});
// called with a 'yyyy-mm-dd' string to format
ngModelController.$formatters.push(function (modelValue) {
if (!modelValue) {
return undefined;
}
// date constructor will apply timezone deviations from UTC (i.e. if locale is behind UTC 'dt' will be one day behind)
var dt = new Date(modelValue);
// 'undo' the timezone offset again (so we end up on the original date again)
dt.setMinutes(dt.getMinutes() + dt.getTimezoneOffset());
return dt;
});
}
}]);
@karenli1995
Copy link

karenli1995 commented May 8, 2020

The above solutions only work for timezones West of the UTC Timezone. Here's a fix that also works for timezones East of UTC so that dates don't appear one day behind:

 app.directive('datepickerLocaldate', ['$parse', function ($parse) {
    var directive = {
        restrict: 'A',
        require: ['ngModel'],
        link: link
    };
    return directive;

    function link(scope, element, attr, ctrls) {
        var ngModelController = ctrls[0];

        // called once user picks a date from datepicker with a JavaScript Date object
        ngModelController.$parsers.push(function (viewValue) {
            // undo the timezone adjustment we did during the formatting
            viewValue.setMinutes(viewValue.getMinutes() - viewValue.getTimezoneOffset());

            // get a local date in ISO format
            var dateString = viewValue.toISOString().substring(0, 10);
            var dateParts = dateString.split("-");
            var newDate = new Date( dateParts[0], parseInt( dateParts[1] )-1, dateParts[2], 0, 0, 0 );

            if (viewValue.getTimezoneOffset() < 0) {
                //case for Timezones East of UTC (floored to account for Indian Standard Time Zone on 30 minute delineations)
                newDate.setHours(newDate.getHours() - Math.floor(newDate.getTimezoneOffset()/60));
            } else {
                //case for Timezones West of UTC
                return newDate;
            }

            return newDate;
        });

        // called once user saves changes on a Title and passes the Date we had picked in the datepicker
        ngModelController.$formatters.push(function (modelValue) {
            if (!modelValue) {
                return undefined;
            }
            // date constructor will apply timezone deviations from UTC (i.e. if locale is West of UTC 'dt' will be one day behind)
            var dt = new Date(modelValue);

            // 'undo' the timezone offset again (so we end up on the original date again)
            if (dt.getTimezoneOffset() < 0) {
                //case for Timezones East of UTC
                dt.setMinutes(dt.getMinutes() - dt.getTimezoneOffset());
            } else {
                //case for Timezones West of UTC
                dt.setMinutes(dt.getMinutes() + dt.getTimezoneOffset());
            }

            return dt;
        });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment