63

I don't know how to change the date format of the material 2 datepicker. I've read documentation but I don't understand what I actually need to do. Output date format which datepicker provides by default is f.e.: 6/9/2017

What I'm trying to achieve is to change format to one like 9-Jun-2017 or any other.

Documentation https://material.angular.io/components/component/datepicker doesn't help me at all.

starball
  • 20,030
  • 7
  • 43
  • 238
Igor Janković
  • 5,494
  • 6
  • 32
  • 46
  • here is an example https://gist.github.com/fxck/efe4ccff13d99ee9a2dcf82365909168 – Robin Dijkhof Jun 09 '17 at 08:57
  • 1
    Thanks for the help but I don't want to use my own date provider, I just want to change the date format according to documentation where it's written that native date adapter can be used. – Igor Janković Jun 09 '17 at 09:23

17 Answers17

51

Here is the only solution I found for this one:

First, create const:

const MY_DATE_FORMATS = {
   parse: {
       dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
   },
   display: {
       // dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
       dateInput: 'input',
       monthYearLabel: {year: 'numeric', month: 'short'},
       dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
       monthYearA11yLabel: {year: 'numeric', month: 'long'},
   }
};

Then you have to extend NativeDateADapter:

export class MyDateAdapter extends NativeDateAdapter {
   format(date: Date, displayFormat: Object): string {
       if (displayFormat == "input") {
           let day = date.getDate();
           let month = date.getMonth() + 1;
           let year = date.getFullYear();
           return this._to2digit(day) + '/' + this._to2digit(month) + '/' + year;
       } else {
           return date.toDateString();
       }
   }

   private _to2digit(n: number) {
       return ('00' + n).slice(-2);
   } 
}

In format function, you can choose whatever format you want

And the last step, you have to add it into module providers:

providers: [
    {provide: DateAdapter, useClass: MyDateAdapter},
    {provide: MD_DATE_FORMATS, useValue: MY_DATE_FORMATS},
],

And that's it. I can not believe that there is no some easy way to change date format through the @Input but let's hope it will be implemented in some future version of material 2 (currently beta 6).

BrunoLM
  • 97,872
  • 84
  • 296
  • 452
Igor Janković
  • 5,494
  • 6
  • 32
  • 46
  • 1
    Could you put it on plunker ?... I did exactly what your mentioned but it didn't work... – Marcogomesr Jun 30 '17 at 14:48
  • Can anyone post a working example on plunker? Thx a lot! – web2kx Jul 11 '17 at 21:29
  • 1
    It's not working for me either (beta.8). `Error: Uncaught (in promise): TypeError: Cannot read property 'dateInput' of undefined` – Robouste Jul 13 '17 at 09:14
  • And how to use it? – POV Aug 24 '17 at 08:57
  • @web2kx I applied above into plunkr, seems not working as expected please let me know https://stackoverflow.com/questions/46392275/angular-material-2-datepicker-change-date-format-mm-dd-yyyy-to-dd-mm-yyyy – Kelum Sep 24 '17 at 16:28
  • @web2kx I applied above into plunkr, seems not working as expected please let me know https://stackoverflow.com/questions/46392275/angular-material-2-datepicker-change-date-format-mm-dd-yyyy-to-dd-mm-yyyy – Kelum Sep 24 '17 at 16:29
  • 9
    FYI: MD_DATE_FORMATS as now been replaced by MAT_DATE_FORMATS. you can import it this way : `import { DateAdapter, NativeDateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from "@angular/material/core";` – remborg Nov 13 '17 at 14:39
  • 2
    For those that cant get this example working, add `constructor() {super('en-US');}` to the `MyDateAdapter` class. – crollywood Nov 20 '17 at 18:05
  • I did the same thing, but now if i put in the datepicker input: 01/01/18 with will set the year 1918, do you have a solution for this? this happens in IE and firefox – Iosif Petre Jun 07 '18 at 12:39
  • is work fine but for me if i write and choose date in picker is give error, for fixed need add to app.modoule.ts in providers property this: `{provide: MAT_DATE_LOCALE, useValue: 'en-GB'}`, and import: `import { MAT_DATE_LOCALE } from '@angular/material';` credit to this answer https://stackoverflow.com/a/46707890/7452985 – izik f Jul 08 '18 at 12:30
  • @Igor how about dd-mm-yyyy or dd/mm/yyyy – Prashant Pimpale Jul 28 '18 at 06:30
  • Worked perfectly! – Prashant Pimpale Jul 28 '18 at 06:36
