Skip to content

Commit 9a85b9b

Browse files
Silthusjosephperrott
authored andcommitted
feat(moment-dateadapter): add option to create utc dates (#11336)
1 parent 6d1b600 commit 9a85b9b

File tree

4 files changed

+84
-7
lines changed

4 files changed

+84
-7
lines changed

src/lib/datepicker/datepicker.md

+11
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ export class MyComponent {
246246

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

249+
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`.
250+
251+
```ts
252+
@NgModule({
253+
imports: [MatDatepickerModule, MatMomentDateModule],
254+
providers: [
255+
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
256+
]
257+
})
258+
```
259+
249260
It is also possible to create your own `DateAdapter` that works with any date format your app
250261
requires. This is accomplished by subclassing `DateAdapter` and providing your subclass as the
251262
`DateAdapter` implementation. You will also want to make sure that the `MAT_DATE_FORMATS` provided

src/material-moment-adapter/adapter/index.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import {
1212
MAT_DATE_LOCALE,
1313
MAT_DATE_FORMATS
1414
} from '@angular/material';
15-
import {MomentDateAdapter} from './moment-date-adapter';
15+
import {
16+
MomentDateAdapter,
17+
MAT_MOMENT_DATE_ADAPTER_OPTIONS
18+
} from './moment-date-adapter';
1619
import {MAT_MOMENT_DATE_FORMATS} from './moment-date-formats';
1720

1821
export * from './moment-date-adapter';
@@ -21,7 +24,11 @@ export * from './moment-date-formats';
2124

2225
@NgModule({
2326
providers: [
24-
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]}
27+
{
28+
provide: DateAdapter,
29+
useClass: MomentDateAdapter,
30+
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS]
31+
}
2532
],
2633
})
2734
export class MomentDateModule {}

src/material-moment-adapter/adapter/moment-date-adapter.spec.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {async, inject, TestBed} from '@angular/core/testing';
1111
import {DateAdapter, DEC, FEB, JAN, MAR, MAT_DATE_LOCALE} from '@angular/material/core';
1212
import * as moment from 'moment';
1313
import {MomentDateModule} from './index';
14-
import {MomentDateAdapter} from './moment-date-adapter';
14+
import {MomentDateAdapter, MAT_MOMENT_DATE_ADAPTER_OPTIONS} from './moment-date-adapter';
1515

1616

1717
describe('MomentDateAdapter', () => {
@@ -143,7 +143,8 @@ describe('MomentDateAdapter', () => {
143143
});
144144

145145
it('should create Moment date', () => {
146-
expect(adapter.createDate(2017, JAN, 1).format()).toEqual(moment([2017, JAN, 1]).format());
146+
expect(adapter.createDate(2017, JAN, 1).format())
147+
.toEqual(moment([2017, JAN, 1]).format());
147148
});
148149

149150
it('should not create Moment date with month over/under-flow', () => {
@@ -164,6 +165,10 @@ describe('MomentDateAdapter', () => {
164165
expect(adapter.createDate(100, JAN, 1).year()).toBe(100);
165166
});
166167

168+
it('should not create Moment date in utc format', () => {
169+
expect(adapter.createDate(2017, JAN, 5).isUTC()).toEqual(false);
170+
});
171+
167172
it("should get today's date", () => {
168173
expect(adapter.sameDate(adapter.today(), moment()))
169174
.toBe(true, "should be equal to today's date");
@@ -408,3 +413,24 @@ describe('MomentDateAdapter with LOCALE_ID override', () => {
408413
expect(adapter.format(moment([2017, JAN, 2]), 'll')).toEqual('2 janv. 2017');
409414
});
410415
});
416+
417+
describe('MomentDateAdapter with MAT_MOMENT_DATE_ADAPTER_OPTIONS override', () => {
418+
let adapter: MomentDateAdapter;
419+
420+
beforeEach(async(() => {
421+
TestBed.configureTestingModule({
422+
imports: [MomentDateModule],
423+
providers: [
424+
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
425+
]
426+
}).compileComponents();
427+
}));
428+
429+
beforeEach(inject([DateAdapter], (d: MomentDateAdapter) => {
430+
adapter = d;
431+
}));
432+
433+
it('should create Moment date in utc format if option useUtc is set', () => {
434+
expect(adapter.createDate(2017, JAN, 5).isUTC()).toBeTruthy();
435+
});
436+
});

src/material-moment-adapter/adapter/moment-date-adapter.ts

+36-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Inject, Injectable, Optional} from '@angular/core';
9+
import {Inject, Injectable, Optional, InjectionToken} from '@angular/core';
1010
import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material';
1111
// Depending on whether rollup is used, moment needs to be imported differently.
1212
// 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';
1919

2020
const moment = _rollupMoment || _moment;
2121

22+
/** Configurable options for {@see MomentDateAdapter}. */
23+
export interface MatMomentDateAdapterOptions {
24+
/**
25+
* Turns the use of utc dates on or off.
26+
* Changing this will change how Angular Material components like DatePicker output dates.
27+
* {@default false}
28+
*/
29+
useUtc: boolean;
30+
}
31+
32+
/** InjectionToken for moment date adapter to configure options. */
33+
export const MAT_MOMENT_DATE_ADAPTER_OPTIONS = new InjectionToken<MatMomentDateAdapterOptions>(
34+
'MAT_MOMENT_DATE_ADAPTER_OPTIONS', {
35+
providedIn: 'root',
36+
factory: MAT_MOMENT_DATE_ADAPTER_OPTIONS_FACTORY
37+
});
38+
39+
40+
/** @docs-private */
41+
export function MAT_MOMENT_DATE_ADAPTER_OPTIONS_FACTORY(): MatMomentDateAdapterOptions {
42+
return {
43+
useUtc: false
44+
};
45+
}
46+
2247

2348
/** Creates an array and fills it with values. */
2449
function range<T>(length: number, valueFunction: (index: number) => T): T[] {
@@ -48,7 +73,10 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
4873
narrowDaysOfWeek: string[]
4974
};
5075

51-
constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string) {
76+
constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string,
77+
@Optional() @Inject(MAT_MOMENT_DATE_ADAPTER_OPTIONS)
78+
private options?: MatMomentDateAdapterOptions) {
79+
5280
super();
5381
this.setLocale(dateLocale || moment.locale());
5482
}
@@ -130,7 +158,12 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
130158
throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
131159
}
132160

133-
let result = moment({year, month, date}).locale(this.locale);
161+
let result;
162+
if (this.options && this.options.useUtc) {
163+
result = moment.utc({ year, month, date }).locale(this.locale);
164+
} else {
165+
result = moment({ year, month, date }).locale(this.locale);
166+
}
134167

135168
// If the result isn't valid, the date must have been out of bounds for this month.
136169
if (!result.isValid()) {

0 commit comments

Comments
 (0)