В Angular преобразование данных для отображения выполняется через механизм pipes. Pipes представляют собой чистые функции, применяемые в шаблонах для форматирования, фильтрации и трансформации значений без изменения исходных данных. При работе с датами стандартные средства JavaScript оказываются ограниченными, особенно в задачах локализации, относительного времени и сложного форматирования. В этих сценариях часто применяется библиотека Day.js.
Day.js представляет собой компактную библиотеку для работы с датами, построенную с учётом API Moment.js, но с минимальным размером и модульной архитектурой. Она легко интегрируется в Angular через пользовательские pipes, позволяя централизовать логику форматирования дат.
Pipe в Angular представляет собой класс с методом transform, который принимает входное значение и возвращает преобразованный результат. Для дат это значение обычно приходит в виде строки, timestamp или объекта Date.
Базовая структура pipe:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'formatDate'
})
export class FormatDatePipe implements PipeTransform {
transform(value: any): string {
return value;
}
}
Такой pipe не выполняет преобразований, но задаёт основу для подключения Day.js.
Day.js устанавливается через npm:
npm install dayjs
Далее библиотека импортируется в pipe:
import * as dayjs from 'dayjs';
Для расширения функциональности подключаются плагины. Например, для работы с относительным временем:
npm install dayjs-plugin-relativeTime
Или встроенный плагин:
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
Основная задача pipe — преобразование даты в читаемый формат.
import { Pipe, PipeTransform } from '@angular/core';
import * as dayjs from 'dayjs';
@Pipe({
name: 'formatDate'
})
export class FormatDatePipe implements PipeTransform {
transform(value: string | Date, format: string = 'DD.MM.YYYY'): string {
if (!value) {
return '';
}
return dayjs(value).format(format);
}
}
Использование в шаблоне Angular:
<span>{{ user.createdAt | formatDate:'YYYY-MM-DD' }}</span>
Day.js поддерживает гибкие шаблоны форматирования, включая часы, минуты, секунды, а также локализованные представления дат.
Одной из ключевых возможностей Day.js является отображение времени относительно текущего момента.
Pipe для relative time:
import { Pipe, PipeTransform } from '@angular/core';
import * as dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
@Pipe({
name: 'fromNow'
})
export class FromNowPipe implements PipeTransform {
transform(value: string | Date): string {
if (!value) {
return '';
}
return dayjs(value).fromNow();
}
}
Применение:
<span>{{ comment.createdAt | fromNow }}</span>
Результат: «2 hours ago», «5 days ago» или локализованный аналог при подключении языка.
Day.js поддерживает подключение языковых пакетов.
import * as dayjs from 'dayjs';
import 'dayjs/locale/ru';
dayjs.locale('ru');
После этого все методы форматирования и relative time автоматически используют выбранную локаль.
Pipe с учётом локали:
import { Pipe, PipeTransform } from '@angular/core';
import * as dayjs from 'dayjs';
@Pipe({
name: 'localizedDate'
})
export class LocalizedDatePipe implements PipeTransform {
transform(value: string | Date): string {
if (!value) {
return '';
}
return dayjs(value).format('D MMMM YYYY');
}
}
В реальных приложениях часто требуется единый pipe, поддерживающий несколько режимов: форматирование, относительное время и кастомные шаблоны.
import { Pipe, PipeTransform } from '@angular/core';
import * as dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
@Pipe({
name: 'dayjsFormat'
})
export class DayjsFormatPipe implements PipeTransform {
transform(
value: string | Date,
mode: 'format' | 'fromNow' = 'format',
formatStr: string = 'DD.MM.YYYY'
): string {
if (!value) {
return '';
}
const date = dayjs(value);
switch (mode) {
case 'fromNow':
return date.fromNow();
case 'format':
default:
return date.format(formatStr);
}
}
}
Использование:
<span>{{ task.deadline | dayjsFormat:'format':'YYYY-MM-DD HH:mm' }}</span>
<span>{{ task.updatedAt | dayjsFormat:'fromNow' }}</span>
Angular pipes могут вызываться часто при изменении детекции. Day.js сам по себе лёгкий, но при большом количестве элементов важно учитывать производительность.
Применяются следующие подходы:
Пример чистого pipe:
@Pipe({
name: 'formatDate',
pure: true
})
Day.js поддерживает расширения для работы с UTC и временными зонами.
npm install dayjs-plugin-utc dayjs-plugin-timezone
Подключение:
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
Pipe с учётом временной зоны:
@Pipe({
name: 'tzDate'
})
export class TimezoneDatePipe implements PipeTransform {
transform(value: string | Date, tz: string = 'UTC'): string {
if (!value) {
return '';
}
return dayjs(value).tz(tz).format('DD.MM.YYYY HH:mm');
}
}
В Angular архитектуре форматирование дат может выполняться не только через pipes, но и через сервисы, особенно если результат используется в нескольких местах.
import { Injectable } from '@angular/core';
import * as dayjs from 'dayjs';
@Injectable({
providedIn: 'root'
})
export class DateService {
format(value: string | Date, format: string): string {
return dayjs(value).format(format);
}
fromNow(value: string | Date): string {
return dayjs(value).fromNow();
}
}
Pipe в таком случае становится тонкой обёрткой над сервисом, что улучшает тестируемость и переиспользование логики.
При работе с Observable в Angular даты часто приходят асинхронно. Pipes с Day.js остаются применимыми без дополнительной логики:
<div *ngIf="user$ | async as user">
{{ user.lastLogin | fromNow }}
</div>
Day.js выполняет преобразование синхронно, не требуя дополнительных подписок или преобразований потоков данных.
В крупных приложениях применяются единые константы форматов:
export const DATE_FORMATS = {
short: 'DD.MM.YY',
long: 'DD MMMM YYYY',
time: 'HH:mm',
full: 'DD.MM.YYYY HH:mm:ss'
};
Pipe использует эти значения:
transform(value: string | Date, format: string = DATE_FORMATS.short): string {
return dayjs(value).format(format);
}
Это снижает дублирование строк форматов и упрощает поддержку.
Day.js возвращает объект invalid date при некорректном вводе. В pipe важно учитывать это поведение:
transform(value: string | Date): string {
const date = dayjs(value);
if (!date.isValid()) {
return '';
}
return date.format('DD.MM.YYYY');
}
Day.js позволяет расширять функциональность через плагины, что особенно полезно в Angular pipe-архитектуре:
Пример инициализации:
import * as dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(relativeTime);
dayjs.extend(utc);
dayjs.extend(timezone);