Use Cases

Handling Date and Time Correctly: Claude Code 활용 가이드

handling date and time correctly: Claude Code 활용. 실용적인 코드 예시를 포함합니다.

날짜・시간処理をClaude Code로올바르게구현する

날짜と시간の処理は、タイムゾーン、フォーマット、ロケール대응など思わぬ落とし穴が多い領域です。Claude Code를 활용하면 모범 사례に沿った堅牢な날짜処理を효율적으로구현할 수 있습니다。

라이브러리の선택

> 날짜・시간の処理ユーティリティを作って。
> day.jsを使って、タイムゾーン変換、相対시간표시、
> 日本語フォーマット、営業日計算를 구현해줘。
  • day.js: 軽量(2KB)で Moment.js 互換のAPI
  • date-fns: 함수ベース、Tree-shakingに最適
  • Temporal API: 将来の標準API(まだ提案段階)

날짜ユーティリティの구현

// src/lib/date-utils.ts
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/ja';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(relativeTime);
dayjs.locale('ja');

// デフォルトタイムゾーン
const DEFAULT_TZ = 'Asia/Tokyo';

// フォーマットのプ리셋
export const DATE_FORMATS = {
  full: 'YYYY年M月D日(ddd) HH:mm',
  date: 'YYYY年M月D日',
  dateShort: 'M/D',
  time: 'HH:mm',
  iso: 'YYYY-MM-DDTHH:mm:ssZ',
  api: 'YYYY-MM-DD',
} as const;

/**
 * UTCの日付文字列をJSTでフォーマット
 */
export function formatDate(
  date: string | Date,
  format: keyof typeof DATE_FORMATS = 'date'
): string {
  return dayjs(date).tz(DEFAULT_TZ).format(DATE_FORMATS[format]);
}

/**
 * 相対時間を返す(「3分前」「2時間前」「昨日」など)
 */
export function timeAgo(date: string | Date): string {
  const d = dayjs(date);
  const now = dayjs();
  const diffHours = now.diff(d, 'hour');

  if (diffHours < 1) {
    const diffMinutes = now.diff(d, 'minute');
    if (diffMinutes < 1) return 'たった今';
    return `${diffMinutes}分前`;
  }
  if (diffHours < 24) return `${diffHours}時間前`;
  if (diffHours < 48) return '昨日';
  if (diffHours < 168) return `${Math.floor(diffHours / 24)}日前`;

  return formatDate(date, 'date');
}

/**
 * タイムゾーン変換
 */
export function convertTimezone(
  date: string | Date,
  fromTz: string,
  toTz: string
): dayjs.Dayjs {
  return dayjs.tz(date, fromTz).tz(toTz);
}

/**
 * 営業日かどうかを判定
 */
export function isBusinessDay(date: string | Date): boolean {
  const d = dayjs(date);
  const dayOfWeek = d.day();
  return dayOfWeek !== 0 && dayOfWeek !== 6; // 日曜=0, 土曜=6
}

/**
 * N営業日後の日付を取得
 */
export function addBusinessDays(date: string | Date, days: number): dayjs.Dayjs {
  let current = dayjs(date);
  let remaining = days;

  while (remaining > 0) {
    current = current.add(1, 'day');
    if (isBusinessDay(current.toDate())) {
      remaining--;
    }
  }

  return current;
}

Intl API에 의한ネイティブフォーマット

라이브러리なしでも、브라우저のIntlAPIで多くのフォーマットが가능합니다。

// src/lib/intl-date.ts

/**
 * Intl.DateTimeFormatを使った日付フォーマット
 */
export function formatDateIntl(date: Date, style: 'long' | 'short' = 'long'): string {
  return new Intl.DateTimeFormat('en-US', {
    year: 'numeric',
    month: style === 'long' ? 'long' : 'numeric',
    day: 'numeric',
    weekday: style === 'long' ? 'short' : undefined,
  }).format(date);
}

/**
 * 2つの日付の差を人間が読める形式で表示
 */
export function formatDateRange(start: Date, end: Date): string {
  return new Intl.DateTimeFormat('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  }).formatRange(start, end);
}

/**
 * 相対時間のフォーマット
 */
export function formatRelative(date: Date): string {
  const rtf = new Intl.RelativeTimeFormat('ja', { numeric: 'auto' });
  const now = new Date();
  const diffMs = date.getTime() - now.getTime();
  const diffSec = Math.round(diffMs / 1000);
  const diffMin = Math.round(diffSec / 60);
  const diffHour = Math.round(diffMin / 60);
  const diffDay = Math.round(diffHour / 24);

  if (Math.abs(diffSec) < 60) return rtf.format(diffSec, 'second');
  if (Math.abs(diffMin) < 60) return rtf.format(diffMin, 'minute');
  if (Math.abs(diffHour) < 24) return rtf.format(diffHour, 'hour');
  return rtf.format(diffDay, 'day');
}

React컴포넌트での利用

// src/components/TimeDisplay.tsx
'use client';
import { useState, useEffect } from 'react';
import { timeAgo } from '@/lib/date-utils';

export function TimeDisplay({ date }: { date: string }) {
  const [display, setDisplay] = useState(timeAgo(date));

  useEffect(() => {
    const interval = setInterval(() => {
      setDisplay(timeAgo(date));
    }, 60000); // 1分ごとに업데이트
    return () => clearInterval(interval);
  }, [date]);

  return (
    <time dateTime={date} title={new Date(date).toLocaleString('en-US')}>
      {display}
    </time>
  );
}

よくある落とし穴

  • タイムゾーン未考慮: 서버と클라이언트でタイムゾーンが異なる場合、常にUTCで저장し클라이언트で変換する
  • 夏시간: 日本にはないが、海外사용자대응時は要주의
  • Date.parse()の挙動: 브라우저間で差異があるため、dayjs等でパースする

関連글

国際化대응全般はi18n구현가이드、通貨のフォーマットは通貨フォーマットの구현를 참고하세요.

day.js의 공식 문서(day.js.org)で플러그인목록を확인할 수 있습니다。

#Claude Code #日付 #タイムゾーン #day.js #Intl