43

Igor's answer didn't work for me so I asked directly on Angular 2 Material's github and someone gave me that answer which worked for me :

  1. First write your own adapter :

    import { NativeDateAdapter } from "@angular/material";
    
    
    export class AppDateAdapter extends NativeDateAdapter {
    
        format(date: Date, displayFormat: Object): string {
    
            if (displayFormat === 'input') {
    
                const day = date.getDate();
                const month = date.getMonth() + 1;
                const year = date.getFullYear();
    
                return `${day}-${month}-${year}`;
            }
    
            return date.toDateString();
        }
    }
    
  2. Create your date format :

    export const APP_DATE_FORMATS =
    {
        parse: {
            dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
        },
        display: {
            dateInput: 'input',
            monthYearLabel: { year: 'numeric', month: 'numeric' },
            dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
            monthYearA11yLabel: { year: 'numeric', month: 'long' },
        }
    };
    
  3. Provide those two to your module

    providers: [
            {
                provide: DateAdapter, useClass: AppDateAdapter
            },
            {
                provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
            }
        ]
    

More infos here

EDIT: For those who are having the trouble of the manual input is being not respected with the format, you may override the parse(value: any) function from the NativeDateAdapter as follows.

parse(value: any): Date | null {
    const date = moment(value, 'DD/MM/YYYY');
    return date.isValid() ? date.toDate() : null;
}

So, the custom adapter will take the final shape as follows.

import { NativeDateAdapter } from "@angular/material";
import * as moment from 'moment';

export class AppDateAdapter extends NativeDateAdapter {

    format(date: Date, displayFormat: Object): string {
        if (displayFormat === 'input') {

            const day = date.getDate();
            const month = date.getMonth() + 1;
            const year = date.getFullYear();

            return `${day}/${month}/${year}`;
        }

        return date.toDateString();
    }

    parse(value: any): Date | null {
        const date = moment(value, environment.APP_DATE_FORMAT);
        return date.isValid() ? date.toDate() : null;
    }
}
Romeo Sierra
  • 1,666
  • 1
  • 17
  • 35
Robouste
  • 3,020
  • 4
  • 33
  • 55
  • 2
    Prefer this due to the ES6 string literal template, reduces code significantly – jarodsmk Jul 25 '17 at 05:48
  • @Robouste this works partially. It gives a specific format like `Fri 28 Jul 2017` but if you change the format then the input and the calendar expects US format, even if you have set correctly the locale. – Vassilis Pits Aug 14 '17 at 08:51
  • 1
    @VassilisPits While the native-date-adapter format() function put it out nicely, the native-date-adapter parse() function doesn't even try. https://github.com/angular/material2/blob/master/src/lib/core/datetime/native-date-adapter.ts You can override the parse function to get the date back into a date object. This is what I did to parse 'de-DE' formatted dates 'dd.mm.yyyy' back into Date() objects. – Stephen Sep 14 '17 at 17:57
  • I applied your solution in my [plunkr](https://plnkr.co/edit/P0pcQYlT5gUHxnbBr5wM?p=preview) but this not working – Kelum Sep 24 '17 at 17:15
  • For those that cant get this example working, add `constructor() {super('en-US');}` to the `AppDateAdapter ` class. – crollywood Nov 20 '17 at 18:05
  • 1
    I believe this is now MAT_DATE_FORMATS instead of MD_? – Gaspa79 Mar 08 '18 at 15:26
  • 2
    Thanks, it works for me, however when i fill the input manually it still using the old format, do you have a solution for that? – Abdennacer Lachiheb Apr 27 '18 at 14:03
  • @AbdennacerLachiheb Check out the edit made to the post. :) – Romeo Sierra Jan 03 '20 at 12:22
20

You just need to provide a custom MAT_DATE_FORMATS

