aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDi Peng2011-07-14 12:02:01 -0700
committerIgor Minar2011-07-20 17:06:56 -0700
commit3af1e7ca2ee8c2acd69e5bcbb3ffc1bf51239285 (patch)
treee354ff465d7f29e419591dd12fb7c9f48bd8bb81
parent0fbaa2f12ab96328fe2e7b4b9f3ec0c8d7f30e37 (diff)
downloadangular.js-3af1e7ca2ee8c2acd69e5bcbb3ffc1bf51239285.tar.bz2
feat(filter.date): add support for default datetime formats in en
- add support for full,long, medium, short datetime formats in en Breaks MMMMM. now we don't support MMMMM anymore as old implementation differs from Unicode Locale Data format we are following. - removed support for fullDateTime and fullTime as it means too much trouble with full timeZone names - added docs for the new features
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/filters.js69
-rw-r--r--test/FiltersSpec.js78
-rw-r--r--test/angular-mocksSpec.js10
4 files changed, 133 insertions, 27 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 45428ad4..dd2dcc97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
<a name="0.9.18"><a/>
# <angular/> 0.9.18 jiggling-armfat (in-progress) #
-
+### Breaking changes
+- no longer support MMMMM in filter.date as we need to follow UNICODE LOCALE DATA formats.
diff --git a/src/filters.js b/src/filters.js
index 1dd6322b..8fac671d 100644
--- a/src/filters.js
+++ b/src/filters.js
@@ -184,6 +184,17 @@ function dateStrGetter(name, shortForm) {
};
}
+function timeZoneGetter(numFormat) {
+ return function(date) {
+ var timeZone;
+ if (numFormat || !(timeZone = GET_TIME_ZONE.exec(date.toString()))) {
+ var offset = date.getTimezoneOffset();
+ return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
+ }
+ return timeZone[0];
+ };
+}
+
var DAY = 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(',');
var MONTH = 'January,February,March,April,May,June,July,August,September,October,November,December'.
@@ -192,7 +203,8 @@ var MONTH = 'January,February,March,April,May,June,July,August,September,October
var DATE_FORMATS = {
yyyy: dateGetter('FullYear', 4),
yy: dateGetter('FullYear', 2, 0, true),
- MMMMM: dateStrGetter('Month'),
+ y: dateGetter('FullYear', 1),
+ MMMM: dateStrGetter('Month'),
MMM: dateStrGetter('Month', true),
MM: dateGetter('Month', 2, 1),
M: dateGetter('Month', 1, 1),
@@ -209,14 +221,26 @@ var DATE_FORMATS = {
EEEE: dateStrGetter('Day'),
EEE: dateStrGetter('Day', true),
a: function(date){return date.getHours() < 12 ? 'am' : 'pm';},
- Z: function(date){
- var offset = date.getTimezoneOffset();
- return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
- }
+ z: timeZoneGetter(false),
+ Z: timeZoneGetter(true)
};
+var DEFAULT_DATETIME_FORMATS = {
+ long: 'MMMM d, y h:mm:ss a z',
+ medium: 'MMM d, y h:mm:ss a',
+ short: 'M/d/yy h:mm a',
+ fullDate: 'EEEE, MMMM d, y',
+ longDate: 'MMMM d, y',
+ mediumDate: 'MMM d, y',
+ shortDate: 'M/d/yy',
+ longTime: 'h:mm:ss a z',
+ mediumTime: 'h:mm:ss a',
+ shortTime: 'h:mm a'
+};
-var DATE_FORMATS_SPLIT = /([^yMdHhmsaZE]*)(E+|y+|M+|d+|H+|h+|m+|s+|a|Z)(.*)/;
+var GET_TIME_ZONE = /[A-Z]{3}(?![+\-])/;
+var DATE_FORMATS_SPLIT = /([^yMdHhmsazZE]*)(E+|y+|M+|d+|H+|h+|m+|s+|a|Z|z)(.*)/;
+var OPERA_TOSTRING_PATTERN = /^[\d].*Z$/;
var NUMBER_STRING = /^\d+$/;
@@ -231,9 +255,10 @@ var NUMBER_STRING = /^\d+$/;
*
* `format` string can be composed of the following elements:
*
- * * `'yyyy'`: 4 digit representation of year e.g. 2010
- * * `'yy'`: 2 digit representation of year, padded (00-99)
- * * `'MMMMM'`: Month in year (January‒December)
+ * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
+ * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
+ * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
+ * * `'MMMM'`: Month in year (January‒December)
* * `'MMM'`: Month in year (Jan - Dec)
* * `'MM'`: Month in year, padded (01‒12)
* * `'M'`: Month in year (1‒12)
@@ -251,15 +276,36 @@ var NUMBER_STRING = /^\d+$/;
* * `'s'`: Second in minute (0‒59)
* * `'a'`: am/pm marker
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200‒1200)
+ * * `'z'`: short form of current timezone name (e.g. PDT)
+ *
+ * `format` string can also be the following default formats for `en_US` locale (support for other
+ * locales will be added in the future versions):
+ *
+ * * `'long'`: equivalent to `'MMMM d, y h:mm:ss a z'` for en_US locale
+ * (e.g. September 3, 2010 12:05:08 pm PDT)
+ * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
+ * (e.g. Sep 3, 2010 12:05:08 pm)
+ * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
+ * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
+ * (e.g. Friday, September 3, 2010)
+ * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010
+ * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
+ * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
+ * * `'longTime'`: equivalent to `'h:mm:ss a z'` for en_US locale (e.g. 12:05:08 pm PDT)
+ * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
+ * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
*
* @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).
- * @param {string=} format Formatting rules. If not specified, Date#toLocaleDateString is used.
+ * @param {string=} format Formatting rules (see Description). If not specified,
+ * Date#toLocaleDateString is used.
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
*
* @example
<doc:example>
<doc:source>
+ <span ng:non-bindable>{{1288323623006 | date:'medium'}}</span>:
+ {{1288323623006 | date:'medium'}}<br/>
<span ng:non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br/>
<span ng:non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
@@ -267,6 +313,8 @@ var NUMBER_STRING = /^\d+$/;
</doc:source>
<doc:scenario>
it('should format date', function(){
+ expect(binding("1288323623006 | date:'medium'")).
+ toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} pm/);
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
@@ -276,6 +324,7 @@ var NUMBER_STRING = /^\d+$/;
</doc:example>
*/
angularFilter.date = function(date, format) {
+ format = DEFAULT_DATETIME_FORMATS[format] || format;
if (isString(date)) {
if (NUMBER_STRING.test(date)) {
date = parseInt(date, 10);
diff --git a/test/FiltersSpec.js b/test/FiltersSpec.js
index 594428f6..6bcdb511 100644
--- a/test/FiltersSpec.js
+++ b/test/FiltersSpec.js
@@ -111,8 +111,10 @@ describe('filter', function() {
});
it('should handle mailto:', function() {
- expect(linky("mailto:me@example.com").html).toEqual('<a href="mailto:me@example.com">me@example.com</a>');
- expect(linky("me@example.com").html).toEqual('<a href="mailto:me@example.com">me@example.com</a>');
+ expect(linky("mailto:me@example.com").html).
+ toEqual('<a href="mailto:me@example.com">me@example.com</a>');
+ expect(linky("me@example.com").html).
+ toEqual('<a href="mailto:me@example.com">me@example.com</a>');
expect(linky("send email to me@example.com, but").html).
toEqual('send email to <a href="mailto:me@example.com">me@example.com</a>, but');
});
@@ -123,6 +125,9 @@ describe('filter', function() {
var morning = new TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am
var noon = new TzDate(+5, '2010-09-03T17:05:08.000Z'); //12pm
var midnight = new TzDate(+5, '2010-09-03T05:05:08.000Z'); //12am
+ var earlyDate = new TzDate(+5, '0001-09-03T05:05:08.000Z');
+ var timZoneDate = new TzDate(+5, '2010-09-03T05:05:08.000Z',
+ 'Mon Sep 3 2010 00:05:08 GMT+0500 (XYZ)'); //12am
it('should ignore falsy inputs', function() {
expect(filter.date(null)).toBeNull();
@@ -141,24 +146,79 @@ describe('filter', function() {
it('should accept various format strings', function() {
expect(filter.date(morning, "yy-MM-dd HH:mm:ss")).
- toEqual('10-09-03 07:05:08');
+ toEqual('10-09-03 07:05:08');
expect(filter.date(midnight, "yyyy-M-d h=H:m:saZ")).
- toEqual('2010-9-3 12=0:5:8am0500');
+ toEqual('2010-9-3 12=0:5:8am0500');
expect(filter.date(midnight, "yyyy-MM-dd hh=HH:mm:ssaZ")).
- toEqual('2010-09-03 12=00:05:08am0500');
+ toEqual('2010-09-03 12=00:05:08am0500');
expect(filter.date(noon, "yyyy-MM-dd hh=HH:mm:ssaZ")).
- toEqual('2010-09-03 12=12:05:08pm0500');
+ toEqual('2010-09-03 12=12:05:08pm0500');
+
+ expect(filter.date(timZoneDate, "yyyy-MM-dd hh=HH:mm:ss a z")).
+ toEqual('2010-09-03 12=00:05:08 am XYZ');
expect(filter.date(noon, "EEE, MMM d, yyyy")).
- toEqual('Fri, Sep 3, 2010');
+ toEqual('Fri, Sep 3, 2010');
+
+ expect(filter.date(noon, "EEEE, MMMM dd, yyyy")).
+ toEqual('Friday, September 03, 2010');
+
+ expect(filter.date(earlyDate, "MMMM dd, y")).
+ toEqual('September 03, 1');
+ });
+
+ it('should accept default formats', function() {
+
+ expect(filter.date(timZoneDate, "long")).
+ toEqual('September 3, 2010 12:05:08 am XYZ');
+
+ expect(filter.date(noon, "medium")).
+ toEqual('Sep 3, 2010 12:05:08 pm');
+
+ expect(filter.date(noon, "short")).
+ toEqual('9/3/10 12:05 pm');
+
+ expect(filter.date(noon, "fullDate")).
+ toEqual('Friday, September 3, 2010');
+
+ expect(filter.date(noon, "longDate")).
+ toEqual('September 3, 2010');
- expect(filter.date(noon, "EEEE, MMMMM dd, yyyy")).
- toEqual('Friday, September 03, 2010');
+ expect(filter.date(noon, "mediumDate")).
+ toEqual('Sep 3, 2010');
+
+ expect(filter.date(noon, "shortDate")).
+ toEqual('9/3/10');
+
+ expect(filter.date(timZoneDate, "longTime")).
+ toEqual('12:05:08 am XYZ');
+
+ expect(filter.date(noon, "mediumTime")).
+ toEqual('12:05:08 pm');
+
+ expect(filter.date(noon, "shortTime")).
+ toEqual('12:05 pm');
+ });
+
+
+ it('should parse timezone identifier from various toString values', function() {
+ //chrome and firefox format
+ expect(filter.date(new TzDate(+5, '2010-09-03T17:05:08.000Z',
+ 'Mon Sep 3 2010 17:05:08 GMT+0500 (XYZ)'), "z")).toBe('XYZ');
+
+ //opera format
+ expect(filter.date(new TzDate(+5, '2010-09-03T17:05:08.000Z',
+ '2010-09-03T17:05:08Z'), "z")).toBe('0500');
+
+ //ie 8 format
+ expect(filter.date(new TzDate(+5, '2010-09-03T17:05:08.000Z',
+ 'Mon Sep 3 17:05:08 XYZ 2010'), "z")).toBe('XYZ');
});
+
it('should be able to parse ISO 8601 dates/times using', function() {
var isoString = '2010-09-03T05:05:08.872Z';
expect(filter.date(isoString)).
diff --git a/test/angular-mocksSpec.js b/test/angular-mocksSpec.js
index b85503e6..a30c3497 100644
--- a/test/angular-mocksSpec.js
+++ b/test/angular-mocksSpec.js
@@ -130,13 +130,9 @@ describe('mocks', function(){
it('should throw error when no third param but toString called', function() {
- var t = new TzDate(0, 0);
- try {
- t.toString();
- } catch(err) {
- expect(err.name).toBe('MethodNotImplemented');
- }
- })
+ expect(function() { new TzDate(0,0).toString() }).
+ toThrow('Method \'toString\' is not implemented in the TzDate mock');
+ });
});
describe('$log mock', function() {