From 439d6fc591faf2a236c6027f217a97d906180b6c Mon Sep 17 00:00:00 2001 From: adotnusiyan <36204879+adotnusiyan@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:19:26 +0300 Subject: [PATCH] feat(material-luxon-adapter): add option to set default calendar (#27453) * feat(material-luxon-adapter): add option to set default calendar Add defaultOutputCalendar option to be able to change default calndar through MAT_LUXON_DATE_ADAPTER_OPTIONS * feat(material-luxon-adapter): update options to add default calendar Update options of luxon-date-adapter to add defaultOutputCalendar to be able to change default calndar through MAT_LUXON_DATE_ADAPTER_OPTIONS --- .../adapter/luxon-date-adapter.spec.ts | 37 +++++++++++++++++- .../adapter/luxon-date-adapter.ts | 39 ++++++++++++++----- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/material-luxon-adapter/adapter/luxon-date-adapter.spec.ts b/src/material-luxon-adapter/adapter/luxon-date-adapter.spec.ts index 8ee5312d04cf..c896c9406dbd 100644 --- a/src/material-luxon-adapter/adapter/luxon-date-adapter.spec.ts +++ b/src/material-luxon-adapter/adapter/luxon-date-adapter.spec.ts @@ -9,7 +9,7 @@ import {LOCALE_ID} from '@angular/core'; import {TestBed, waitForAsync} from '@angular/core/testing'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material/core'; -import {DateTime, FixedOffsetZone, Settings} from 'luxon'; +import {CalendarSystem, DateTime, FixedOffsetZone, Settings} from 'luxon'; import {LuxonDateModule} from './index'; import {MAT_LUXON_DATE_ADAPTER_OPTIONS} from './luxon-date-adapter'; @@ -632,6 +632,41 @@ describe('LuxonDateAdapter with MAT_LUXON_DATE_ADAPTER_OPTIONS override', () => }); }); +describe('LuxonDateAdapter with MAT_LUXON_DATE_ADAPTER_OPTIONS override for defaultOutputCalendar option', () => { + let adapter: DateAdapter; + + const calendarExample: CalendarSystem = 'islamic'; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [LuxonDateModule], + providers: [ + { + provide: MAT_LUXON_DATE_ADAPTER_OPTIONS, + useValue: {defaultOutputCalendar: calendarExample}, + }, + ], + }).compileComponents(); + + adapter = TestBed.inject(DateAdapter); + })); + + describe(`use ${calendarExample} calendar`, () => { + it(`should create Luxon date in ${calendarExample} calendar`, () => { + // Use 0 since createDate takes 0-indexed months. + expect(adapter.createDate(2017, 0, 2).toLocaleString()).toBe( + DateTime.local(2017, JAN, 2, {outputCalendar: calendarExample}).toLocaleString(), + ); + }); + + it(`should create today in ${calendarExample} calendar`, () => { + expect(adapter.today().toLocaleString()).toBe( + DateTime.local({outputCalendar: calendarExample}).toLocaleString(), + ); + }); + }); +}); + function assertValidDate(adapter: DateAdapter, d: DateTime | null, valid: boolean) { expect(adapter.isDateInstance(d)) .not.withContext(`Expected ${d} to be a date instance`) diff --git a/src/material-luxon-adapter/adapter/luxon-date-adapter.ts b/src/material-luxon-adapter/adapter/luxon-date-adapter.ts index 663859c3aac1..ef518cd5a181 100644 --- a/src/material-luxon-adapter/adapter/luxon-date-adapter.ts +++ b/src/material-luxon-adapter/adapter/luxon-date-adapter.ts @@ -12,6 +12,7 @@ import { DateTime as LuxonDateTime, Info as LuxonInfo, DateTimeOptions as LuxonDateTimeOptions, + CalendarSystem as LuxonCalendarSystem, } from 'luxon'; /** Configurable options for the `LuxonDateAdapter`. */ @@ -27,6 +28,12 @@ export interface MatLuxonDateAdapterOptions { * Changing this will change how Angular Material components like DatePicker shows start of week. */ firstDayOfWeek: number; + + /** + * Sets the output Calendar. + * Changing this will change how Angular Material components like DatePicker output dates. + */ + defaultOutputCalendar: LuxonCalendarSystem; } /** InjectionToken for LuxonDateAdapter to configure options. */ @@ -43,6 +50,7 @@ export function MAT_LUXON_DATE_ADAPTER_OPTIONS_FACTORY(): MatLuxonDateAdapterOpt return { useUtc: false, firstDayOfWeek: 0, + defaultOutputCalendar: 'gregory', }; } @@ -60,6 +68,7 @@ function range(length: number, valueFunction: (index: number) => T): T[] { export class LuxonDateAdapter extends DateAdapter { private _useUTC: boolean; private _firstDayOfWeek: number; + private _defaultOutputCalendar: LuxonCalendarSystem; constructor( @Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string, @@ -70,6 +79,7 @@ export class LuxonDateAdapter extends DateAdapter { super(); this._useUTC = !!options?.useUtc; this._firstDayOfWeek = options?.firstDayOfWeek || 0; + this._defaultOutputCalendar = options?.defaultOutputCalendar || 'gregory'; this.setLocale(dateLocale || LuxonDateTime.local().locale); } @@ -91,7 +101,11 @@ export class LuxonDateAdapter extends DateAdapter { } getMonthNames(style: 'long' | 'short' | 'narrow'): string[] { - return LuxonInfo.months(style, {locale: this.locale}); + // Adding outputCalendar option, because LuxonInfo doesn't get effected by LuxonSettings + return LuxonInfo.months(style, { + locale: this.locale, + outputCalendar: this._defaultOutputCalendar, + }); } getDateNames(): string[] { @@ -113,7 +127,7 @@ export class LuxonDateAdapter extends DateAdapter { } getYearName(date: LuxonDateTime): string { - return date.toFormat('yyyy'); + return date.toFormat('yyyy', this._getOptions()); } getFirstDayOfWeek(): number { @@ -125,10 +139,12 @@ export class LuxonDateAdapter extends DateAdapter { } clone(date: LuxonDateTime): LuxonDateTime { - return LuxonDateTime.fromObject(date.toObject()); + return LuxonDateTime.fromObject(date.toObject(), this._getOptions()); } createDate(year: number, month: number, date: number): LuxonDateTime { + const options = this._getOptions(); + if (month < 0 || month > 11) { throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`); } @@ -139,18 +155,20 @@ export class LuxonDateAdapter extends DateAdapter { // Luxon uses 1-indexed months so we need to add one to the month. const result = this._useUTC - ? LuxonDateTime.utc(year, month + 1, date) - : LuxonDateTime.local(year, month + 1, date); + ? LuxonDateTime.utc(year, month + 1, date, options) + : LuxonDateTime.local(year, month + 1, date, options); if (!this.isValid(result)) { throw Error(`Invalid date "${date}". Reason: "${result.invalidReason}".`); } - return result.setLocale(this.locale); + return result; } today(): LuxonDateTime { - return (this._useUTC ? LuxonDateTime.utc() : LuxonDateTime.local()).setLocale(this.locale); + const options = this._getOptions(); + + return this._useUTC ? LuxonDateTime.utc(options) : LuxonDateTime.local(options); } parse(value: any, parseFormat: string | string[]): LuxonDateTime | null { @@ -201,15 +219,15 @@ export class LuxonDateAdapter extends DateAdapter { } addCalendarYears(date: LuxonDateTime, years: number): LuxonDateTime { - return date.plus({years}).setLocale(this.locale); + return date.reconfigure(this._getOptions()).plus({years}); } addCalendarMonths(date: LuxonDateTime, months: number): LuxonDateTime { - return date.plus({months}).setLocale(this.locale); + return date.reconfigure(this._getOptions()).plus({months}); } addCalendarDays(date: LuxonDateTime, days: number): LuxonDateTime { - return date.plus({days}).setLocale(this.locale); + return date.reconfigure(this._getOptions()).plus({days}); } toIso8601(date: LuxonDateTime): string { @@ -256,6 +274,7 @@ export class LuxonDateAdapter extends DateAdapter { return { zone: this._useUTC ? 'utc' : undefined, locale: this.locale, + outputCalendar: this._defaultOutputCalendar, }; } }