export const APP_DATE_FORMATS = {
    parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
    display: {
        dateInput: {month: 'short', year: 'numeric', day: 'numeric'},
        monthYearLabel: {year: 'numeric'}
    }
};

and add it to providers.

providers: [{
   provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
}]

Working code

onalbi
  • 2,609
  • 1
  • 24
  • 36
Abhishek Jha
  • 935
  • 2
  • 10
  • 22
12

The work around that works for me is:

my.component.html:

<md-input-container>
  <input mdInput disabled [ngModel]="someDate | date:'d-MMM-y'" >
  <input mdInput [hidden]='true' [(ngModel)]="someDate"  
[mdDatepicker]="picker">
  <button mdSuffix [mdDatepickerToggle]="picker"></button>
</md-input-container>
<md-datepicker #picker></md-datepicker> 

my.component.ts :


@Component({...
})
export class MyComponent implements OnInit {
  ....
  public someDate: Date;
  ...

So now you can have the format (Ex. 'd-MMM-y') that works best for you.

luka martinovic
  • 303
  • 2
  • 3
11

There's a high chance that you already use a library that provides you with an convinient way of manipulating (parsing, validating, displaying, etc.) dates and times in JavaScript. If you dont, take a look at one of them, for example moment.js.

Implementing your custom adapter using moment.js would look like this.

Create CustomDateAdapter.ts and implement it like this:

import { NativeDateAdapter } from "@angular/material";
import * as moment from 'moment';

export class CustomDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        moment.locale('ru-RU'); // Choose the locale
        var formatString = (displayFormat === 'input')? 'DD.MM.YYYY' : 'LLL';
        return moment(date).format(formatString);
    }
}

In your app.module.ts:

import { DateAdapter } from '@angular/material';

providers: [
    ...
    {
        provide: DateAdapter, useClass: CustomDateAdapter
    },
    ...
]

That's it. Simple, easy and no need of reinventing bicycles.

Gil Epshtain
  • 8,670
  • 7
  • 63
  • 89
Arthur Z.
  • 183
  • 1
  • 5
4

Create a constant for date format.

export const DateFormat = {
parse: {
  dateInput: 'input',
  },
  display: {
  dateInput: 'DD-MMM-YYYY',
  monthYearLabel: 'MMMM YYYY',
  dateA11yLabel: 'MM/DD/YYYY',
  monthYearA11yLabel: 'MMMM YYYY',
  }
};

And Use the below code inside app module

 providers: [
  { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
  { provide: MAT_DATE_FORMATS, useValue: DateFormat }
]
Mohan Singh
  • 1,142
  • 3
  • 15
  • 30
  • This worked but seemed to have a collision with the formControl validation. Haven't dug into it too much though. – Josh Leslie Feb 12 '19 at 22:27
3

Robouste worked perfect!!

I made easy one (Angular 4 "@angular/material": "^2.0.0-beta.10") first made datepicker.module.ts



    import { NgModule }  from '@angular/core';
    import { MdDatepickerModule, MdNativeDateModule, NativeDateAdapter, DateAdapter, MD_DATE_FORMATS  }  from '@angular/material';

    class AppDateAdapter extends NativeDateAdapter {
        format(date: Date, displayFormat: Object): string {
            if (displayFormat === 'input') {
                const day = date.getDate();
                const month = date.getMonth() + 1;
                const year = date.getFullYear();
                return `${year}-${month}-${day}`;
            } else {
                return date.toDateString();
            }
        }
    }

    const APP_DATE_FORMATS = {
    parse: {
    dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
    },
    display: {
    // dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
    dateInput: 'input',
    monthYearLabel: {year: 'numeric', month: 'short'},
    dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
    monthYearA11yLabel: {year: 'numeric', month: 'long'},
    }
    };

    @NgModule({
    declarations:  [ ],
    imports:  [ ],
        exports:  [ MdDatepickerModule, MdNativeDateModule ],
    providers: [
    {
        provide: DateAdapter, useClass: AppDateAdapter
    },
    {
        provide: MD_DATE_FORMATS, useValue: APP_DATE_FORMATS
    }
    ]
    })

    export class DatePickerModule {

    }

just import it (app.module.ts)


    import {Component, NgModule, VERSION,  ReflectiveInjector}   from '@angular/core'//NgZone,
    import { CommonModule }              from '@angular/common';
    import {BrowserModule}               from '@angular/platform-browser'
    import { BrowserAnimationsModule }        from '@angular/platform-browser/animations';
    import { FormsModule }              from '@angular/forms';
    import { DatePickerModule }            from './modules/date.picker/datepicker.module';

    @Component({
    selector: 'app-root',
    template: `
    <input (click)="picker.open()" [mdDatepicker]="picker" placeholder="Choose a date" [(ngModel)]="datepicker.SearchDate"  >
    <md-datepicker-toggle mdSuffix [for]="picker"></md-datepicker-toggle>
    <md-datepicker #picker touchUi="true"  ></md-datepicker>
    `,
    })


    export class App{
        datepicker = {SearchDate:new Date()}
        constructor( ) {}

        }

    @NgModule({
    declarations: [ App ],
    imports: [ CommonModule, BrowserModule, BrowserAnimationsModule, FormsModule, DatePickerModule],
    bootstrap: [ App ],
    providers: [   ]//NgZone
    })
    export class AppModule {}

YoungHyeong Ryu
  • 929
  • 7
  • 9
3

Why to not use Angular DatePipe?

import {Component} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, NativeDateAdapter} from '@angular/material';
import {FormControl} from '@angular/forms';
import {DatePipe} from '@angular/common';

