Skip to content

Commit 6b21e54

Browse files
committed
fix(input): allow overriding timezone for date input types
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
1 parent b7bb797 commit 6b21e54

File tree

2 files changed

+117
-2
lines changed

2 files changed

+117
-2
lines changed

src/ng/directive/input.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1468,11 +1468,13 @@ function createDateInputType(type, regexp, parseDate, format) {
14681468
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
14691469
badInputChecker(scope, element, attr, ctrl, type);
14701470
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
1471-
var timezone = ctrl && ctrl.$options.getOption('timezone');
14721471
var previousDate;
14731472

14741473
ctrl.$parsers.push(function(value) {
1475-
if (ctrl.$isEmpty(value)) return null;
1474+
if (ctrl.$isEmpty(value)) {
1475+
previousDate = null;
1476+
return null;
1477+
}
14761478
if (regexp.test(value)) {
14771479
// Note: We cannot read ctrl.$modelValue, as there might be a different
14781480
// parser/formatter in the processing chain so that the model
@@ -1489,6 +1491,7 @@ function createDateInputType(type, regexp, parseDate, format) {
14891491
}
14901492
if (isValidDate(value)) {
14911493
previousDate = value;
1494+
var timezone = ctrl.$options.getOption('timezone');
14921495
if (previousDate && timezone) {
14931496
previousDate = convertTimezoneToLocal(previousDate, timezone, true);
14941497
}
@@ -1532,6 +1535,8 @@ function createDateInputType(type, regexp, parseDate, format) {
15321535

15331536
function parseDateAndConvertTimeZoneToLocal(value, previousDate) {
15341537
var parsedDate = parseDate(value, previousDate);
1538+
var timezone = ctrl.$options.getOption('timezone');
1539+
15351540
if (!isNaN(parsedDate) && timezone) {
15361541
parsedDate = convertTimezoneToLocal(parsedDate, timezone);
15371542
}

test/ng/directive/inputSpec.js

+110
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,21 @@ describe('input', function() {
718718
});
719719

720720

721+
it('should be possible to override the timezone', function() {
722+
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
723+
724+
helper.changeInputValueTo('2013-07');
725+
expect(+$rootScope.value).toBe(Date.UTC(2013, 6, 1));
726+
727+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
728+
729+
$rootScope.$apply(function() {
730+
$rootScope.value = new Date(Date.UTC(2014, 6, 1));
731+
});
732+
expect(inputElm.val()).toBe('2014-06');
733+
});
734+
735+
721736
they('should use any timezone if specified in the options (format: $prop)',
722737
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
723738
function(tz) {
@@ -1004,6 +1019,21 @@ describe('input', function() {
10041019
});
10051020

10061021

1022+
it('should be possible to override the timezone', function() {
1023+
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
1024+
1025+
helper.changeInputValueTo('2013-W03');
1026+
expect(+$rootScope.value).toBe(Date.UTC(2013, 0, 17));
1027+
1028+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '+5000'});
1029+
1030+
$rootScope.$apply(function() {
1031+
$rootScope.value = new Date(Date.UTC(2014, 0, 17));
1032+
});
1033+
expect(inputElm.val()).toBe('2014-W04');
1034+
});
1035+
1036+
10071037
they('should use any timezone if specified in the options (format: $prop)',
10081038
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
10091039
function(tz) {
@@ -1229,6 +1259,25 @@ describe('input', function() {
12291259
});
12301260

12311261

1262+
it('should be possible to override the timezone', function() {
1263+
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
1264+
1265+
helper.changeInputValueTo('2000-01-01T01:02');
1266+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
1267+
1268+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '+0500'});
1269+
$rootScope.$apply(function() {
1270+
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
1271+
});
1272+
expect(inputElm.val()).toBe('2001-01-01T06:02:00.000');
1273+
1274+
inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
1275+
1276+
helper.changeInputValueTo('2000-01-01T01:02');
1277+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
1278+
});
1279+
1280+
12321281
they('should use any timezone if specified in the options (format: $prop)',
12331282
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
12341283
function(tz) {
@@ -1591,6 +1640,25 @@ describe('input', function() {
15911640
});
15921641

15931642

1643+
it('should be possible to override the timezone', function() {
1644+
var inputElm = helper.compileInput('<input type="time" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
1645+
1646+
helper.changeInputValueTo('23:02:00');
1647+
expect(+$rootScope.value).toBe(Date.UTC(1970, 0, 1, 23, 2, 0));
1648+
1649+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
1650+
$rootScope.$apply(function() {
1651+
$rootScope.value = new Date(Date.UTC(1971, 0, 1, 23, 2, 0));
1652+
});
1653+
expect(inputElm.val()).toBe('18:02:00.000');
1654+
1655+
inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
1656+
helper.changeInputValueTo('23:02:00');
1657+
// The year is still set from the previous date
1658+
expect(+$rootScope.value).toBe(Date.UTC(1971, 0, 1, 23, 2, 0));
1659+
});
1660+
1661+
15941662
they('should use any timezone if specified in the options (format: $prop)',
15951663
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
15961664
function(tz) {
@@ -1920,6 +1988,24 @@ describe('input', function() {
19201988
});
19211989

19221990

1991+
it('should be possible to override the timezone', function() {
1992+
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
1993+
1994+
helper.changeInputValueTo('2000-01-01');
1995+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1));
1996+
1997+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
1998+
$rootScope.$apply(function() {
1999+
$rootScope.value = new Date(Date.UTC(2001, 0, 1));
2000+
});
2001+
expect(inputElm.val()).toBe('2000-12-31');
2002+
2003+
inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
2004+
helper.changeInputValueTo('2000-01-01');
2005+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 19));
2006+
});
2007+
2008+
19232009
they('should use any timezone if specified in the options (format: $prop)',
19242010
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
19252011
function(tz) {
@@ -2005,6 +2091,30 @@ describe('input', function() {
20052091
dealoc(formElm);
20062092
});
20072093

2094+
it('should not reuse the hour part of a previous date object after emptying the input', function() {
2095+
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
2096+
2097+
helper.changeInputValueTo('2000-01-01');
2098+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1));
2099+
2100+
// Change the timezone offset so that the display date is a day earlier
2101+
// This does not change the model, but our implementation
2102+
// internally caches a Date object with this offset
2103+
// and re-uses it if part of the date changes
2104+
inputElm.controller('ngModel').$overrideModelOptions({timezone: '-0500'});
2105+
$rootScope.$apply(function() {
2106+
$rootScope.value = new Date(Date.UTC(2001, 0, 1));
2107+
});
2108+
expect(inputElm.val()).toBe('2000-12-31');
2109+
2110+
// Emptying the input should clear the cached date object
2111+
helper.changeInputValueTo('');
2112+
2113+
inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
2114+
helper.changeInputValueTo('2000-01-01');
2115+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 0));
2116+
});
2117+
20082118
describe('min', function() {
20092119

20102120
it('should invalidate', function() {

0 commit comments

Comments
 (0)