¿Cómo establecer la configuración regional en DatePipe en Angular 2?

138

Quiero mostrar la fecha con el formato europeo, dd/MM/yyyypero con el formato DatePipe shortDate solo se muestra con el estilo de fecha de EE MM/dd/yyyy. UU .
Supongo que esa configuración regional predeterminada es en_US. Tal vez me faltan los documentos, pero ¿cómo puedo cambiar la configuración regional predeterminada en una aplicación Angular2? ¿O tal vez hay alguna forma de pasar un formato personalizado a DatePipe?

nsbm
fuente
1
Me gustaría saber esto también. He encontrado los documentos de la tubería de fecha que explican el orden de las y 'm' yd en la cadena de formato se ignoran a medida que el orden lo establece la configuración regional. Pero no hay indicaciones de cómo configurar (o incluso obtener) la configuración regional.
Mark Farmiloe

Respuestas:

276

A partir de Angular2 RC6, puede establecer la configuración regional predeterminada en el módulo de su aplicación, agregando un proveedor:

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

Las tuberías Moneda / Fecha / Número deben recoger la configuración regional. LOCALE_ID es un OpaqueToken , que se importará desde angular / core.

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

Para un caso de uso más avanzado, es posible que desee elegir la configuración regional de un servicio. La configuración regional se resolverá (una vez) cuando se cree el componente que usa la tubería de fecha:

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

Espero que funcione para ti.

corola
fuente
43
Me sorprende que esto todavía no parezca estar documentado en ninguna parte. No en la página de canalización de fecha ( angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html ), no en la página de canalización general ( angular.io/docs/ts/latest/guide/pipes .html ) y esta pregunta es en realidad el primer éxito en Google ( google.com/search?q=angular%202%20locales&rct=j ). Gran hallazgo.
JP ten Berge
2
Para usar una tubería en el código, ahora debe formatearlo como new CurrencyPipe('en-US');. Espero que esto sea útil para algo, ya que apareció como el primer resultado al buscar en Google mi problema.
Ash Blue
1
@corolla ¿Puedes arrojar algo de luz sobre ese servicio? Me gustaría cambiar la configuración regional cuando la aplicación se está ejecutando, ¿es posible con ese servicio? ¿Y cómo implementaría tal servicio?
Martijn van den Bergh
1
@MartijnvandenBergh, el servicio solo devuelve una cadena de configuración regional, nada lujoso. Hemos tenido resultados mixtos al intentar cambiar la configuración regional mientras se ejecuta la aplicación. Terminó la página de recarga para manejar todos los casos. YMMV.
corolla
1
También luché mucho con este tema y espero que el artículo que escribí sobre esto pueda ayudar a algunas personas: medium.com/dailyjs/dynamic-locales-in-angular-dd9a527ebe1f
Michael Karén
72

La solución con LOCALE_ID es excelente si desea configurar el idioma de su aplicación una vez. Pero no funciona, si desea cambiar el idioma durante el tiempo de ejecución. Para este caso, puede implementar una tubería de fecha personalizada.

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);
  }

}

Ahora, si cambia el idioma de visualización de la aplicación utilizando TranslateService (consulte ngx-translate )

this.translateService.use('en');

los formatos dentro de su aplicación deberían actualizarse automáticamente.

Ejemplo de uso:

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

o mira mi simple proyecto "Notas" aquí .

ingrese la descripción de la imagen aquí

Milan Hlinák
fuente
Recibo un error de análisis de plantilla; no puedo compilar el filtro 'localizedDate' que utilicé de la misma manera que lo sugerido.
Prasad Shinde
¿Has declarado LocalizedDatePipe correctamente? Ver pipe.module.ts en mi proyecto de ejemplo .
Milan Hlinák
Sí, lo he resuelto antes, @Milan Hlinak. Debería haber respondido a mi comentario solo en ese momento. Pero de todos modos, gracias por su pronta respuesta. Lo estás haciendo genial.
Prasad Shinde
Esto es aparentemente lo que estaba buscando. Sin embargo, es una pena que se requiera una tubería personalizada para cambiar la
configuración
2
Funciona, pero tenga en cuenta que el uso de tuberías "impuras" es más lento que el "puro". Como dice la guía Angular : Angular ejecuta una tubería impura durante cada ciclo de detección de cambio de componentes. A menudo se llama una tubería impura, tan a menudo como cada pulsación de tecla o movimiento del mouse. Con esa preocupación en mente, implemente una tubería impura con mucho cuidado. Una tubería costosa y de larga duración podría destruir la experiencia del usuario.
Luca Ritossa
64

