Skip to content

DateUtility

Overview

The DateUtility provides a pre-configured Day.js instance with essential plugins for timezone-aware date manipulation. All backend services import dayjs from @nx/core to ensure consistent date handling across the system.

Source: packages/core/src/utilities/date.utility.ts (23 lines)

Source

The entire module is 23 lines -- a pre-configured singleton export:

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

Configuration

Default Timezone

The default timezone is Asia/Ho_Chi_Minh (UTC+7). It can be overridden via the APP_ENV_APPLICATION_TIMEZONE environment variable.

VariableRequiredDefaultDescription
APP_ENV_APPLICATION_TIMEZONENoAsia/Ho_Chi_MinhIANA timezone identifier
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

Loaded Plugins

PluginPurposeExample
customParseFormatParse dates with custom format stringsdayjs('20/01/2025', 'DD/MM/YYYY')
timezoneTimezone conversion and awarenessdayjs().tz('Asia/Tokyo')
isoWeekISO week number calculationsdayjs().isoWeek()
utcUTC mode operationsdayjs.utc()
isSameOrBeforeInclusive "before" comparisondate.isSameOrBefore(other)
isSameOrAfterInclusive "after" comparisondate.isSameOrAfter(other)

Import

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

Basic Usage

Current Date/Time

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

Parse Dates

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

Format Dates

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"

Timezone Operations

Convert Between Timezones

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"

Store and Display Pattern

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"

Timezone Flow

Date Comparisons

Basic Comparisons

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)

Same or Before/After

These methods come from the isSameOrBefore and isSameOrAfter plugins:

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

Compare with Granularity

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

Date Manipulation

Add/Subtract

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"

Start/End of Period

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"

ISO Week Operations

The isoWeek plugin provides ISO 8601 week calculations:

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)

Common Use Cases

Event Date Validation

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

Date Range for Reports

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

Database Integration

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

Best Practices

1. Always Store UTC

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

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

2. Parse with Explicit Timezone

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. Use ISO Format for API Responses

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"

IGNIS Framework Reference

The dayjs instance exported by @nx/core builds on the IGNIS Date utility. For the base utility documentation, see:

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