Skip to content

Commit

Permalink
fixup! feat(common): add injection token for default date pipe format
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasweiss committed Sep 15, 2022
1 parent 9590ddc commit 09fb9a7
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 16 deletions.
4 changes: 2 additions & 2 deletions goldens/public-api/common/index.md
Expand Up @@ -76,14 +76,14 @@ export class CurrencyPipe implements PipeTransform {
}

// @public
export const DATE_PIPE_DEFAULT_FORMAT: InjectionToken<string>;
export const DATE_PIPE_DEFAULT_OPTIONS: InjectionToken<DatePipeConfig>;

// @public
export const DATE_PIPE_DEFAULT_TIMEZONE: InjectionToken<string>;

// @public
export class DatePipe implements PipeTransform {
constructor(locale: string, defaultTimezone?: string | null | undefined, defaultFormat?: string | null | undefined);
constructor(locale: string, defaultTimezone?: string | null | undefined, defaultOptions?: DatePipeConfig | null | undefined);
// (undocumented)
transform(value: Date | string | number, format?: string, timezone?: string, locale?: string): string | null;
// (undocumented)
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/common.ts
Expand Up @@ -22,7 +22,7 @@ export {parseCookieValue as ɵparseCookieValue} from './cookie';
export {CommonModule} from './common_module';
export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
export {DOCUMENT} from './dom_tokens';
export {AsyncPipe, DatePipe, DATE_PIPE_DEFAULT_TIMEZONE, DATE_PIPE_DEFAULT_FORMAT, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe, KeyValuePipe, KeyValue} from './pipes/index';
export {AsyncPipe, DatePipe, DATE_PIPE_DEFAULT_TIMEZONE, DATE_PIPE_DEFAULT_OPTIONS, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe, KeyValuePipe, KeyValue} from './pipes/index';
export {PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, PLATFORM_WORKER_APP_ID as ɵPLATFORM_WORKER_APP_ID, PLATFORM_WORKER_UI_ID as ɵPLATFORM_WORKER_UI_ID, isPlatformBrowser, isPlatformServer, isPlatformWorkerApp, isPlatformWorkerUi} from './platform_id';
export {VERSION} from './version';
export {ViewportScroller, NullViewportScroller as ɵNullViewportScroller} from './viewport_scroller';
Expand Down
21 changes: 12 additions & 9 deletions packages/common/src/pipes/date_pipe.ts
Expand Up @@ -10,6 +10,7 @@ import {Inject, InjectionToken, LOCALE_ID, Optional, Pipe, PipeTransform} from '

import {formatDate} from '../i18n/format_date';

import {DatePipeConfig} from './date_pipe_config';
import {invalidPipeArgumentError} from './invalid_pipe_argument_error';

/**
Expand All @@ -22,7 +23,8 @@ export const DATE_PIPE_DEFAULT_TIMEZONE = new InjectionToken<string>('DATE_PIPE_
* Optionally-provided default format to use for all instances of `DatePipe` (such as `short`).
* If the value isn't provided, the `DatePipe` will default to 'mediumDate'.
*/
export const DATE_PIPE_DEFAULT_FORMAT = new InjectionToken<string>('DATE_PIPE_DEFAULT_FORMAT');
export const DATE_PIPE_DEFAULT_OPTIONS =
new InjectionToken<DatePipeConfig>('DATE_PIPE_DEFAULT_OPTIONS');

// clang-format off
/**
Expand Down Expand Up @@ -192,17 +194,18 @@ export class DatePipe implements PipeTransform {
constructor(
@Inject(LOCALE_ID) private locale: string,
@Inject(DATE_PIPE_DEFAULT_TIMEZONE) @Optional() private defaultTimezone?: string|null,
@Inject(DATE_PIPE_DEFAULT_FORMAT) @Optional() private defaultFormat?: string|null) {}
@Inject(DATE_PIPE_DEFAULT_OPTIONS) @Optional() private defaultOptions?: DatePipeConfig|null,
) {}

/**
* @param value The date expression: a `Date` object, a number
* (milliseconds since UTC epoch), or an ISO string (https://www.w3.org/TR/NOTE-datetime).
* @param format The date/time components to include, using predefined options or a
* custom format string. When not supplied, either the value of the `DATE_PIPE_DEFAULT_FORMAT`
* injection token is used or the 'mediumDate' format.
* @param options The date/time components to include, using predefined options or a
* custom format string. When not supplied, either the `dateFormat` property of the
* `DATE_PIPE_DEFAULT_FORMAT` injection token is used or the 'mediumDate' format.
* @param timezone A timezone offset (such as `'+0430'`), or a standard UTC/GMT, or continental US
* timezone abbreviation. When not supplied, either the value of the `DATE_PIPE_DEFAULT_TIMEZONE`
* injection token is used or the end-user's local system timezone.
* timezone abbreviation. When not supplied, either the `timezone` property of the
* `DATE_PIPE_DEFAULT_OPTIONS` injection token is used or the end-user's local system timezone.
* @param locale A locale code for the locale format rules to use.
* When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.
* See [Setting your app locale](guide/i18n-common-locale-id).
Expand All @@ -221,8 +224,8 @@ export class DatePipe implements PipeTransform {

try {
return formatDate(
value, format ?? this.defaultFormat ?? 'mediumDate', locale || this.locale,
timezone ?? this.defaultTimezone ?? undefined);
value, format ?? this.defaultOptions?.dateFormat ?? 'mediumDate', locale || this.locale,
timezone ?? this.defaultOptions?.timezone ?? this.defaultTimezone ?? undefined);
} catch (error) {
throw invalidPipeArgumentError(DatePipe, (error as Error).message);
}
Expand Down
12 changes: 12 additions & 0 deletions packages/common/src/pipes/date_pipe_config.ts
@@ -0,0 +1,12 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

export interface DatePipeConfig {
dateFormat: string;
timezone: string;
}
4 changes: 2 additions & 2 deletions packages/common/src/pipes/index.ts
Expand Up @@ -13,7 +13,7 @@
*/
import {AsyncPipe} from './async_pipe';
import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from './case_conversion_pipes';
import {DATE_PIPE_DEFAULT_FORMAT, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe} from './date_pipe';
import {DATE_PIPE_DEFAULT_OPTIONS, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe} from './date_pipe';
import {I18nPluralPipe} from './i18n_plural_pipe';
import {I18nSelectPipe} from './i18n_select_pipe';
import {JsonPipe} from './json_pipe';
Expand All @@ -24,7 +24,7 @@ import {SlicePipe} from './slice_pipe';
export {
AsyncPipe,
CurrencyPipe,
DATE_PIPE_DEFAULT_FORMAT,
DATE_PIPE_DEFAULT_OPTIONS,
DATE_PIPE_DEFAULT_TIMEZONE,
DatePipe,
DecimalPipe,
Expand Down
45 changes: 43 additions & 2 deletions packages/common/test/pipes/date_pipe_spec.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {DatePipe} from '@angular/common';
import {DATE_PIPE_DEFAULT_OPTIONS, DatePipe} from '@angular/common';
import localeEn from '@angular/common/locales/en';
import localeEnExtra from '@angular/common/locales/extra/en';
import {Component, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
Expand Down Expand Up @@ -72,9 +72,31 @@ import {TestBed} from '@angular/core/testing';
});

describe('transform', () => {
it('should use "mediumDate" as the default format',
it('should use "mediumDate" as the default format if no format is provided',
() => expect(pipe.transform('2017-01-11T10:14:39+0000')).toEqual('Jan 11, 2017'));

it('should give precedence to the passed in format',
() => expect(pipe.transform('2017-01-11T10:14:39+0000', 'shortDate')).toEqual('1/11/17'));

it('should use provided format as default format when no format is passed in', () => {
@Component({
selector: 'test-component',
imports: [DatePipe],
template: '{{ value | date }}',
standalone: true,
providers: [{provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {dateFormat: 'shortDate'}}]
})
class TestComponent {
value = '2017-01-11T10:14:39+0000';
}

const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const content = fixture.nativeElement.textContent;
expect(content).toBe('1/11/17');
});

it('should return first week if some dates fall in previous year but belong to next year according to ISO 8601 format',
() => {
expect(pipe.transform('2019-12-28T00:00:00', 'w')).toEqual('52');
Expand Down Expand Up @@ -111,6 +133,25 @@ import {TestBed} from '@angular/core/testing';
expect(pipe.transform('2017-01-11T00:00:00', 'mediumDate', '+0100'))
.toEqual('Jan 11, 2017');
});

it('should use provided timezone as default timezone when no format is passed in', () => {
@Component({
selector: 'test-component',
imports: [DatePipe],
template: '{{ value | date }}',
standalone: true,
providers: [{provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {timezone: '-1200'}}]
})
class TestComponent {
value = '2017-01-11T00:00:00';
}

const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

const content = fixture.nativeElement.textContent;
expect(content).toBe('Jan 10, 2017');
});
});

it('should be available as a standalone pipe', () => {
Expand Down

0 comments on commit 09fb9a7

Please sign in to comment.