Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0413bee

Browse files
shahatapetebacondarwin
authored andcommitted
feat(ngModel): support conversion to timezone other than UTC
Closes #11005
1 parent c0498d4 commit 0413bee

File tree

3 files changed

+103
-7
lines changed

3 files changed

+103
-7
lines changed

src/ng/directive/input.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -1156,8 +1156,12 @@ function createDateInputType(type, regexp, parseDate, format) {
11561156
// parser/formatter in the processing chain so that the model
11571157
// contains some different data format!
11581158
var parsedDate = parseDate(value, previousDate);
1159-
if (timezone === 'UTC') {
1160-
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
1159+
if (timezone) {
1160+
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1161+
if (!isNaN(requestedTimezoneOffset)) {
1162+
parsedDate = new Date(parsedDate.getTime());
1163+
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset() + requestedTimezoneOffset);
1164+
}
11611165
}
11621166
return parsedDate;
11631167
}
@@ -1170,9 +1174,12 @@ function createDateInputType(type, regexp, parseDate, format) {
11701174
}
11711175
if (isValidDate(value)) {
11721176
previousDate = value;
1173-
if (previousDate && timezone === 'UTC') {
1174-
var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
1175-
previousDate = new Date(previousDate.getTime() + timezoneOffset);
1177+
if (previousDate && timezone) {
1178+
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1179+
if (!isNaN(requestedTimezoneOffset)) {
1180+
previousDate = new Date(previousDate.getTime());
1181+
previousDate.setMinutes(previousDate.getMinutes() + previousDate.getTimezoneOffset() - requestedTimezoneOffset);
1182+
}
11761183
}
11771184
return $filter('date')(value, format, timezone);
11781185
} else {

src/ng/directive/ngModel.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -1097,8 +1097,10 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
10971097
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
10981098
`ngModel` as getters/setters.
10991099
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
1100-
* `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
1101-
* otherwise the default timezone of the browser will be used.
1100+
* `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
1101+
* continental US time zone abbreviations, but for general use, use a time zone offset, for
1102+
* example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
1103+
* If not specified, the timezone of the browser will be used.
11021104
*
11031105
* @example
11041106

test/ng/directive/inputSpec.js

+87
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,19 @@ describe('input', function() {
613613
});
614614

615615

616+
it('should use any timezone if specified in the options', function() {
617+
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
618+
619+
helper.changeInputValueTo('2013-07');
620+
expect(+$rootScope.value).toBe(Date.UTC(2013, 5, 30, 19, 0, 0));
621+
622+
$rootScope.$apply(function() {
623+
$rootScope.value = new Date(Date.UTC(2014, 5, 30, 19, 0, 0));
624+
});
625+
expect(inputElm.val()).toBe('2014-07');
626+
});
627+
628+
616629
it('should label parse errors as `month`', function() {
617630
var inputElm = helper.compileInput('<input type="month" ng-model="val" name="alias" />', {
618631
valid: false,
@@ -636,6 +649,17 @@ describe('input', function() {
636649
expect(inputElm.val()).toBe('2013-12');
637650
});
638651

652+
it('should only change the month of a bound date in any timezone', function() {
653+
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
654+
655+
$rootScope.$apply(function() {
656+
$rootScope.value = new Date(Date.UTC(2013, 6, 31, 20, 0, 0));
657+
});
658+
helper.changeInputValueTo('2013-09');
659+
expect(+$rootScope.value).toBe(Date.UTC(2013, 7, 31, 20, 0, 0));
660+
expect(inputElm.val()).toBe('2013-09');
661+
});
662+
639663
describe('min', function() {
640664
var inputElm;
641665
beforeEach(function() {
@@ -814,6 +838,19 @@ describe('input', function() {
814838
});
815839

816840

841+
it('should use any timezone if specified in the options', function() {
842+
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
843+
844+
helper.changeInputValueTo('2013-W03');
845+
expect(+$rootScope.value).toBe(Date.UTC(2013, 0, 16, 19, 0, 0));
846+
847+
$rootScope.$apply(function() {
848+
$rootScope.value = new Date(Date.UTC(2014, 0, 16, 19, 0, 0));
849+
});
850+
expect(inputElm.val()).toBe('2014-W03');
851+
});
852+
853+
817854
it('should label parse errors as `week`', function() {
818855
var inputElm = helper.compileInput('<input type="week" ng-model="val" name="alias" />', {
819856
valid: false,
@@ -990,6 +1027,30 @@ describe('input', function() {
9901027
});
9911028

9921029

1030+
it('should use any timezone if specified in the options', function() {
1031+
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
1032+
1033+
helper.changeInputValueTo('2000-01-01T06:02');
1034+
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
1035+
1036+
$rootScope.$apply(function() {
1037+
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
1038+
});
1039+
expect(inputElm.val()).toBe('2001-01-01T06:02:00.000');
1040+
});
1041+
1042+
1043+
it('should fallback to default timezone in case an unknown timezone was passed', function() {
1044+
var inputElm = helper.compileInput(
1045+
'<input type="datetime-local" ng-model="value1" ng-model-options="{timezone: \'WTF\'}" />' +
1046+
'<input type="datetime-local" ng-model="value2" />');
1047+
1048+
helper.changeGivenInputTo(inputElm.eq(0), '2000-01-01T06:02');
1049+
helper.changeGivenInputTo(inputElm.eq(1), '2000-01-01T06:02');
1050+
expect($rootScope.value1).toEqual($rootScope.value2);
1051+
});
1052+
1053+
9931054
it('should allow to specify the milliseconds', function() {
9941055
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value"" />');
9951056

@@ -1278,6 +1339,19 @@ describe('input', function() {
12781339
});
12791340

12801341

1342+
it('should use any timezone if specified in the options', function() {
1343+
var inputElm = helper.compileInput('<input type="time" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
1344+
1345+
helper.changeInputValueTo('23:02:00');
1346+
expect(+$rootScope.value).toBe(Date.UTC(1970, 0, 1, 18, 2, 0));
1347+
1348+
$rootScope.$apply(function() {
1349+
$rootScope.value = new Date(Date.UTC(1971, 0, 1, 18, 2, 0));
1350+
});
1351+
expect(inputElm.val()).toBe('23:02:00.000');
1352+
});
1353+
1354+
12811355
it('should allow to specify the milliseconds', function() {
12821356
var inputElm = helper.compileInput('<input type="time" ng-model="value"" />');
12831357

@@ -1559,6 +1633,19 @@ describe('input', function() {
15591633
});
15601634

15611635

1636+
it('should use any timezone if specified in the options', function() {
1637+
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
1638+
1639+
helper.changeInputValueTo('2000-01-01');
1640+
expect(+$rootScope.value).toBe(Date.UTC(1999, 11, 31, 19, 0, 0));
1641+
1642+
$rootScope.$apply(function() {
1643+
$rootScope.value = new Date(Date.UTC(2000, 11, 31, 19, 0, 0));
1644+
});
1645+
expect(inputElm.val()).toBe('2001-01-01');
1646+
});
1647+
1648+
15621649
it('should label parse errors as `date`', function() {
15631650
var inputElm = helper.compileInput('<input type="date" ng-model="val" name="alias" />', {
15641651
valid: false,

0 commit comments

Comments
 (0)