diff --git a/src/lib/datepicker/datepicker.md b/src/lib/datepicker/datepicker.md index 0c7c08f2c537..33f4d3fd8bbf 100644 --- a/src/lib/datepicker/datepicker.md +++ b/src/lib/datepicker/datepicker.md @@ -246,6 +246,17 @@ export class MyComponent { +By default the `MomentDateAdapter` will creates dates in your time zone specific locale. You can change the default behaviour to parse dates as UTC by providing the `MAT_MOMENT_DATA_ADAPTER_OPTIONS` and setting it to `useUtc: true`. + +```ts +@NgModule({ + imports: [MatDatepickerModule, MatMomentDateModule], + providers: [ + { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } } + ] +}) +``` + It is also possible to create your own `DateAdapter` that works with any date format your app requires. This is accomplished by subclassing `DateAdapter` and providing your subclass as the `DateAdapter` implementation. You will also want to make sure that the `MAT_DATE_FORMATS` provided diff --git a/src/material-moment-adapter/adapter/index.ts b/src/material-moment-adapter/adapter/index.ts index 3f4e7077d4d0..5add99fe0794 100644 --- a/src/material-moment-adapter/adapter/index.ts +++ b/src/material-moment-adapter/adapter/index.ts @@ -12,7 +12,10 @@ import { MAT_DATE_LOCALE, MAT_DATE_FORMATS } from '@angular/material'; -import {MomentDateAdapter} from './moment-date-adapter'; +import { + MomentDateAdapter, + MAT_MOMENT_DATE_ADAPTER_OPTIONS +} from './moment-date-adapter'; import {MAT_MOMENT_DATE_FORMATS} from './moment-date-formats'; export * from './moment-date-adapter'; @@ -21,7 +24,11 @@ export * from './moment-date-formats'; @NgModule({ providers: [ - {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]} + { + provide: DateAdapter, + useClass: MomentDateAdapter, + deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] + } ], }) export class MomentDateModule {} diff --git a/src/material-moment-adapter/adapter/moment-date-adapter.spec.ts b/src/material-moment-adapter/adapter/moment-date-adapter.spec.ts index feba4da338a9..5517df6da4c4 100644 --- a/src/material-moment-adapter/adapter/moment-date-adapter.spec.ts +++ b/src/material-moment-adapter/adapter/moment-date-adapter.spec.ts @@ -11,7 +11,7 @@ import {async, inject, TestBed} from '@angular/core/testing'; import {DateAdapter, DEC, FEB, JAN, MAR, MAT_DATE_LOCALE} from '@angular/material/core'; import * as moment from 'moment'; import {MomentDateModule} from './index'; -import {MomentDateAdapter} from './moment-date-adapter'; +import {MomentDateAdapter, MAT_MOMENT_DATE_ADAPTER_OPTIONS} from './moment-date-adapter'; describe('MomentDateAdapter', () => { @@ -143,7 +143,8 @@ describe('MomentDateAdapter', () => { }); it('should create Moment date', () => { - expect(adapter.createDate(2017, JAN, 1).format()).toEqual(moment([2017, JAN, 1]).format()); + expect(adapter.createDate(2017, JAN, 1).format()) + .toEqual(moment([2017, JAN, 1]).format()); }); it('should not create Moment date with month over/under-flow', () => { @@ -164,6 +165,10 @@ describe('MomentDateAdapter', () => { expect(adapter.createDate(100, JAN, 1).year()).toBe(100); }); + it('should not create Moment date in utc format', () => { + expect(adapter.createDate(2017, JAN, 5).isUTC()).toEqual(false); + }); + it("should get today's date", () => { expect(adapter.sameDate(adapter.today(), moment())) .toBe(true, "should be equal to today's date"); @@ -408,3 +413,24 @@ describe('MomentDateAdapter with LOCALE_ID override', () => { expect(adapter.format(moment([2017, JAN, 2]), 'll')).toEqual('2 janv. 2017'); }); }); + +describe('MomentDateAdapter with MAT_MOMENT_DATE_ADAPTER_OPTIONS override', () => { + let adapter: MomentDateAdapter; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MomentDateModule], + providers: [ + { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } } + ] + }).compileComponents(); + })); + + beforeEach(inject([DateAdapter], (d: MomentDateAdapter) => { + adapter = d; + })); + + it('should create Moment date in utc format if option useUtc is set', () => { + expect(adapter.createDate(2017, JAN, 5).isUTC()).toBeTruthy(); + }); +}); diff --git a/src/material-moment-adapter/adapter/moment-date-adapter.ts b/src/material-moment-adapter/adapter/moment-date-adapter.ts index caf36dfbf6ad..96a9a64ad470 100644 --- a/src/material-moment-adapter/adapter/moment-date-adapter.ts +++ b/src/material-moment-adapter/adapter/moment-date-adapter.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, Injectable, Optional} from '@angular/core'; +import {Inject, Injectable, Optional, InjectionToken} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; // Depending on whether rollup is used, moment needs to be imported differently. // Since Moment.js doesn't have a default export, we normally need to import using the `* as` @@ -19,6 +19,31 @@ import {default as _rollupMoment, Moment} from 'moment'; const moment = _rollupMoment || _moment; +/** Configurable options for {@see MomentDateAdapter}. */ +export interface MatMomentDateAdapterOptions { + /** + * Turns the use of utc dates on or off. + * Changing this will change how Angular Material components like DatePicker output dates. + * {@default false} + */ + useUtc: boolean; +} + +/** InjectionToken for moment date adapter to configure options. */ +export const MAT_MOMENT_DATE_ADAPTER_OPTIONS = new InjectionToken( + 'MAT_MOMENT_DATE_ADAPTER_OPTIONS', { + providedIn: 'root', + factory: MAT_MOMENT_DATE_ADAPTER_OPTIONS_FACTORY +}); + + +/** @docs-private */ +export function MAT_MOMENT_DATE_ADAPTER_OPTIONS_FACTORY(): MatMomentDateAdapterOptions { + return { + useUtc: false + }; +} + /** Creates an array and fills it with values. */ function range(length: number, valueFunction: (index: number) => T): T[] { @@ -48,7 +73,10 @@ export class MomentDateAdapter extends DateAdapter { narrowDaysOfWeek: string[] }; - constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string) { + constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string, + @Optional() @Inject(MAT_MOMENT_DATE_ADAPTER_OPTIONS) + private options?: MatMomentDateAdapterOptions) { + super(); this.setLocale(dateLocale || moment.locale()); } @@ -130,7 +158,12 @@ export class MomentDateAdapter extends DateAdapter { throw Error(`Invalid date "${date}". Date has to be greater than 0.`); } - let result = moment({year, month, date}).locale(this.locale); + let result; + if (this.options && this.options.useUtc) { + result = moment.utc({ year, month, date }).locale(this.locale); + } else { + result = moment({ year, month, date }).locale(this.locale); + } // If the result isn't valid, the date must have been out of bounds for this month. if (!result.isValid()) {