Skip to content

DateUtility

Tổng quan

DateUtility cung cấp một instance Day.js đã cấu hình sẵn với các plugin thiết yếu để thao tác ngày giờ có nhận biết múi giờ. Tất cả service backend đều import dayjs từ @nx/core để đảm bảo việc xử lý ngày giờ nhất quán trên toàn hệ thống.

Nguồn: packages/core/src/utilities/date.utility.ts (23 dòng)

Mã nguồn

Toàn bộ module chỉ gồm 23 dòng -- một singleton được export sau khi cấu hình sẵn:

typescript
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import isoWeek from 'dayjs/plugin/isoWeek';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';

dayjs.extend(customParseFormat);
dayjs.extend(timezone);
dayjs.extend(isoWeek);
dayjs.extend(utc);
dayjs.extend(isSameOrBefore);
dayjs.extend(isSameOrAfter);

const tz = process.env.APP_ENV_APPLICATION_TIMEZONE ?? 'Asia/Ho_Chi_Minh';
dayjs.tz.setDefault(tz);

export { dayjs };

Cấu hình

Múi giờ mặc định

Múi giờ mặc định là Asia/Ho_Chi_Minh (UTC+7). Có thể ghi đè thông qua biến môi trường APP_ENV_APPLICATION_TIMEZONE.

BiếnBắt buộcMặc địnhMô tả
APP_ENV_APPLICATION_TIMEZONEKhôngAsia/Ho_Chi_MinhĐịnh danh múi giờ theo IANA
bash
# .env.development
APP_ENV_APPLICATION_TIMEZONE=Asia/Ho_Chi_Minh    # Default
APP_ENV_APPLICATION_TIMEZONE=America/New_York     # Override for US Eastern
APP_ENV_APPLICATION_TIMEZONE=UTC                  # UTC mode

Các plugin đã nạp

PluginMục đíchVí dụ
customParseFormatPhân tích ngày với chuỗi định dạng tuỳ chỉnhdayjs('20/01/2025', 'DD/MM/YYYY')
timezoneChuyển đổi và nhận biết múi giờdayjs().tz('Asia/Tokyo')
isoWeekTính số tuần theo chuẩn ISOdayjs().isoWeek()
utcThao tác ở chế độ UTCdayjs.utc()
isSameOrBeforeSo sánh "trước" bao gồm cả bằngdate.isSameOrBefore(other)
isSameOrAfterSo sánh "sau" bao gồm cả bằngdate.isSameOrAfter(other)

Import

typescript
import { dayjs } from '@nx/core';
// or
import { dayjs } from '@nx/core/utilities';

Cách dùng cơ bản

Ngày/giờ hiện tại

typescript
// Current time in default timezone (Asia/Ho_Chi_Minh)
const now = dayjs();

// Current time in UTC
const utcNow = dayjs.utc();

// Current time in a specific timezone
const tokyoNow = dayjs().tz('Asia/Tokyo');

Phân tích ngày

typescript
// ISO string
const date1 = dayjs('2025-01-20T10:00:00Z');

// Custom format (requires customParseFormat plugin)
const date2 = dayjs('20/01/2025', 'DD/MM/YYYY');

// From timestamp
const date3 = dayjs(1705708800000);

// From Date object
const date4 = dayjs(new Date());

Định dạng ngày

typescript
const date = dayjs('2025-01-20T15:30:00');

date.format('YYYY-MM-DD');              // "2025-01-20"
date.format('DD/MM/YYYY');              // "20/01/2025"
date.format('YYYY-MM-DD HH:mm:ss');    // "2025-01-20 15:30:00"
date.format('YYYY-MM-DD HH:mm:ss Z');  // "2025-01-20 15:30:00 +07:00"

Thao tác múi giờ

Chuyển đổi giữa các múi giờ

typescript
const date = dayjs('2025-01-20T10:00:00Z'); // UTC

// Convert to Vietnam time
const vnTime = date.tz('Asia/Ho_Chi_Minh');
vnTime.format('HH:mm'); // "17:00"

// Convert to US Eastern
const etTime = date.tz('America/New_York');
etTime.format('HH:mm'); // "05:00"

Mẫu lưu trữ và hiển thị

typescript
// Store in UTC (for database)
const stored = dayjs().utc().toISOString();
// "2025-01-20T08:30:00.000Z"

// Display in user's timezone
const displayTime = dayjs(stored).tz('Asia/Ho_Chi_Minh').format('HH:mm DD/MM/YYYY');
// "15:30 20/01/2025"

Luồng múi giờ

So sánh ngày

So sánh cơ bản

typescript
const date1 = dayjs('2025-01-20');
const date2 = dayjs('2025-01-25');

date1.isBefore(date2);       // true
date1.isAfter(date2);        // false
date1.isSame(date2);         // false
date1.isSame(date2, 'month'); // true (same month)