export const PICK_FORMATS = {
    parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
    display: {
        dateInput: 'input',
        monthYearLabel: {year: 'numeric', month: 'short'},
        dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
        monthYearA11yLabel: {year: 'numeric', month: 'long'}
    }
};
class PickDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        if (displayFormat === 'input') {
            return new DatePipe('en-US').transform(date, 'EEE, MMM dd, yyyy');
        } else {
            return date.toDateString();
        }
    }
}
@Component({
    selector: 'custom-date',
    template: `<mat-form-field>
                   <input matInput [formControl]="date" />
                   <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
                   <mat-datepicker #picker></mat-datepicker>
               </mat-form-field>`,
    providers: [
        {provide: DateAdapter, useClass: PickDateAdapter},
        {provide: MAT_DATE_FORMATS, useValue: PICK_FORMATS}
    ]
})
export class DateComponent {
    date = new FormControl(new Date());
    constructor() {}
}
onalbi
  • 2,609
  • 1
  • 24
  • 36
2

original idea of Arthur z and Gil Epshtain, I have changed moment to date-fns. tested in angular @angular/material": "^10.0.2.

Create CustomDateAdapter.ts and implement it like this:

import { NativeDateAdapter } from "@angular/material/core";
import { format } from 'date-fns';
import { es } from 'date-fns/locale'

export class CustomDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        var formatString = (displayFormat === 'input')? 'DD.MM.YYYY' : 'dd-MM-yyyy';
        return format(date, formatString, {locale: es});
    }
}

In your app.module.ts:

import { DateAdapter } from '@angular/material';

providers: [
    ...
    {
        provide: DateAdapter, useClass: CustomDateAdapter
    },
    ...
]
Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
user12452512
  • 71
  • 1
  • 2
1

I used the solution propose by @igor-janković and had the problem of "Error: Uncaught (in promise): TypeError: Cannot read property 'dateInput' of undefined". I realized that this problem was because MY_DATE_FORMATS need to be declare like type MdDateFormats:

export declare type MdDateFormats = {
    parse: {
        dateInput: any;
    };
    display: {
        dateInput: any;
        monthYearLabel: any;
        dateA11yLabel: any;
        monthYearA11yLabel: any;
    };
};

So, the correct way of declare MY_DATE_FORMATS is:

const MY_DATE_FORMATS:MdDateFormats = {
   parse: {
       dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
   },
   display: {
       dateInput: 'input',
       monthYearLabel: {year: 'numeric', month: 'short'},
       dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
       monthYearA11yLabel: {year: 'numeric', month: 'long'},
   }
};

With the above modification the solution work for me.

Regards

ffcc
  • 50
  • 1
  • 1
  • 10
1

create a file date.adapter.ts

import { NativeDateAdapter, DateAdapter, MAT_DATE_FORMATS, MatDateFormats } from "@angular/material";

