180

I want to display Date using European format dd/MM/yyyy but using DatePipe shortDate format it only display using US date style MM/dd/yyyy.
I'm assuming thats the default locale is en_US. Maybe I am missing in the docs but how can I change the default locale settings in an Angular2 app? Or maybe is there some way to pass a custom format to DatePipe ?

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
nsbm
  • 5,842
  • 6
  • 30
  • 45
  • 1
    I'd like to know this too. I've found the date pipe docs which explains the order of the y's m' and d's in the format string are ignored as the order is set by the locale. But no indication of how to set (or even get) the locale. – Mark Farmiloe Jan 26 '16 at 16:01

15 Answers15

315

As of Angular2 RC6, you can set default locale in your app module, by adding a provider:

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "en-US" }, //replace "en-US" with your locale
    //otherProviders...
  ]
})

The Currency/Date/Number pipes should pick up the locale. LOCALE_ID is an OpaqueToken, to be imported from angular/core.

import { LOCALE_ID } from '@angular/core';

For a more advanced use case, you may want to pick up locale from a service. Locale will be resolved (once) when component using date pipe is created:

{
  provide: LOCALE_ID,
  deps: [SettingsService],      //some service handling global settings
  useFactory: (settingsService) => settingsService.getLanguage()  //returns locale string
}

Hope it works for you.

Superole
  • 1,329
  • 21
  • 29
