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

fix(dateFilter, input): fix Date parsing in IE/Edge when timezone offset contains : #13887

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,10 @@ function fromJson(json) {
}


var ALL_COLONS = /:/g;
function timezoneToOffset(timezone, fallback) {
// IE/Edge do not "understand" colon (`:`) in timezone
timezone = timezone.replace(ALL_COLONS, '');
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
}
Expand All @@ -1230,8 +1233,9 @@ function addDateMinutes(date, minutes) {

function convertTimezoneToLocal(date, timezone, reverse) {
reverse = reverse ? -1 : 1;
var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
var dateTimezoneOffset = date.getTimezoneOffset();
var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
}


Expand Down
2 changes: 1 addition & 1 deletion src/ng/filter/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ function dateFilter($locale) {

var dateTimezoneOffset = date.getTimezoneOffset();
if (timezone) {
dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
date = convertTimezoneToLocal(date, timezone, true);
}
forEach(parts, function(value) {
Expand Down
115 changes: 70 additions & 45 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,17 +628,22 @@ 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\'}" />');
they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
var ngModelOptions = "{timezone: '" + tz + "'}";
var inputElm = helper.compileInput(
'<input type="month" ng-model="value" ng-model-options="' + ngModelOptions + '" />');

helper.changeInputValueTo('2013-07');
expect(+$rootScope.value).toBe(Date.UTC(2013, 5, 30, 19, 0, 0));
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');
});
$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() {
Expand Down Expand Up @@ -865,17 +870,22 @@ 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\'}" />');
they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
var ngModelOptions = "{timezone: '" + tz + "'}";
var inputElm = helper.compileInput(
'<input type="week" ng-model="value" ng-model-options="' + ngModelOptions + '" />');

helper.changeInputValueTo('2013-W03');
expect(+$rootScope.value).toBe(Date.UTC(2013, 0, 16, 19, 0, 0));
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');
});
$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() {
Expand Down Expand Up @@ -1066,17 +1076,22 @@ 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\'}" />');
they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
var ngModelOptions = "{timezone: '" + tz + "'}";
var inputElm = helper.compileInput(
'<input type="datetime-local" ng-model="value" ng-model-options="' + ngModelOptions + '" />');

helper.changeInputValueTo('2000-01-01T06:02');
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
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');
});
$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() {
Expand Down Expand Up @@ -1390,17 +1405,22 @@ 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\'}" />');
they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
var ngModelOptions = "{timezone: '" + tz + "'}";
var inputElm = helper.compileInput(
'<input type="time" ng-model="value" ng-model-options="' + ngModelOptions + '" />');

helper.changeInputValueTo('23:02:00');
expect(+$rootScope.value).toBe(Date.UTC(1970, 0, 1, 18, 2, 0));
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');
});
$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() {
Expand Down Expand Up @@ -1697,17 +1717,22 @@ 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\'}" />');
they('should use any timezone if specified in the options (format: $prop)',
{'+HHmm': '+0500', '+HH:mm': '+05:00'},
function(tz) {
var ngModelOptions = "{timezone: '" + tz + "'}";
var inputElm = helper.compileInput(
'<input type="date" ng-model="value" ng-model-options="' + ngModelOptions + '" />');

helper.changeInputValueTo('2000-01-01');
expect(+$rootScope.value).toBe(Date.UTC(1999, 11, 31, 19, 0, 0));
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');
});
$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() {
Expand Down
33 changes: 17 additions & 16 deletions test/ng/filter/filtersSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

describe('filters', function() {

var filter;

beforeEach(inject(function($filter) {
Expand Down Expand Up @@ -165,13 +164,12 @@ describe('filters', function() {
}));
});


describe('number', function() {
var number;

beforeEach(inject(function($rootScope) {
beforeEach(function() {
number = filter('number');
}));
});


it('should do basic filter', function() {
Expand Down Expand Up @@ -270,17 +268,16 @@ describe('filters', function() {
});

describe('date', function() {

var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.001Z'); //7am
var noon = new angular.mock.TzDate(+5, '2010-09-03T17:05:08.012Z'); //12pm
var midnight = new angular.mock.TzDate(+5, '2010-09-03T05:05:08.123Z'); //12am
var earlyDate = new angular.mock.TzDate(+5, '0001-09-03T05:05:08.000Z');
var secondWeek = new angular.mock.TzDate(+5, '2013-01-11T12:00:00.000Z'); //Friday Jan 11, 2012
var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.001Z'); //7am
var noon = new angular.mock.TzDate(+5, '2010-09-03T17:05:08.012Z'); //12pm
var midnight = new angular.mock.TzDate(+5, '2010-09-03T05:05:08.123Z'); //12am
var earlyDate = new angular.mock.TzDate(+5, '0001-09-03T05:05:08.000Z');
var secondWeek = new angular.mock.TzDate(+5, '2013-01-11T12:00:00.000Z'); //Friday Jan 11, 2013
var date;

beforeEach(inject(function($filter) {
date = $filter('date');
}));
beforeEach(function() {
date = filter('date');
});

it('should ignore falsy inputs', function() {
expect(date(null)).toBeNull();
Expand Down Expand Up @@ -456,7 +453,6 @@ describe('filters', function() {
expect(date(morning, 'yy/xxx')).toEqual('10/xxx');
});


it('should support various iso8061 date strings with timezone as input', function() {
var format = 'yyyy-MM-dd ss';

Expand All @@ -479,7 +475,6 @@ describe('filters', function() {
expect(date('2003-09-10T13Z', format)).toEqual('2003-09-' + localDay + ' 00');
});


it('should parse iso8061 date strings without timezone as local time', function() {
var format = 'yyyy-MM-dd HH-mm-ss';

Expand Down Expand Up @@ -514,7 +509,13 @@ describe('filters', function() {
});

it('should support conversion to any timezone', function() {
expect(date(new Date(Date.UTC(2003, 8, 10, 3, 2, 4)), 'yyyy-MM-dd HH-mm-ssZ', 'GMT+0500')).toEqual('2003-09-10 08-02-04+0500');
var dateObj = new Date(Date.UTC(2003, 8, 10, 3, 2, 4));
var format = 'yyyy-MM-dd HH-mm-ssZ';

expect(date(dateObj, format, '+0500')).toEqual('2003-09-10 08-02-04+0500');
expect(date(dateObj, format, '+05:00')).toEqual('2003-09-10 08-02-04+0500');
expect(date(dateObj, format, 'GMT+0500')).toEqual('2003-09-10 08-02-04+0500');
expect(date(dateObj, format, 'GMT+05:00')).toEqual('2003-09-10 08-02-04+0500');
});

it('should fallback to default timezone in case an unknown timezone was passed', function() {
Expand Down