Skip to content

Commit

Permalink
fix(input): allow overriding timezone for date input types
Browse files Browse the repository at this point in the history
This commit also fixes a bug where part of the Date object
was re-used even after the input was emptied.

Fixes angular#16181
Closes angular#13382
  • Loading branch information
Narretz committed Nov 21, 2017
1 parent aa3f951 commit d172e8e
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/ng/directive/input.js
Expand Up @@ -1431,17 +1431,20 @@ function createDateInputType(type, regexp, parseDate, format) {
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
badInputChecker(scope, element, attr, ctrl);
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
var timezone = ctrl && ctrl.$options.getOption('timezone');
var previousDate;

ctrl.$$parserName = type;
ctrl.$parsers.push(function(value) {
if (ctrl.$isEmpty(value)) return null;
if (ctrl.$isEmpty(value)) {
previousDate = null;
return null;
}
if (regexp.test(value)) {
// Note: We cannot read ctrl.$modelValue, as there might be a different
// parser/formatter in the processing chain so that the model
// contains some different data format!
var parsedDate = parseDate(value, previousDate);
var timezone = ctrl.$options.getOption('timezone');
if (timezone) {
parsedDate = convertTimezoneToLocal(parsedDate, timezone);
}
Expand All @@ -1456,6 +1459,7 @@ function createDateInputType(type, regexp, parseDate, format) {
}
if (isValidDate(value)) {
previousDate = value;
var timezone = ctrl.$options.getOption('timezone');
if (previousDate && timezone) {
previousDate = convertTimezoneToLocal(previousDate, timezone, true);
}
Expand Down
110 changes: 110 additions & 0 deletions test/ng/directive/inputSpec.js
Expand Up @@ -662,6 +662,21 @@ describe('input', function() {
});


it('should be possible to override the timezone', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('2013-07');
expect(+$rootScope.value).toBe(Date.UTC(2013, 6, 1));

inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});

$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2014, 6, 1));
});
expect(inputElm.val()).toBe('2014-06');
});


they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
Expand Down Expand Up @@ -931,6 +946,21 @@ describe('input', function() {
});


it('should be possible to override the timezone', function() {
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('2013-W03');
expect(+$rootScope.value).toBe(Date.UTC(2013, 0, 17));

inputElm.controller('ngModel').$overrideModelOptions({timezone: '+5000'});

$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2014, 0, 17));
});
expect(inputElm.val()).toBe('2014-W04');
});


they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
Expand Down Expand Up @@ -1137,6 +1167,25 @@ describe('input', function() {
});


it('should be possible to override the timezone', function() {
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('2000-01-01T01:02');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));

inputElm.controller('ngModel').$overrideModelOptions({timezone: '+0500'});
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
});
expect(inputElm.val()).toBe('2001-01-01T06:02:00.000');

inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});

helper.changeInputValueTo('2000-01-01T01:02');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
});


they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
Expand Down Expand Up @@ -1482,6 +1531,25 @@ describe('input', function() {
});


it('should be possible to override the timezone', function() {
var inputElm = helper.compileInput('<input type="time" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('23:02:00');
expect(+$rootScope.value).toBe(Date.UTC(1970, 0, 1, 23, 2, 0));

inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(1971, 0, 1, 23, 2, 0));
});
expect(inputElm.val()).toBe('18:02:00.000');

inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
helper.changeInputValueTo('23:02:00');
// The year is still set from the previous date
expect(+$rootScope.value).toBe(Date.UTC(1971, 0, 1, 23, 2, 0));
});


they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
Expand Down Expand Up @@ -1794,6 +1862,24 @@ describe('input', function() {
});


it('should be possible to override the timezone', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1));

inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2001, 0, 1));
});
expect(inputElm.val()).toBe('2000-12-31');

inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 19));
});


they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
Expand Down Expand Up @@ -1879,6 +1965,30 @@ describe('input', function() {
dealoc(formElm);
});

it('should not reuse the hour part of a previous date object after emptying the input', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');

helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1));

// Change the timezone offset so that the display date is a day earlier
// This does not change the model, but our implementation
// internally caches a Date object with this offset
// and re-uses it if part of the date changes
inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2001, 0, 1));
});
expect(inputElm.val()).toBe('2000-12-31');

// Emptying the input should clear the cached date object
helper.changeInputValueTo('');

inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 0));
});

describe('min', function() {

it('should invalidate', function() {
Expand Down

0 comments on commit d172e8e

Please sign in to comment.