export class AppDateAdapter extends NativeDateAdapter {
    parse(value: any): Date | null {
        if ((typeof value === 'string') && (value.indexOf('/') > -1)) {
          const str = value.split('/');
          const year = Number(str[2]);
          const month = Number(str[1]) - 1;
          const date = Number(str[0]);
          return new Date(year, month, date);
        }
        const timestamp = typeof value === 'number' ? value : Date.parse(value);
        return isNaN(timestamp) ? null : new Date(timestamp);
      }
   format(date: Date, displayFormat: string): string {
       if (displayFormat == "input") {
          let day = date.getDate();
          let month = date.getMonth() + 1;
          let year = date.getFullYear();
          return   year + '-' + this._to2digit(month) + '-' + this._to2digit(day)   ;
       } else if (displayFormat == "inputMonth") {
          let month = date.getMonth() + 1;
          let year = date.getFullYear();
          return  year + '-' + this._to2digit(month);
       } else {
           return date.toDateString();
       }
   }
   private _to2digit(n: number) {
       return ('00' + n).slice(-2);
   }
}
export const APP_DATE_FORMATS =
{
   parse: {
       dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
   },
   display: {
       dateInput: 'input',
       monthYearLabel: 'inputMonth',
       dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
       monthYearA11yLabel: {year: 'numeric', month: 'long'},
   }
}

app.module.ts

  providers: [
    DatePipe,
    {
        provide: DateAdapter, useClass: AppDateAdapter
    },
    {
        provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
    }
    ]

app.component.ts

import { FormControl } from '@angular/forms';
import { DatePipe } from '@angular/common';
@Component({
  selector: 'datepicker-overview-example',
  templateUrl: 'datepicker-overview-example.html',
  styleUrls: ['datepicker-overview-example.css'],
  providers: [
    DatePipe,
    {
        provide: DateAdapter, useClass: AppDateAdapter
    },
    {
        provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
    }
    ]
})
export class DatepickerOverviewExample {
  day = new Date();
  public date;
 constructor(private datePipe: DatePipe){
    console.log("anh "," " +datePipe.transform(this.day.setDate(this.day.getDate()+7)));
    this.date = new FormControl(this.datePipe.transform(this.day.setDate(this.day.getDate()+7)));
    console.log("anht",' ' +new Date());
 }
}

app.component.html

<mat-form-field>
  <input matInput [matDatepicker]="picker" placeholder="Choose a date" [formControl]="date">
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker></mat-datepicker>
</mat-form-field>
Tienanhvn
  • 239
  • 5
  • 9
1

angular material date will return the format below (just console.log to see it)

Moment {_isAMomentObject: true, _i: {…}, _isUTC: false, _pf: {…}, _locale: Locale, …} _d: Thu Jan 28 2021 00:00:00 GMT+0800 (Singapore Standard Time) {}

_i: {year: 2021, month: 0, date: 28}

_isAMomentObject: true........

so I convert to short date by using template literals

due_date = ${due_date._i.year}-${due_date._i.month + 1}-${due_date._i.date}

you will get "YYYY-MM-DD" format

Jeff
  • 11
  • 2
0

This is work for me!

import {Component} from '@angular/core';
import {FormControl} from '@angular/forms';
import {MomentDateAdapter, MAT_MOMENT_DATE_ADAPTER_OPTIONS} from '@angular/material-moment-adapter';
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core';

// 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`
// syntax. However, rollup creates a synthetic default module and we thus need to import it using
// the `default as` syntax.
import * as _moment from 'moment';
// tslint:disable-next-line:no-duplicate-imports
import {default as _rollupMoment} from 'moment';

const moment = _rollupMoment || _moment;

// See the Moment.js docs for the meaning of these formats:
// https://momentjs.com/docs/#/displaying/format/
export const MY_FORMATS = {
parse: {
    dateInput: 'LL',
},
display: {
    dateInput: 'LL',
    monthYearLabel: 'MMM YYYY',
    dateA11yLabel: 'LL',
    monthYearA11yLabel: 'MMMM YYYY',
},
};