Con angular5 la respuesta anterior ya no funciona!

El siguiente código:

app.module.ts

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

Conduce al siguiente error:

Error: Faltan datos de configuración regional para la configuración regional "de-at".

Con angular5usted debe cargar y registrar el archivo de configuración regional utilizado por su cuenta.

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...
  ]
})

Documentación

zgue
fuente
De hecho, si necesita usar alguna otra configuración regional, excepto en EE. UU., Debe registrarla. Gracias por la respuesta, @zgue
MikkaRin
1
OK, eso me evitó otro dolor de cabeza ... ¡Gracias! El documento es un poco complicado, ya que pensé que registerLocaleDataera suficiente, bueno, no lo es.
danger89
1
¡La mejor respuesta para Ionic 4!
Parrycima
22

Si usa TranslateServicedesde @ngx-translate/core, a continuación se muestra una versión sin crear una nueva tubería que funcione con el cambio dinámico en tiempo de ejecución (probado en Angular 7). Usando el localeparámetro de DatePipe ( docs ):

Primero, declare las configuraciones regionales que usa en su aplicación, por ejemplo, en 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');
}

Luego, use su tubería dinámicamente:

myComponent.component.html

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

myComponent.component.ts

 constructor(public translateService: TranslateService) { ... }
knnhcn
fuente
2
Esto es sorprendentemente bueno. Ni siquiera necesitas @ ngx-translate para eso. ¿Puede explicar qué hace la declaración en la plantilla?
lama
2
@lama, dueDate (cualquier fecha que desee formatear) | date: 'shortDate' (1er parámetro para la tubería de fecha correspondiente al 'formato') : '' (2do parámetro => timeZone, "Cuando no se suministra, usa la zona horaria del sistema local del usuario final") : trasnlateService.currentLang (3er parámetro => local), chatea
Diego Osornio
¿Qué pasa si tiene un formato personalizado? ¿eso también se localizaría?
Martillo salvaje
12

He echado un vistazo en date_pipe.ts y tiene dos bits de información que son de interés. cerca de la parte superior están las siguientes dos líneas:

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

Cerca del fondo está esta línea:

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

Esto me sugiere que la fecha está actualmente codificada para ser 'en-US'.

Por favor, ilumíneme si estoy equivocado.

Mark Farmiloe
fuente
Es posible que desee ver la respuesta de Corolla a continuación. Está más actualizado y ofrece una excelente solución.
Mark Langer
9

En app.module.ts agregue las siguientes importaciones. Hay una lista de opciones LOCALE aquí .

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

Luego agregue el proveedor

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

Use tuberías en html. Aquí está la documentación angular para esto.

{{ dateObject | date: 'medium' }}
Alejandro del Río
fuente
Justo necesitamos esto!
alexchvrches
5

Haces algo como esto:

{{ dateObj | date:'shortDate' }}

o

{{ dateObj | date:'ddmmy' }}

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

Langley
fuente
perdón si no estaba claro en mi pregunta, pero esto es exactamente lo que estoy haciendo, pero con el patrón 'shortDate' y se muestra solo en el estilo estadounidense. El estilo del tiempo está bien.
nsbm
El segundo ejemplo muestra un formato que se pasa a DatePipe, eso es lo que querías, ¿no?
Langley
Intenté pero no funciona. Mostrar solo el número '5' independientemente de la fecha.
nsbm
3

Estaba luchando con el mismo problema y no funcionó para mí usando esto

{{dateObj | date:'ydM'}}

Entonces, probé una solución alternativa, no la mejor solución, pero funcionó:

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

Siempre puedo crear una tubería personalizada.

Hydrangenius
fuente
3

Para aquellos que tienen problemas con AOT, debe hacerlo de manera un poco diferente con useFactory:

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

@NgModule({
  providers: [
    { provide: LOCALE_ID, useFactory: getCulture },
    //otherProviders...
  ]
})
vidalsasoon
fuente
44
a partir de angular5, puede usar una expresión de flecha
gruesa
{ provide: LOCALE_ID, useFactory: () => 'fr-CA'}hizo el truco para mí;)
JoxieMedina
0

Copié el google pipe, cambié la configuración regional y funciona para mi país, es posible que no lo terminen para todas las configuraciones regionales. Debajo está el código.

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ć
fuente
0

Ok, propongo esta solución, muy simple, usando 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
fuente
-1

Esto podría ser un poco tarde, pero en mi caso (angular 6), creé una tubería simple encima de DatePipe, algo así:

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);
}

Puede que no sea la mejor solución, pero simple y funciona.

Ngoc Nam Nguyen
fuente