Skip to content

Commit

Permalink
feat(moment-dateadapter): add option to create utc dates (#11336)
Browse files Browse the repository at this point in the history
  • Loading branch information
Silthus authored and josephperrott committed Jun 27, 2018
1 parent 6d1b600 commit 9a85b9b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/lib/datepicker/datepicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,17 @@ export class MyComponent {

<!-- example(datepicker-moment) -->

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
Expand Down
11 changes: 9 additions & 2 deletions src/material-moment-adapter/adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 {}
Expand Down
30 changes: 28 additions & 2 deletions src/material-moment-adapter/adapter/moment-date-adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand All @@ -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");
Expand Down Expand Up @@ -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();
});
});
39 changes: 36 additions & 3 deletions src/material-moment-adapter/adapter/moment-date-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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<MatMomentDateAdapterOptions>(
'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<T>(length: number, valueFunction: (index: number) => T): T[] {
Expand Down Expand Up @@ -48,7 +73,10 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
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());
}
Expand Down Expand Up @@ -130,7 +158,12 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
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()) {
Expand Down

0 comments on commit 9a85b9b

Please sign in to comment.