From 984ed39195d8291f0da0c2747a45761144e6daa2 Mon Sep 17 00:00:00 2001 From: Prashant Tholia Date: Sat, 12 Sep 2020 20:21:49 +0530 Subject: [PATCH] feat(common): Add ISO week-numbering year formats support to formatDate (#38828) Add ISO 8601 week-numbering year formats ('r', 'rr', 'rrr', 'rrrr') support for formatDate function. Issue:https://github.com/angular/angular/issues/38739 PR Close #38828 --- packages/common/src/i18n/format_date.ts | 33 ++++++++++++++++++- packages/common/src/pipes/date_pipe.ts | 4 +++ packages/common/test/i18n/format_date_spec.ts | 17 ++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/common/src/i18n/format_date.ts b/packages/common/src/i18n/format_date.ts index c9ecd65c20..5d4c704510 100644 --- a/packages/common/src/i18n/format_date.ts +++ b/packages/common/src/i18n/format_date.ts @@ -13,7 +13,7 @@ export const ISO8601_DATE_REGEX = // 1 2 3 4 5 6 7 8 9 10 11 const NAMED_FORMATS: {[localeId: string]: {[format: string]: string}} = {}; const DATE_FORMATS_SPLIT = - /((?:[^GyMLwWdEabBhHmsSzZO']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/; + /((?:[^GyrMLwWdEabBhHmsSzZO']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|r{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/; enum ZoneWidth { Short, @@ -394,6 +394,18 @@ function weekGetter(size: number, monthBased = false): DateFormatter { }; } +/** + * Returns a date formatter that provides the week-numbering year for the input date. + */ +function weekNumberingYearGetter(size: number, trim = false): DateFormatter { + return function(date: Date, locale: string) { + const thisThurs = getThursdayThisWeek(date); + const weekNumberingYear = thisThurs.getFullYear(); + return padNumber( + weekNumberingYear, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign), trim); + }; +} + type DateFormatter = (date: Date, locale: string, offset: number) => string; const DATE_FORMATS: {[format: string]: DateFormatter} = {}; @@ -438,6 +450,25 @@ function getDateFormatter(format: string): DateFormatter|null { formatter = dateGetter(DateType.FullYear, 4, 0, false, true); break; + // 1 digit representation of the week-numbering year, e.g. (AD 1 => 1, AD 199 => 199) + case 'r': + formatter = weekNumberingYearGetter(1); + break; + // 2 digit representation of the week-numbering year, padded (00-99). (e.g. AD 2001 => 01, AD + // 2010 => 10) + case 'rr': + formatter = weekNumberingYearGetter(2, true); + break; + // 3 digit representation of the week-numbering year, padded (000-999). (e.g. AD 1 => 001, AD + // 2010 => 2010) + case 'rrr': + formatter = weekNumberingYearGetter(3); + break; + // 4 digit representation of the week-numbering year (e.g. AD 1 => 0001, AD 2010 => 2010) + case 'rrrr': + formatter = weekNumberingYearGetter(4); + break; + // Month of the year (1-12), numeric case 'M': case 'L': diff --git a/packages/common/src/pipes/date_pipe.ts b/packages/common/src/pipes/date_pipe.ts index a6781804a3..bd9236c865 100644 --- a/packages/common/src/pipes/date_pipe.ts +++ b/packages/common/src/pipes/date_pipe.ts @@ -65,6 +65,10 @@ import {invalidPipeArgumentError} from './invalid_pipe_argument_error'; * | | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | * | | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | * | | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | + * | Week-numbering year| r | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | + * | | rr | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | + * | | rrr | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | + * | | rrrr | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | * | Month | M | Numeric: 1 digit | 9, 12 | * | | MM | Numeric: 2 digits + zero padded | 09, 12 | * | | MMM | Abbreviated | Sep | diff --git a/packages/common/test/i18n/format_date_spec.ts b/packages/common/test/i18n/format_date_spec.ts index 25a1f2b71f..2a9cabf6ad 100644 --- a/packages/common/test/i18n/format_date_spec.ts +++ b/packages/common/test/i18n/format_date_spec.ts @@ -95,6 +95,10 @@ describe('Format date', () => { yy: '15', yyy: '2015', yyyy: '2015', + r: '2015', + rr: '15', + rrr: '2015', + rrrr: '2015', M: '6', MM: '06', MMM: 'Jun', @@ -153,6 +157,10 @@ describe('Format date', () => { yy: '15', yyy: '2015', yyyy: '2015', + r: '2015', + rr: '15', + rrr: '2015', + rrrr: '2015', M: '1', MM: '01', MMM: 'Jan', @@ -361,5 +369,14 @@ describe('Format date', () => { expect(formatDate(3001, 'm:ss.SS', 'en')).toEqual('0:03.00'); expect(formatDate(3001, 'm:ss.SSS', 'en')).toEqual('0:03.001'); }); + + // https://github.com/angular/angular/issues/38739 + it('should return correct ISO 8601 week-numbering year for dates close to year end/beginning', + () => { + expect(formatDate('2013-12-27', 'rrrr', 'en')).toEqual('2013'); + expect(formatDate('2013-12-29', 'rrrr', 'en')).toEqual('2014'); + expect(formatDate('2010-01-02', 'rrrr', 'en')).toEqual('2009'); + expect(formatDate('2010-01-04', 'rrrr', 'en')).toEqual('2010'); + }); }); });