aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/JSON.js43
-rw-r--r--src/ng/filter/filters.js24
-rw-r--r--src/ngMock/angular-mocks.js266
-rw-r--r--test/JsonSpec.js52
-rw-r--r--test/ng/filter/filtersSpec.js32
5 files changed, 201 insertions, 216 deletions
diff --git a/src/JSON.js b/src/JSON.js
index 21d526c2..cddfc52d 100644
--- a/src/JSON.js
+++ b/src/JSON.js
@@ -1,7 +1,5 @@
'use strict';
-var array = [].constructor;
-
/**
* @ngdoc function
* @name angular.toJson
@@ -35,46 +33,11 @@ function toJson(obj, pretty) {
function fromJson(json, useNative) {
if (!isString(json)) return json;
- var obj;
-
- if (useNative && window.JSON && window.JSON.parse) {
- obj = JSON.parse(json);
- } else {
- obj = parseJson(json, true)();
- }
- return transformDates(obj);
-
- // TODO make forEach optionally recursive and remove this function
- // TODO(misko): remove this once the $http service is checked in.
- function transformDates(obj) {
- if (isString(obj) && 15 <= obj.length && obj.length <= 24) {
- return jsonStringToDate(obj);
- } else if (isArray(obj) || isObject(obj)) {
- forEach(obj, function(val, name) {
- obj[name] = transformDates(val);
- });
- }
- return obj;
- }
+ return (useNative && window.JSON && window.JSON.parse)
+ ? JSON.parse(json)
+ : parseJson(json, true)();
}
-var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
-function jsonStringToDate(string){
- var match;
- if (match = string.match(R_ISO8061_STR)) {
- var date = new Date(0),
- tzHour = 0,
- tzMin = 0;
- if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
- }
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
- date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
- return date;
- }
- return string;
-}
function jsonDateToString(date){
if (!date) return date;
diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js
index 078c54fc..c792cace 100644
--- a/src/ng/filter/filters.js
+++ b/src/ng/filter/filters.js
@@ -288,7 +288,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* (e.g. `"h o''clock"`).
*
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
- * number) or ISO 8601 extended datetime string (yyyy-MM-ddTHH:mm:ss.SSSZ).
+ * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
+ * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
* @param {string=} format Formatting rules (see Description). If not specified,
* `mediumDate` is used.
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
@@ -317,6 +318,27 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
*/
dateFilter.$inject = ['$locale'];
function dateFilter($locale) {
+
+
+ var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+ function jsonStringToDate(string){
+ var match;
+ if (match = string.match(R_ISO8601_STR)) {
+ var date = new Date(0),
+ tzHour = 0,
+ tzMin = 0;
+ if (match[9]) {
+ tzHour = int(match[9] + match[10]);
+ tzMin = int(match[9] + match[11]);
+ }
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
+ date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
+ return date;
+ }
+ return string;
+ }
+
+
return function(date, format) {
var text = '',
parts = [],
diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js
index 306ca77b..f5dd6758 100644
--- a/src/ngMock/angular-mocks.js
+++ b/src/ngMock/angular-mocks.js
@@ -373,146 +373,176 @@ angular.mock.$LogProvider = function() {
};
-/**
- * @ngdoc object
- * @name angular.mock.TzDate
- * @description
- *
- * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
- *
- * Mock of the Date type which has its timezone specified via constroctor arg.
- *
- * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
- * offset, so that we can test code that depends on local timezone settings without dependency on
- * the time zone settings of the machine where the code is running.
- *
- * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
- * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
- *
- * @example
- * !!!! WARNING !!!!!
- * This is not a complete Date object so only methods that were implemented can be called safely.
- * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
- *
- * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
- * incomplete we might be missing some non-standard methods. This can result in errors like:
- * "Date.prototype.foo called on incompatible Object".
- *
- * <pre>
- * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
- * newYearInBratislava.getTimezoneOffset() => -60;
- * newYearInBratislava.getFullYear() => 2010;
- * newYearInBratislava.getMonth() => 0;
- * newYearInBratislava.getDate() => 1;
- * newYearInBratislava.getHours() => 0;
- * newYearInBratislava.getMinutes() => 0;
- * </pre>
- *
- */
-angular.mock.TzDate = function (offset, timestamp) {
- var self = new Date(0);
- if (angular.isString(timestamp)) {
- var tsStr = timestamp;
-
- self.origDate = angular.fromJson(angular.toJson({date:timestamp})).date;
-
- timestamp = self.origDate.getTime();
- if (isNaN(timestamp))
- throw {
- name: "Illegal Argument",
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
- };
- } else {
- self.origDate = new Date(timestamp);
+(function() {
+ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+
+ function jsonStringToDate(string){
+ var match;
+ if (match = string.match(R_ISO8061_STR)) {
+ var date = new Date(0),
+ tzHour = 0,
+ tzMin = 0;
+ if (match[9]) {
+ tzHour = int(match[9] + match[10]);
+ tzMin = int(match[9] + match[11]);
+ }
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
+ date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
+ return date;
+ }
+ return string;
}
- var localOffset = new Date(timestamp).getTimezoneOffset();
- self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
- self.date = new Date(timestamp + self.offsetDiff);
+ function int(str) {
+ return parseInt(str, 10);
+ }
- self.getTime = function() {
- return self.date.getTime() - self.offsetDiff;
- };
- self.toLocaleDateString = function() {
- return self.date.toLocaleDateString();
- };
+ /**
+ * @ngdoc object
+ * @name angular.mock.TzDate
+ * @description
+ *
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
+ *
+ * Mock of the Date type which has its timezone specified via constroctor arg.
+ *
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
+ * offset, so that we can test code that depends on local timezone settings without dependency on
+ * the time zone settings of the machine where the code is running.
+ *
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
+ *
+ * @example
+ * !!!! WARNING !!!!!
+ * This is not a complete Date object so only methods that were implemented can be called safely.
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
+ *
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
+ * "Date.prototype.foo called on incompatible Object".
+ *
+ * <pre>
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
+ * newYearInBratislava.getTimezoneOffset() => -60;
+ * newYearInBratislava.getFullYear() => 2010;
+ * newYearInBratislava.getMonth() => 0;
+ * newYearInBratislava.getDate() => 1;
+ * newYearInBratislava.getHours() => 0;
+ * newYearInBratislava.getMinutes() => 0;
+ * </pre>
+ *
+ */
+ angular.mock.TzDate = function (offset, timestamp) {
+ var self = new Date(0);
+ if (angular.isString(timestamp)) {
+ var tsStr = timestamp;
+
+ self.origDate = jsonStringToDate(timestamp)
+
+ timestamp = self.origDate.getTime();
+ if (isNaN(timestamp))
+ throw {
+ name: "Illegal Argument",
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
+ };
+ } else {
+ self.origDate = new Date(timestamp);
+ }
- self.getFullYear = function() {
- return self.date.getFullYear();
- };
+ var localOffset = new Date(timestamp).getTimezoneOffset();
+ self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
+ self.date = new Date(timestamp + self.offsetDiff);
- self.getMonth = function() {
- return self.date.getMonth();
- };
+ self.getTime = function() {
+ return self.date.getTime() - self.offsetDiff;
+ };
- self.getDate = function() {
- return self.date.getDate();
- };
+ self.toLocaleDateString = function() {
+ return self.date.toLocaleDateString();
+ };
- self.getHours = function() {
- return self.date.getHours();
- };
+ self.getFullYear = function() {
+ return self.date.getFullYear();
+ };
- self.getMinutes = function() {
- return self.date.getMinutes();
- };
+ self.getMonth = function() {
+ return self.date.getMonth();
+ };
- self.getSeconds = function() {
- return self.date.getSeconds();
- };
+ self.getDate = function() {
+ return self.date.getDate();
+ };
- self.getTimezoneOffset = function() {
- return offset * 60;
- };
+ self.getHours = function() {
+ return self.date.getHours();
+ };
- self.getUTCFullYear = function() {
- return self.origDate.getUTCFullYear();
- };
+ self.getMinutes = function() {
+ return self.date.getMinutes();
+ };
- self.getUTCMonth = function() {
- return self.origDate.getUTCMonth();
- };
+ self.getSeconds = function() {
+ return self.date.getSeconds();
+ };
- self.getUTCDate = function() {
- return self.origDate.getUTCDate();
- };
+ self.getTimezoneOffset = function() {
+ return offset * 60;
+ };
- self.getUTCHours = function() {
- return self.origDate.getUTCHours();
- };
+ self.getUTCFullYear = function() {
+ return self.origDate.getUTCFullYear();
+ };
- self.getUTCMinutes = function() {
- return self.origDate.getUTCMinutes();
- };
+ self.getUTCMonth = function() {
+ return self.origDate.getUTCMonth();
+ };
- self.getUTCSeconds = function() {
- return self.origDate.getUTCSeconds();
- };
+ self.getUTCDate = function() {
+ return self.origDate.getUTCDate();
+ };
- self.getDay = function() {
- return self.date.getDay();
- };
+ self.getUTCHours = function() {
+ return self.origDate.getUTCHours();
+ };
- //hide all methods not implemented in this mock that the Date prototype exposes
- var unimplementedMethods = ['getMilliseconds', 'getUTCDay',
- 'getUTCMilliseconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
- 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
- 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
- 'setYear', 'toDateString', 'toJSON', 'toGMTString', 'toLocaleFormat', 'toLocaleString',
- 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
-
- angular.forEach(unimplementedMethods, function(methodName) {
- self[methodName] = function() {
- throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
+ self.getUTCMinutes = function() {
+ return self.origDate.getUTCMinutes();
};
- });
- return self;
-};
+ self.getUTCSeconds = function() {
+ return self.origDate.getUTCSeconds();
+ };
+
+ self.getUTCMilliseconds = function() {
+ return self.origDate.getUTCMilliseconds();
+ };
+
+ self.getDay = function() {
+ return self.date.getDay();
+ };
+
+ //hide all methods not implemented in this mock that the Date prototype exposes
+ var unimplementedMethods = ['getMilliseconds', 'getUTCDay',
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
+ 'setYear', 'toDateString', 'toJSON', 'toGMTString', 'toLocaleFormat', 'toLocaleString',
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
+
+ angular.forEach(unimplementedMethods, function(methodName) {
+ self[methodName] = function() {
+ throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
+ };
+ });
+
+ return self;
+ };
-//make "tzDateInstance instanceof Date" return true
-angular.mock.TzDate.prototype = Date.prototype;
+ //make "tzDateInstance instanceof Date" return true
+ angular.mock.TzDate.prototype = Date.prototype;
+})();
/**
diff --git a/test/JsonSpec.js b/test/JsonSpec.js
index e4abeef9..ad0cb415 100644
--- a/test/JsonSpec.js
+++ b/test/JsonSpec.js
@@ -72,9 +72,8 @@ describe('json', function() {
});
it('should serialize UTC dates', function() {
- var date = jsonStringToDate('2009-10-09T01:02:03.027Z');
+ var date = new angular.mock.TzDate(-1, '2009-10-09T01:02:03.027Z');
expect(toJson(date)).toEqual('"2009-10-09T01:02:03.027Z"');
- expect(fromJson('"2009-10-09T01:02:03.027Z"').getTime()).toEqual(date.getTime());
});
it('should prevent recursion', function() {
@@ -156,17 +155,7 @@ describe('json', function() {
expect(fromJson('{}', true)).toEqual({});
expect(spy).toHaveBeenCalled();
});
-
-
- it('should convert timestamp strings to Date objects', function() {
- expect(fromJson('"2010-12-22T17:23:17.974Z"', true) instanceof Date).toBe(true);
- expect(fromJson('["2010-12-22T17:23:17.974Z"]', true)[0] instanceof Date).toBe(true);
- expect(fromJson('{"t":"2010-12-22T17:23:17.974Z"}', true).t instanceof Date).toBe(true);
- expect(fromJson('{"t":["2010-12-22T17:23:17.974Z"]}', true).t[0] instanceof Date).toBe(true);
- expect(fromJson('{"t":{"t":"2010-12-22T17:23:17.974Z"}}', true).t.t instanceof Date).toBe(true);
- });
});
-
}
@@ -220,45 +209,6 @@ describe('json', function() {
});
- describe('iso 8061 date', function() {
- it('should read/write to date', function() {
- var date = new Date('Sep 10 2003 13:02:03 GMT');
- expect(jsonDateToString(date)).toBe('2003-09-10T13:02:03.000Z');
- expect(jsonStringToDate(jsonDateToString(date)).getTime()).toBe(date.getTime());
- });
-
-
- it('should convert to date', function() {
- //full ISO8061
- expect(jsonStringToDate('2003-09-10T13:02:03.000Z')).toEqual(new Date('Sep 10 2003 13:02:03 GMT'));
-
- expect(jsonStringToDate('2003-09-10T13:02:03.000+00:00')).toEqual(new Date('Sep 10 2003 13:02:03 GMT'));
-
- expect(jsonStringToDate('20030910T033203-0930')).toEqual(new Date('Sep 10 2003 13:02:03 GMT'));
-
- //no millis
- expect(jsonStringToDate('2003-09-10T13:02:03Z')).toEqual(new Date('Sep 10 2003 13:02:03 GMT'));
-
- //no seconds
- expect(jsonStringToDate('2003-09-10T13:02Z')).toEqual(new Date('Sep 10 2003 13:02:00 GMT'));
-
- //no minutes
- expect(jsonStringToDate('2003-09-10T13Z')).toEqual(new Date('Sep 10 2003 13:00:00 GMT'));
-
- //no time
- expect(jsonStringToDate('2003-09-10')).toEqual(new Date('Sep 10 2003 00:00:00 GMT'));
-
- expect(jsonStringToDate('2011-12-28T13:02:09-08:00')).toEqual(new Date('Dec 28 2011 21:02:09 GMT'));
- });
-
-
- it('should parse date', function() {
- var date = jsonStringToDate('2003-09-10T13:02:03.000Z');
- expect(jsonDateToString(date)).toBe('2003-09-10T13:02:03.000Z');
- expect(jsonStringToDate('str')).toBe('str');
- });
- });
-
describe('string', function() {
it('should quote', function() {
expect(quoteUnicode('a')).toBe('"a"');
diff --git a/test/ng/filter/filtersSpec.js b/test/ng/filter/filtersSpec.js
index 98651c58..9ea200a3 100644
--- a/test/ng/filter/filtersSpec.js
+++ b/test/ng/filter/filtersSpec.js
@@ -267,14 +267,34 @@ describe('filters', function() {
toEqual('12:05 PM');
});
- it('should be able to parse ISO 8601 dates/times using', function() {
- var isoString = '2010-09-03T05:05:08.872Z';
- expect(date(isoString)).
- toEqual(date(isoString, 'mediumDate'));
- });
-
it('should parse format ending with non-replaced string', function() {
expect(date(morning, 'yy/xxx')).toEqual('10/xxx');
});
+
+
+ it('should support various iso8061 date strings as input', function() {
+ var format = 'yyyy-MM ss';
+
+ //full ISO8061
+ expect(date('2003-09-10T13:02:03.000Z', format)).toEqual('2003-09 03');
+
+ expect(date('2003-09-10T13:02:03.000+00:00', format)).toEqual('2003-09 03');
+
+ expect(date('2003-09-10T13:02:03-08:00', format)).toEqual('2003-09 03');
+
+ expect(date('20030910T033203-0930', format)).toEqual('2003-09 03');
+
+ //no millis
+ expect(date('2003-09-10T13:02:03Z', format)).toEqual('2003-09 03');
+
+ //no seconds
+ expect(date('2003-09-10T13:02Z', format)).toEqual('2003-09 00');
+
+ //no minutes
+ expect(date('2003-09-10T13Z', format)).toEqual('2003-09 00');
+
+ //no time
+ expect(date('2003-09-10', format)).toEqual('2003-09 00');
+ });
});
});