corolla
  • 5,386
  • 1
  • 23
  • 21
  • 66
    I'm amazed this still doesn't appear to be documented anywhere. Not on the Date Pipe page (https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html), not on the general pipes page (https://angular.io/docs/ts/latest/guide/pipes.html) and this question is actually the first hit on Google (https://www.google.com/search?q=angular%202%20locales&rct=j). Great find. – J.P. Oct 04 '16 at 14:24
  • Also: Setting this locale doesn't seem to affect the `currency` pipe (Angular 2.0 final). – J.P. Oct 04 '16 at 14:32
  • Does this also mean we can use an HTTP request to get the locale? Not entirely sure how that works. – Diego Ledesma Oct 07 '16 at 21:10
  • @Hyperd, yeah, check out the APP_INITIALIZER approach from the following answer - you'd have a chance to resolve locale before app initializes: http://stackoverflow.com/a/37611614/495244 – corolla Oct 22 '16 at 20:27
  • 2
    To use a pipe in code you must now format it as `new CurrencyPipe('en-US');`. Hopefully this is useful for something as this showed up as the first result when Googling my issue. – Ash Blue Nov 24 '16 at 00:51
  • @corolla, seems like LOCALE_ID provider gets called before APP_INITIALIZER (weird!) so you can't really reach your service. – rook Mar 21 '17 at 22:08
  • I use this simple factory function without creating a SettingsService: `() => navigator.language` – Steven Liekens Mar 27 '17 at 12:58
  • 1
    @corolla Can u shed some light on that service? I would like to change the locale when the app is running, is that possible with that service? And how would i implement such service? – Martijn van den Bergh Jun 01 '17 at 07:16
  • 1
    @MartijnvandenBergh, the service just returns locale string - nothing fancy. We've had mixed results trying to change locale while app runs. Ended up reloading page to handle all cases. YMMV. – corolla Jun 06 '17 at 06:22
  • @J.P.tenBerge as of now, there is one reference here https://angular.io/guide/i18n – carkod Jan 04 '19 at 07:45
  • 2
    I also struggled a lot with this subject and I hope the article I wrote about this can help some people: https://medium.com/dailyjs/dynamic-locales-in-angular-dd9a527ebe1f – Michael Karén Feb 12 '19 at 13:43
  • @MichaelKarén ugh, that website has the most obnoxious popup on the internet, I was unable to reach the article before closing the browser tab – JohnF Jul 22 '19 at 12:08
  • @JohnF Yes, I know. Going to move away from it soon. – Michael Karén Jul 23 '19 at 13:26
  • @corolla it says Parameter 'settingsService' implicitly has an 'any' type , Error – Saurabh Aug 28 '19 at 05:36
  • In my case the factory is only called once. :( `{ provide: LOCALE_ID, useFactory: (translate: TranslateService) => {return translate.currentLang; }, deps: [TranslateService] }` (ngx-translate). And the `currentLang` is undefined because set a little bit later. (init order). Why is the factory only called once? How to set LOCALE_ID dynamically? – Domske Oct 31 '19 at 14:05
  • @Dominik check [this answer](https://stackoverflow.com/a/54803065/6640527) to change language on runtime – Diego Osornio May 20 '20 at 19:20
  • Before spend some hours in this...finally get it and its thanks to you @corolla. GGWP!! – AdamWist Feb 04 '22 at 09:10
92

Solution with LOCALE_ID is great if you want to set the language for your app once. But it doesn’t work, if you want to change the language during runtime. For this case you can implement custom date pipe.

import { DatePipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Pipe({
  name: 'localizedDate',
  pure: false
})
export class LocalizedDatePipe implements PipeTransform {

  constructor(private translateService: TranslateService) {
  }

  transform(value: any, pattern: string = 'mediumDate'): any {
    const datePipe: DatePipe = new DatePipe(this.translateService.currentLang);
    return datePipe.transform(value, pattern);
  }

}

Now if you change the app display language using TranslateService (see ngx-translate)

this.translateService.use('en');

the formats within your app should automatically being updated.

Example of use:

<p>{{ 'note.created-at' | translate:{date: note.createdAt | localizedDate} }}</p>
<p>{{ 'note.updated-at' | translate:{date: note.updatedAt | localizedDate:'fullDate'} }}</p>

or check my simple "Notes" project here.

enter image description here

Milan Hlinák
  • 4,260
  • 1
  • 30
  • 41
  • I am getting template parse error; can't compile filter 'localizedDate' I used with the same way as suggested. – Prasad Shinde Sep 26 '17 at 14:06
  • Have you declared LocalizedDatePipe correctly? See pipe.module.ts in my [example project](https://github.com/milanhlinak/notes/blob/master/notes-ui/src/app/shared/pipes/pipes.module.ts). – Milan Hlinák Sep 27 '17 at 11:34
  • Yes, I have solved it earlier, @Milan Hlinak I should have answered on my comment at that time only. But anyways thanks for your prompt response. You're doing great. – Prasad Shinde Sep 28 '17 at 08:45
  • This is apparently what i was looking for. Its a shame that a custom pipe is required to just change Locale at runtime though.. – dendimiiii Oct 23 '17 at 08:12
  • 3
    It works but pay attention that use an "impure" pipes is slower than the "pure". As [Angular guide](https://angular.io/guide/pipes) says: Angular executes an impure pipe during every component change detection cycle. An impure pipe is called often, as often as every keystroke or mouse-move. With that concern in mind, implement an impure pipe with great care. An expensive, long-running pipe could destroy the user experience. – Luca Ritossa Nov 28 '17 at 10:33
  • Hi @LucaRitossa, thanks for comment. I have not found another way to do it. If you have some tip, please post it. :) +1 btw – Milan Hlinák Feb 05 '18 at 20:59
  • Check my answer for changing language on runtime without creating custom pipe. – knnhcn Feb 21 '19 at 09:05
  • Why was the pipe made impure? – Sasuke Uchiha May 28 '20 at 13:18
91

With angular5 the above answer no longer works!

The following code:

app.module.ts

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
    //otherProviders...
  ]
})

Leads to following error:

Error: Missing locale data for the locale "de-at".

With angular5 you have to load and register the used locale file on your own.

app.module.ts

import { NgModule, LOCALE_ID } from '@angular/core';
import { registerLocaleData } from '@angular/common';
import localeDeAt from '@angular/common/locales/de-at';

registerLocaleData(localeDeAt);

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
    //otherProviders...
  ]
})

Documentation

Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
zgue
  • 3,793
  • 9
  • 34
  • 39
54

If you use TranslateService from @ngx-translate/core, below is a version without creating a new pipe which works with switching dynamically on runtime (tested on Angular 7). Using DatePipe's locale parameter (docs):

First, declare the locales you use in your app, e.g. in app.component.ts:

import localeIt from '@angular/common/locales/it';
import localeEnGb from '@angular/common/locales/en-GB';
.
.
.
ngOnInit() {
    registerLocaleData(localeIt, 'it-IT');
    registerLocaleData(localeEnGb, 'en-GB');
}

Then, use your pipe dynamically:

myComponent.component.html

<span>{{ dueDate | date: 'shortDate' : '' : translateService.currentLang }}</span>

myComponent.component.ts

 constructor(public translateService: TranslateService) { ... }