/** @title Datepicker with custom formats */
@Component({
selector: 'datepicker-formats-example',
templateUrl: 'datepicker-formats-example.html',
providers: [
    // `MomentDateAdapter` can be automatically provided by importing `MomentDateModule` in your
    // application's root module. We provide it at the component level here, due to limitations of
    // our example generation script.
    {
    provide: DateAdapter,
    useClass: MomentDateAdapter,
    deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS]
    },

    {provide: MAT_DATE_FORMATS, useValue: MY_FORMATS},
],
})
export class YourDatepickerUsedComponent {
    date = new FormControl(moment());
}

Link: https://material.angular.io/components/datepicker/examples and search "Datepicker with custom formats"

lahiru dilshan
  • 690
  • 9
  • 13
0

All tested using Angular 14 and Material 14

This code is unique because it allows for MatDatePicker formats to be changed on an individual use basis, requires no external libraries (by using the built-in Angular DatePipe), and defaults to MAT_NATIVE_DATE_FORMATS for all other dates shown in the date picker (besides the one visible in the input, which is what we are customizing). To see those defaults specified by MAT_NATIVE_DATE_FORMATS, check out its definition on Github.

  1. Create a custom DateAdapter which extends NativeDateAdapter and overrides the parent format() function, but falls back on the parent via super.format() if no custom format string is provided.
import { DatePipe } from '@angular/common';
import { Injectable } from '@angular/core';
import { MAT_NATIVE_DATE_FORMATS, MatDateFormats, NativeDateAdapter } from '@angular/material/core';

@Injectable()
export class DatePipeDateAdapter extends NativeDateAdapter {
  override format(date: Date, displayFormat: Object): string {
    // Use DatePipe to format date however you specify
    if (typeof displayFormat === 'string') {
      return new DatePipe('en-US').transform(date, displayFormat) as string;
    }

    // Default to parent class format() if no custom format string is given
    return super.format(date, displayFormat);
  }

  // This function creates a custom `MatDateFormats` object that 
  // defaults all values to `MAT_NATIVE_DATE_FORMATS` except for
  // the `display.dateInput` property, which gets set by the user
  // via this `displayFormat` parameter. This parameter ultimately
  // gets passed to the Angular `DatePipe` in the `format()` 
  // function above, so it can be any format value that `DatePipe`
  // accepts:
  //    https://angular.io/api/common/DatePipe#usage-notes
  static createCustomMatDateFormats(displayFormat: string): MatDateFormats {
    const customDateInputFormats: MatDateFormats = {
      ...MAT_NATIVE_DATE_FORMATS,
      display: {
        ...MAT_NATIVE_DATE_FORMATS.display,
        dateInput: displayFormat,
      }
    }

    return customDateInputFormats;
  }
}
  1. Provide our custom DateAdapter and MAT_DATE_FORMATS. By providing these in the component, only MatDatePickers used inside this component will be affected. If you want all MatDatePickers to be affected, provide these inside AppModule.
@Component({
  ...,
  providers: [
    { provide: DateAdapter, useClass: DatePipeDateAdapter },
    {
      provide: MAT_DATE_FORMATS,
      // Pass any format string you would pass to DatePipe
      useValue: DatePipeDateAdapter.createCustomMatDateFormats('EEE, MMM dd, yyyy'),
    },
  ],
})

In my particular use-case, I have the <input> set to readonly, so the user is forced to change the date via the date picker by clicking on its surrounding <mat-form-field> or its connected <mat-datepicker-toggle>.

<mat-form-field (click)="crewDate.open()">
  <input type="text" placeholder="Date of Crews"
    readonly
    matInput
    [formControl]="this.crewDateControl"
    [matDatepicker]="crewDate"
  >
  <mat-datepicker-toggle matSuffix [for]="crewDate"></mat-datepicker-toggle>
  <mat-datepicker #crewDate></mat-datepicker>
</mat-form-field>

For this reason, I did not need to override the parse() function in DatePipeDateAdapter, but if you do need to, check out some of the other examples for how to implement a custom parse() function.

JWess
  • 602
  • 7
  • 17
0

Igor's answer didn't work for me either. So I came along with the following solution:

Adapter:

export const APP_DATE_FORMATS = {
    ...MAT_DATE_FORMATS,
    parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
    display: {
        dateInput: {month: 'short', year: 'numeric', day: 'numeric'},
        monthYearLabel: {month: 'short', year: 'numeric'},
    }
};

@Injectable()
export class AppDateAdapter extends NativeDateAdapter {
    actualYear = (new Date()).getFullYear() - 2000;
    format(date: Date, displayFormat: Object): string {
        if (displayFormat === APP_DATE_FORMATS.display.dateInput) {
            const day = date.getDate();
            const month = date.getMonth() + 1;
            const year = date.getFullYear();

            return `${AppDateAdapter._to2digit(day)}.${AppDateAdapter._to2digit(month)}.${year}`;
        }

        return date.toLocaleDateString();
    }

    private static _to2digit(n: number) {
        return ('00' + n).slice(-2);
    }

    parse(value: any): Date | null {
        const matches = value.match(/[0-9]{1,2}[\.\-\/][0-9]{1,2}([\.\-\/][0-9]{1,4})?/gi);
        if (matches) {
            const splits = value.split(/[\.\-\/]/);
            const year = splits[2] ?
                (splits[2] <= this.actualYear + 10 ?
                    Number(splits[2]) + 2000 :
                    splits[2]) :
                this.actualYear + 2000;
            return new Date(year,splits[1] - 1, splits[0]);
        }
        return new Date(value);
    }
}

Providers:

    providers: [
        { provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS },
        { provide: DateAdapter, useClass: AppDateAdapter },
    ]

Advantages:

  • accepts also short dates like 3.6.
  • accepts .-/ as seperators
  • the century for short dates from -90 years until +10 years will be set automatically (default is from 1950 until 2049)
Marc-Iten
  • 1
  • 1
-1

From documentation:

Customizing the parse and display formats

The MD_DATE_FORMATS object is just a collection of formats that the datepicker uses when parsing and displaying dates. These formats are passed through to the DateAdapter so you will want to make sure that the format objects you're using are compatible with the DateAdapter used in your app. This example shows how to use the native Date implementation from material, but with custom formats.

@NgModule({
  imports: [MdDatepickerModule],
  providers: [
    {provide: DateAdapter, useClass: NativeDateAdapter},
    {provide: MD_DATE_FORMATS, useValue: MY_NATIVE_DATE_FORMATS},
  ],
})
export class MyApp {}
  1. Add required to NgModule.
  2. Create your own format - MY_NATIVE_DATE_FORMATS
andrey.shedko
  • 3,128
  • 10
  • 61
  • 121
  • 2
    Can you please explain me how to create MY_NATIVE_DATE_FORMATS? How it should look, that's the part I don't understand. – Igor Janković Jun 09 '17 at 08:40
  • If to believe to what said there - `collection of formats`, this mean that you should create class with @Injectable and put there string array of formats. P.S. I did not tried this myself, but basing on what said in documentation, it should be like that. – andrey.shedko Jun 09 '17 at 08:46
  • @andrey.shedko Unfortunately it's this exact issue that Igor was experiencing that lead me here too, and I'm sure others will follow. If you could update your answer to fill in that gap, it would be much appreciated – jarodsmk Jul 25 '17 at 05:39
-1

Here's my solution with the least amount of code and using the MAT_NATIVE_DATE_FORMATS.

  1. Declare your own date formats
import { MatDateFormats, MAT_NATIVE_DATE_FORMATS } from '@angular/material';

export const GRI_DATE_FORMATS: MatDateFormats = {
  ...MAT_NATIVE_DATE_FORMATS,
  display: {
    ...MAT_NATIVE_DATE_FORMATS.display,
    dateInput: {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
    } as Intl.DateTimeFormatOptions,
  }
};
  1. Use them
@Component({
  selector: 'app-vacation-wizard',
  templateUrl: './vacation-wizard.component.html',
  styleUrls: ['./vacation-wizard.component.scss'],
  providers: [
    { provide: MAT_DATE_FORMATS, useValue: GRI_DATE_FORMATS },
  ]
})

Don't forget to set the appropriate language!

this.adapter.setLocale(this.translate.currentLang);

That's all!

Nato Boram
  • 4,083
  • 6
  • 28
  • 58