Bằng hoặc trước/sau

Các phương thức này đến từ plugin isSameOrBeforeisSameOrAfter:

typescript
const startDate = dayjs('2025-01-01');
const endDate = dayjs('2025-01-31');
const checkDate = dayjs('2025-01-15');

// Check if within an inclusive range
const isInRange =
  checkDate.isSameOrAfter(startDate) &&
  checkDate.isSameOrBefore(endDate);
// true

So sánh theo độ chi tiết

typescript
const date1 = dayjs('2025-01-20 10:00');
const date2 = dayjs('2025-01-20 15:00');

date1.isSame(date2, 'day');     // true  (same day)
date1.isSame(date2, 'hour');    // false (different hour)
date1.isBefore(date2, 'hour');  // true

Biến đổi ngày

Cộng/trừ

typescript
const date = dayjs('2025-01-20');

date.add(7, 'day').format('YYYY-MM-DD');       // "2025-01-27"
date.add(1, 'month').format('YYYY-MM-DD');     // "2025-02-20"
date.subtract(1, 'year').format('YYYY-MM-DD'); // "2024-01-20"

// Chaining
date.add(1, 'month').add(15, 'day').format('YYYY-MM-DD');
// "2025-03-07"

Đầu/cuối kỳ

typescript
const date = dayjs('2025-01-20 15:30:45');

date.startOf('day').format('YYYY-MM-DD HH:mm:ss');
// "2025-01-20 00:00:00"

date.endOf('day').format('YYYY-MM-DD HH:mm:ss');
// "2025-01-20 23:59:59"

date.startOf('month').format('YYYY-MM-DD');
// "2025-01-01"

date.endOf('month').format('YYYY-MM-DD');
// "2025-01-31"

Thao tác tuần ISO

Plugin isoWeek cung cấp tính toán tuần theo chuẩn ISO 8601:

typescript
const date = dayjs('2025-01-20');

date.isoWeek();       // 4   (ISO week number)
date.isoWeekday();    // 1   (Monday = 1, Sunday = 7)
date.isoWeekYear();   // 2025

// Get start of ISO week (Monday)
const weekStart = date.startOf('isoWeek');
weekStart.format('YYYY-MM-DD'); // "2025-01-20" (Monday)

// Get end of ISO week (Sunday)
const weekEnd = date.endOf('isoWeek');
weekEnd.format('YYYY-MM-DD'); // "2025-01-26" (Sunday)

Các tình huống dùng phổ biến

Kiểm tra hợp lệ ngày sự kiện

typescript
function isEventDateValid(eventDate: string): boolean {
  const event = dayjs(eventDate);
  const now = dayjs();
  const maxFutureDate = now.add(1, 'year');

  return event.isAfter(now) && event.isBefore(maxFutureDate);
}

Khoảng ngày cho báo cáo

typescript
function getMonthlyReportRange(year: number, month: number) {
  const start = dayjs()
    .year(year)
    .month(month - 1)
    .startOf('month');

  const end = start.endOf('month');

  return {
    start: start.toISOString(),
    end: end.toISOString(),
  };
}

Tích hợp cơ sở dữ liệu

typescript
// Store in UTC
async createEvent(data: CreateEventDto) {
  const eventDateUtc = dayjs
    .tz(data.eventDate, data.timezone)
    .utc()
    .toISOString();

  return this.eventRepository.create({
    data: {
      ...data,
      eventDate: eventDateUtc,
    },
  });
}

// Query by date range
const weekStart = dayjs().startOf('isoWeek').toISOString();
const weekEnd = dayjs().endOf('isoWeek').toISOString();

const events = await eventRepository.find({
  where: {
    eventDate: { gte: weekStart, lte: weekEnd },
  },
});

Thực hành tốt nhất

1. Luôn lưu trữ theo UTC

typescript
// Correct -- store in UTC
const stored = dayjs.tz(userInput, userTimezone).utc().toISOString();

// Avoid -- timezone-ambiguous
const stored = dayjs(userInput).format();

2. Phân tích với múi giờ rõ ràng

typescript
// Correct -- explicit timezone
const date = dayjs.tz('2025-01-20 15:00', 'Asia/Ho_Chi_Minh');

// Avoid -- ambiguous
const date = dayjs('2025-01-20 15:00'); // Which timezone?

3. Dùng định dạng ISO cho phản hồi API

typescript
// Correct -- machine-readable
{ createdAt: dayjs(record.createdAt).toISOString() }
// "2025-01-20T08:30:00.000Z"

// Avoid -- locale-specific
{ createdAt: dayjs(record.createdAt).format('DD/MM/YYYY') }
// "20/01/2025"

Tham chiếu IGNIS Framework

Instance dayjs được @nx/core export xây dựng trên tiện ích Date của IGNIS. Để xem tài liệu của tiện ích nền tảng, xem:

Tài liệu liên quan

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.