knnhcn
  • 1,071
  • 1
  • 11
  • 22
  • 3
    This is surprisingly nice. You don't even need @ngx-translate for that. Can you explain what the statement in the template does though? – lama May 17 '20 at 18:06
  • 3
    @lama, **dueDate** *(any date you want to format)* **| date: 'shortDate'** *(1st parameter for date pipe corresponding to 'format')* : '' *(2nd parameter => timeZone, "When not supplied, uses the end-user's local system timezone".)* : **trasnlateService.currentLang** *(3rd parameter => local), chick this [DatePipe](https://angular.io/api/common/DatePipe#parameters)* – Diego Osornio May 20 '20 at 18:53
  • what if you have customized format? would that be localized too? – Wildhammer Jun 01 '20 at 15:51
  • One drawback is that you need to make the translateService public so it's accessible by the template... – plgod Aug 27 '20 at 14:16
  • 1
    Why exactly do you think that this is a drawback? I am interested and would like to know ;) – knnhcn Sep 01 '20 at 14:02
  • 2
    Best solution in my opinion, but works perfecly fine without @ngx-translate and TranslateService in my case. – Boommeister Jul 19 '21 at 11:09
17

On app.module.ts add the following imports. There is a list of LOCALE options here.

import es from '@angular/common/locales/es';
import { registerLocaleData } from '@angular/common';
registerLocaleData(es);

Then add the provider

@NgModule({
  providers: [
    { provide: LOCALE_ID, useValue: "es-ES" }, //your locale
  ]
})

Use pipes in html. Here is the angular documentation for this.

{{ dateObject | date: 'medium' }}
Alejandro del Río
  • 3,966
  • 3
  • 33
  • 31
12

I've had a look in date_pipe.ts and it has two bits of info which are of interest. near the top are the following two lines:

// TODO: move to a global configurable location along with other i18n components.
var defaultLocale: string = 'en-US';

Near the bottom is this line:

return DateFormatter.format(value, defaultLocale, pattern);

This suggests to me that the date pipe is currently hard-coded to be 'en-US'.

Please enlighten me if I am wrong.

Mark Farmiloe
  • 396
  • 3
  • 8
5

Starting from Angular 9 localization process changed. Check out official doc.

Follow the steps below:

  1. Add localization package if it's not there yet: ng add @angular/localize
  2. As it's said in docs:

The Angular repository includes common locales. You can change your app's source locale for the build by setting the source locale in the sourceLocale field of your app's workspace configuration file (angular.json). The build process (described in Merge translations into the app in this guide) uses your app's angular.json file to automatically set the LOCALE_ID token and load the locale data.

so set locale in angular.json like this (list of available locales can be found here):

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "test-app": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "i18n": {
        "sourceLocale": "es"
      },
      ....
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          ...
          "configurations": {
            "production": {
             ...
            },
            "ru": {
              "localize": ["ru"]
            },
            "es": {
              "localize": ["es"]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "test-app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "test-app:build:production"
            },
            "ru":{
              "browserTarget": "test-app:build:ru"
            },
            "es": {
              "browserTarget": "test-app:build:es"
            }
          }
        },
        ...
      }
    },
    ...
  "defaultProject": "test-app"
}

Basically you need to define sourceLocale in i18n section and add build configuration with specific locale like "localize": ["es"]. Optionally you can add it so serve section

  1. Build app with specific locale using build or serve: ng serve --configuration=es
Petr Pokrovskiy
  • 725
  • 7
  • 17
  • 1
    As always, you get a much more concise and clear explanation in StackOverflow than Angular official documentation. – Deniz Aug 18 '21 at 18:14
4

You do something like this:

{{ dateObj | date:'shortDate' }}

or

{{ dateObj | date:'ddmmy' }}

See: https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html

Evan Wieland
  • 1,445
  • 1
  • 20
  • 36
Langley
  • 5,326
  • 2
  • 26
  • 42
  • sorry if it wasnt clear in my question but this is exactly what im doing but with pattern 'shortDate' and it shows only in US style. The time style is fine. – nsbm Jan 20 '16 at 16:01
  • The second example shows a format getting passed to the DatePipe, that's what you wanted no? – Langley Jan 20 '16 at 16:03
  • Tried but it doesnt work. Show just the number '5' independently of the date. – nsbm Jan 20 '16 at 16:06
4

I was struggling with the same issue and didn't work for me using this

{{dateObj | date:'ydM'}}

So, I've tried a workaround, not the best solution but it worked:

{{dateObj | date:'d'}}/{{dateObj | date:'M'}}/{{dateObj | date:'y'}}

I can always create a custom pipe.

4

For those having problems with AOT, you need to do it a little differently with a useFactory:

export function getCulture() {
    return 'fr-CA';
}

@NgModule({
  providers: [
    { provide: LOCALE_ID, useFactory: getCulture },
    //otherProviders...
  ]
})
vidalsasoon
  • 4,365
  • 1
  • 32
  • 40
