Permalink
Browse files

feat(ngModel): support conversion to timezone other than UTC

Closes #11005
  • Loading branch information...
shahata authored and petebacondarwin committed Feb 7, 2015
1 parent c0498d4 commit 0413bee8cc563a6555f8d42d5f183f6fbefc7350
Showing with 103 additions and 7 deletions.
  1. +12 −5 src/ng/directive/input.js
  2. +4 −2 src/ng/directive/ngModel.js
  3. +87 −0 test/ng/directive/inputSpec.js
View
@@ -1156,8 +1156,12 @@ function createDateInputType(type, regexp, parseDate, format) {
// parser/formatter in the processing chain so that the model
// contains some different data format!
var parsedDate = parseDate(value, previousDate);
if (timezone === 'UTC') {
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
if (timezone) {
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
if (!isNaN(requestedTimezoneOffset)) {
parsedDate = new Date(parsedDate.getTime());
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset() + requestedTimezoneOffset);
}
}
return parsedDate;
}
@@ -1170,9 +1174,12 @@ function createDateInputType(type, regexp, parseDate, format) {
}
if (isValidDate(value)) {
previousDate = value;
if (previousDate && timezone === 'UTC') {
var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
previousDate = new Date(previousDate.getTime() + timezoneOffset);
if (previousDate && timezone) {
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
if (!isNaN(requestedTimezoneOffset)) {
previousDate = new Date(previousDate.getTime());
previousDate.setMinutes(previousDate.getMinutes() + previousDate.getTimezoneOffset() - requestedTimezoneOffset);
}
}
return $filter('date')(value, format, timezone);
} else {
@@ -1097,8 +1097,10 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
`ngModel` as getters/setters.
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
* `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
* otherwise the default timezone of the browser will be used.
* `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
* continental US time zone abbreviations, but for general use, use a time zone offset, for
* example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
* If not specified, the timezone of the browser will be used.
*
* @example
@@ -613,6 +613,19 @@ describe('input', function() {
});
it('should use any timezone if specified in the options', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
helper.changeInputValueTo('2013-07');
expect(+$rootScope.value).toBe(Date.UTC(2013, 5, 30, 19, 0, 0));
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2014, 5, 30, 19, 0, 0));
});
expect(inputElm.val()).toBe('2014-07');
});
it('should label parse errors as `month`', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="val" name="alias" />', {
valid: false,
@@ -636,6 +649,17 @@ describe('input', function() {
expect(inputElm.val()).toBe('2013-12');
});
it('should only change the month of a bound date in any timezone', function() {
var inputElm = helper.compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2013, 6, 31, 20, 0, 0));
});
helper.changeInputValueTo('2013-09');
expect(+$rootScope.value).toBe(Date.UTC(2013, 7, 31, 20, 0, 0));
expect(inputElm.val()).toBe('2013-09');
});
describe('min', function() {
var inputElm;
beforeEach(function() {
@@ -814,6 +838,19 @@ describe('input', function() {
});
it('should use any timezone if specified in the options', function() {
var inputElm = helper.compileInput('<input type="week" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
helper.changeInputValueTo('2013-W03');
expect(+$rootScope.value).toBe(Date.UTC(2013, 0, 16, 19, 0, 0));
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2014, 0, 16, 19, 0, 0));
});
expect(inputElm.val()).toBe('2014-W03');
});
it('should label parse errors as `week`', function() {
var inputElm = helper.compileInput('<input type="week" ng-model="val" name="alias" />', {
valid: false,
@@ -990,6 +1027,30 @@ describe('input', function() {
});
it('should use any timezone if specified in the options', function() {
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
helper.changeInputValueTo('2000-01-01T06:02');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
$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');
});
it('should fallback to default timezone in case an unknown timezone was passed', function() {
var inputElm = helper.compileInput(
'<input type="datetime-local" ng-model="value1" ng-model-options="{timezone: \'WTF\'}" />' +
'<input type="datetime-local" ng-model="value2" />');
helper.changeGivenInputTo(inputElm.eq(0), '2000-01-01T06:02');
helper.changeGivenInputTo(inputElm.eq(1), '2000-01-01T06:02');
expect($rootScope.value1).toEqual($rootScope.value2);
});
it('should allow to specify the milliseconds', function() {
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value"" />');
@@ -1278,6 +1339,19 @@ describe('input', function() {
});
it('should use any timezone if specified in the options', function() {
var inputElm = helper.compileInput('<input type="time" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
helper.changeInputValueTo('23:02:00');
expect(+$rootScope.value).toBe(Date.UTC(1970, 0, 1, 18, 2, 0));
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(1971, 0, 1, 18, 2, 0));
});
expect(inputElm.val()).toBe('23:02:00.000');
});
it('should allow to specify the milliseconds', function() {
var inputElm = helper.compileInput('<input type="time" ng-model="value"" />');
@@ -1559,6 +1633,19 @@ describe('input', function() {
});
it('should use any timezone if specified in the options', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="value" ng-model-options="{timezone: \'+0500\'}" />');
helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(1999, 11, 31, 19, 0, 0));
$rootScope.$apply(function() {
$rootScope.value = new Date(Date.UTC(2000, 11, 31, 19, 0, 0));
});
expect(inputElm.val()).toBe('2001-01-01');
});
it('should label parse errors as `date`', function() {
var inputElm = helper.compileInput('<input type="date" ng-model="val" name="alias" />', {
valid: false,

0 comments on commit 0413bee

Please sign in to comment.