3

Above answers are certainly correct. Note that is is also possible to pass the locale with the pipe:

  {{ now | date: undefined:undefined:'de-DE' }}

(The 2 first parameters being date format and timezone, leave them undefined if you are great with the defaults)

Not something you want to do for all your pipes, but sometimes it can be handy.

David Bulté
  • 2,988
  • 3
  • 31
  • 43
2

Using Pipes and No other installations.

LocalizedDatePipe.ts

import { Pipe, PipeTransform } from '@angular/core';
import { Locale } from 'src/app/contentful/interfaces/locale';

@Pipe({
  name: 'localizedDate',
})
export class LocalizedDatePipe implements PipeTransform {
  transform(value: any, locale: any): any {
    const date = new Date(value);
    const options: Intl.DateTimeFormatOptions = {
      month: 'short',
      day: 'numeric',
      year: 'numeric',
    };
    return date.toLocaleDateString(locale, options);
  }
}

Search-overlay.component.html

<span *ngIf="card.date" class="hero-cards-carousel__date">
 {{ card.date | localizedDate: vm.locale?.code }}
 </span>

Result

"20. Dez. 2012"

Surya R Praveen
  • 3,393
  • 1
  • 24
  • 25
0

Copied the google pipe changed the locale and it works for my country it is posible they didnt finish it for all locales. Below is the code.

import {
    isDate,
    isNumber,
    isPresent,
    Date,
    DateWrapper,
    CONST,
    isBlank,
    FunctionWrapper
} from 'angular2/src/facade/lang';
import {DateFormatter} from 'angular2/src/facade/intl';
import {PipeTransform, WrappedValue, Pipe, Injectable} from 'angular2/core';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';


var defaultLocale: string = 'hr';

@CONST()
@Pipe({ name: 'mydate', pure: true })
@Injectable()
export class DatetimeTempPipe implements PipeTransform {
    /** @internal */
    static _ALIASES: { [key: string]: String } = {
        'medium': 'yMMMdjms',
        'short': 'yMdjm',
        'fullDate': 'yMMMMEEEEd',
        'longDate': 'yMMMMd',
        'mediumDate': 'yMMMd',
        'shortDate': 'yMd',
        'mediumTime': 'jms',
        'shortTime': 'jm'
    };


    transform(value: any, args: any[]): string {
        if (isBlank(value)) return null;

        if (!this.supports(value)) {
            console.log("DOES NOT SUPPORT THIS DUEYE ERROR");
        }

        var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
        if (isNumber(value)) {
            value = DateWrapper.fromMillis(value);
        }
        if (StringMapWrapper.contains(DatetimeTempPipe._ALIASES, pattern)) {
            pattern = <string>StringMapWrapper.get(DatetimeTempPipe._ALIASES, pattern);
        }
        return DateFormatter.format(value, defaultLocale, pattern);
    }

    supports(obj: any): boolean { return isDate(obj) || isNumber(obj); }
}
Dživo Jelić
  • 1,723
  • 3
  • 25
  • 47
0

Ok, I propose this solution, very simple, using ngx-translate

import { DatePipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Pipe({
  name: 'localizedDate',
  pure: false
})
export class LocalizedDatePipe implements PipeTransform {

  constructor(private translateService: TranslateService) {
}

  transform(value: any): any {
    const date = new Date(value);

    const options = { weekday: 'long',
                  year: 'numeric',
                  month: 'long',
                  day: 'numeric',
                  hour: '2-digit',
                  minute: '2-digit',
                  second: '2-digit'
                    };

    return date.toLocaleString(this.translateService.currentLang, options);
  }

}
LizanLycan
  • 11
  • 3
-1

This might be a little bit late, but in my case (angular 6), I created a simple pipe on top of DatePipe, something like this:

private _regionSub: Subscription;
private _localeId: string;

constructor(private _datePipe: DatePipe, private _store: Store<any>) {
  this._localeId = 'en-AU';
  this._regionSub = this._store.pipe(select(selectLocaleId))
    .subscribe((localeId: string) => {
      this._localeId = localeId || 'en-AU';
    });
}

ngOnDestroy() { // Unsubscribe }

transform(value: string | number, format?: string): string {
  const dateFormat = format || getLocaleDateFormat(this._localeId, FormatWidth.Short);
  return this._datePipe.transform(value, dateFormat, undefined, this._localeId);
}

May not be the best solution, but simple and works.

Ngoc Nam Nguyen
  • 493
  • 6
  • 15