Tutorial

JavaScript タイムスタンプ完全ガイド

はじめに

JavaScript は、日付とタイムスタンプを操作するための Date オブジェクトを提供します。 JavaScript でタイムスタンプを適切に使用する方法を理解することは、Web 開発、データ処理、および時間ベースのアプリケーションにとって不可欠です。このガイドでは、タイムスタンプの基礎、変換、タイムゾーンの処理、およびベスト プラクティスについて説明します。

JavaScript のタイムスタンプについて

JavaScript の Unix タイムスタンプ

JavaScript は、1970 年 1 月 1 日 00:00:00 UTC (Unix エポック) からのミリ秒単位の Unix タイムスタンプを使用します。

JavaScript Timestamp = Milliseconds since 1970-01-01 00:00:00 UTC

Example: 1704624000000
  = 1704624000 seconds since epoch
  = January 8, 2024, 12:00:00 PM UTC

重要: JavaScript はミリ秒を使用しますが、他の多くのシステムは秒を使用します。変換するときは必ず単位を確認してください。

Current Timestamp

// Current timestamp in milliseconds
const nowMs = Date.now();
console.log(nowMs);  // e.g., 1704624000000

// Alternative method
const nowMs2 = new Date().getTime();
console.log(nowMs2);  // Same as Date.now()

// Convert to seconds
const nowSec = Math.floor(Date.now() / 1000);
console.log(nowSec);  // e.g., 1704624000

日付の作成

日付オブジェクトの作成

タイムスタンプから

// Create from milliseconds timestamp
const dateFromMs = new Date(1704624000000);
console.log(dateFromMs.toISOString());  // "2024-01-08T12:00:00.000Z"

// Create from seconds timestamp (multiply by 1000)
const dateFromSec = new Date(1704624000 * 1000);
console.log(dateFromSec.toISOString());  // "2024-01-08T12:00:00.000Z"

開始日コンポーネント

// Create from year, month, day (months are 0-indexed!)
const date1 = new Date(2024, 0, 8);  // January 8, 2024
console.log(date1.toISOString());  // "2024-01-08T00:00:00.000Z"

// Create with time
const date2 = new Date(2024, 0, 8, 14, 30, 0);
console.log(date2.toISOString());  // "2024-01-08T14:30:00.000Z"

// Create from string (ISO 8601 recommended)
const date3 = new Date('2024-01-08T14:30:00.000Z');
console.log(date3.toISOString());  // "2024-01-08T14:30:00.000Z"

よくある間違い: JavaScript の月は 0 からインデックスされます (0 = 1 月、11 = 12 月)。

現在の日付と時刻

const now = new Date();

console.log(now.toISOString());        // "2024-01-08T12:34:56.789Z"
console.log(now.toString());           // "Mon Jan 08 2024 07:34:56 GMT-0500"
console.log(now.toDateString());      // "Mon Jan 08 2024"
console.log(now.toTimeString());      // "07:34:56 GMT-0500"
console.log(now.toLocaleString());     // "1/8/2024, 7:34:56 AM"

日付コンポーネントの取得

日付部分の抽出

const date = new Date(2024, 0, 8, 14, 30, 45, 123);

// Get components
console.log(date.getFullYear());      // 2024
console.log(date.getMonth());        // 0 (January - 0-indexed!)
console.log(date.getDate());         // 8 (day of month)
console.log(date.getHours());        // 14 (hour 0-23)
console.log(date.getMinutes());      // 30 (minutes 0-59)
console.log(date.getSeconds());      // 45 (seconds 0-59)
console.log(date.getMilliseconds()); // 123 (milliseconds 0-999)

// Get day of week (0 = Sunday, 6 = Saturday)
console.log(date.getDay());          // 1 (Monday)

// Get UTC components
console.log(date.getUTCFullYear()); // 2024
console.log(date.getUTCHours());   // 19 (if local is 14:30)

相対時間コンポーネント

const date = new Date(2024, 0, 8);

// Get timezone offset (in minutes)
const offset = date.getTimezoneOffset();
console.log(offset);  // e.g., -300 (UTC-5 = -5 * 60)

// Get timestamp
const timestamp = date.getTime();
console.log(timestamp);  // e.g., 1704672000000 (milliseconds)

// Get ISO 8601 string
const isoString = date.toISOString();
console.log(isoString);  // "2024-01-08T00:00:00.000Z"

Setting Date Components

日付の変更

const date = new Date(2024, 0, 8);

// Set components (returns timestamp)
date.setFullYear(2025);
date.setMonth(11);      // December
date.setDate(25);
date.setHours(18);
date.setMinutes(30);
date.setSeconds(45);
date.setMilliseconds(0);

console.log(date.toISOString());  // "2025-12-25T18:30:45.000Z"

// Set UTC components
date.setUTCFullYear(2025);
date.setUTCHours(12);

重要: Set メソッドは Date オブジェクトではなく、タイムスタンプを返します。慎重にチェーンしてください:

// Correct: Use same date object
const date = new Date(2024, 0, 8);
date.setDate(15);
date.setMonth(5);  // June 15, 2024

// WRONG: Creates new date, loses changes
const date = new Date(2024, 0, 8);
new Date(date).setDate(15);  // Original date unchanged!

日付の算術演算

時間の加算と減算

const date = new Date(2024, 0, 8);

// Add 7 days
date.setDate(date.getDate() + 7);
console.log(date.toISOString());  // "2024-01-15T00:00:00.000Z"

// Add 3 hours (3600 * 1000 ms)
date.setTime(date.getTime() + (3 * 3600 * 1000));
console.log(date.toISOString());  // "2024-01-15T03:00:00.000Z"

// Subtract 1 month
date.setMonth(date.getMonth() - 1);
console.log(date.toISOString());  // "2023-12-15T03:00:00.000Z"

// Add 1 year
date.setFullYear(date.getFullYear() + 1);
console.log(date.toISOString());  // "2024-12-15T03:00:00.000Z"

ベスト プラクティス: 精度を高めるためにタイムスタンプ演算を使用します。

> // Add 1 hour in milliseconds (60 * 60 * 1000)
> const oneHour = 60 * 60 * 1000;
> const newDate = new Date(date.getTime() + oneHour);
>

時差

const date1 = new Date(2024, 0, 8);
const date2 = new Date(2024, 0, 15);

// Difference in milliseconds
const diffMs = date2 - date1;
console.log(diffMs);  // 604800000 (7 days in ms)

// Convert to seconds, minutes, hours, days
const diffSec = Math.floor(diffMs / 1000);
const diffMin = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));

console.log(`${diffDays} days`);  // "7 days"
console.log(`${diffHours} hours`);  // "168 hours"

日付の書式設定

組み込みの書式設定

toLocaleString Family

const date = new Date(2024, 0, 8, 14, 30, 45);

// Locale-specific formats
console.log(date.toLocaleDateString());      // "1/8/2024"
console.log(date.toLocaleTimeString());      // "2:30:45 PM"
console.log(date.toLocaleString());         // "1/8/2024, 2:30:45 PM"

// With locale options
console.log(date.toLocaleDateString('en-US', {
  weekday: 'long',
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}));
// "Monday, January 8, 2024"

console.log(date.toLocaleDateString('zh-CN', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}));
// "2024年1月8日"

国際形式

const date = new Date(2024, 0, 8);

// ISO 8601 (always UTC)
console.log(date.toISOString());  // "2024-01-08T00:00:00.000Z"

// UTC string
console.log(date.toUTCString());  // "Sun, 07 Jan 2024 00:00:00 GMT"

// Date string (local time)
console.log(date.toString());  // "Mon Jan 08 2024 00:00:00 GMT-0500"

ベスト プラクティス: タイムゾーンの問題を避けるために、API 呼び出しとデータベース ストレージには常に toISOString() を使用してください。

カスタム書式設定

// Manual formatting (use Intl.DateTimeFormat for i18n)
function formatDate(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

console.log(formatDate(new Date(2024, 0, 8, 14, 30, 45)));
// "2024-01-08 14:30:45"

推奨事項: 複雑な書式設定には、手動書式設定ではなく、date-fns、luxon、または day.js などのライブラリを使用します。

タイムゾーンの処理

タイムゾーンの操作

タイムゾーン情報の取得

const date = new Date();

// Get timezone offset (in minutes)
const offset = date.getTimezoneOffset();
console.log(offset);  // e.g., -300 (UTC-5) or 300 (UTC+5)

// Convert offset to hours
const offsetHours = offset / 60;
console.log(offsetHours);  // -5 or 5

// Get timezone name (browser-specific)
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(timezone);  // e.g., "America/New_York"

タイムゾーン間の変換

const date = new Date(2024, 0, 8, 14, 30, 0);

// Convert to different timezone using toLocaleString
const nyTime = date.toLocaleString('en-US', {
  timeZone: 'America/New_York',
  timeZoneName: 'short'
});
console.log(nyTime);  // "1/8/2024, 9:30:00 AM EST"

const tokyoTime = date.toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo'
});
console.log(tokyoTime);  // "1/8/2024, 11:30:00 PM"

// Extract time components in specific timezone
const tokyoDate = new Date(date.toLocaleString('en-US', {
  timeZone: 'Asia/Tokyo'
}));
console.log(tokyoDate.getHours());  // 23 (11 PM)

ベスト プラクティス: 内部では常に UTC を使用し、表示の場合のみローカル タイムゾーンに変換します。

UTC と現地時間

const date = new Date(2024, 0, 8, 14, 30, 0);

// Local time methods
console.log(date.getHours());     // Local hour (e.g., 14 for EST)
console.log(date.getTime());    // Timestamp (same regardless of timezone)

// UTC methods
console.log(date.getUTCHours()); // UTC hour (e.g., 19 for EST)
console.log(date.getUTCDate());  // UTC day of month

日付の解析

日付文字列の解析

日付コンストラクターの使用

// ISO 8601 (recommended)
const isoDate = new Date('2024-01-08T14:30:00.000Z');
console.log(isoDate.toISOString());  // "2024-01-08T14:30:00.000Z"

// Short date format (browser-dependent, avoid!)
const shortDate = new Date('01/08/2024');
console.log(shortDate);  // May be Jan 8 or Aug 8 depending on locale

// RFC 2822 format
const rfcDate = new Date('Mon, 08 Jan 2024 14:30:00 GMT');
console.log(rfcDate.toISOString());  // "2024-01-08T14:30:00.000Z"

問題: 日付解析はブラウザーやロケール間で一貫性がありません。

手動解析

// Parse ISO 8601 string manually
function parseISOString(isoString) {
  const date = new Date(isoString);
  if (isNaN(date.getTime())) {
    throw new Error('Invalid date string');
  }
  return date;
}

// Parse custom format (YYYY-MM-DD)
function parseCustomDate(dateString) {
  const [year, month, day] = dateString.split('-').map(Number);
  return new Date(year, month - 1, day);  // months are 0-indexed
}

console.log(parseCustomDate('2024-01-08').toISOString());
// "2024-01-08T00:00:00.000Z"

推奨事項: 信頼性の高い解析を行うには、date-fns/parse または luxon/DateTime.fromISO などのライブラリを使用します。

日付の検証

// Check if date is valid
function isValidDate(date) {
  return date instanceof Date && !isNaN(date.getTime());
}

// Examples
const validDate = new Date(2024, 0, 8);
const invalidDate = new Date('invalid');

console.log(isValidDate(validDate));    // true
console.log(isValidDate(invalidDate));  // false
console.log(isNaN(invalidDate.getTime()));  // true (NaN)

よくある落とし穴

月のインデックス作成

// Common mistake: Using 1-12 for months
const date = new Date(2024, 12, 8);  // January 2025!
console.log(date.toISOString());  // "2025-01-08T00:00:00.000Z"

// Correct: Use 0-11 for months
const date = new Date(2024, 11, 8);  // December 2024
console.log(date.toISOString());  // "2024-12-08T00:00:00.000Z"

タイムゾーンの混乱

const date = new Date(2024, 0, 8, 0, 0, 0);

// These produce different values!
console.log(date.getTime());     // 1704672000000 (same)
console.log(date.toString());     // "Mon Jan 08 2024 00:00:00 GMT-0500"
console.log(date.toISOString()); // "2024-01-08T05:00:00.000Z"

// Midnight EST = 5:00 AM UTC

問題: タイムゾーン情報を指定せずに日付を作成すると、現地時間が想定されます。

文字列解析の不一致

// Different browsers may parse differently
const date1 = new Date('2024-01-08');      // Might be Jan 8 or Jan 1
const date2 = new Date('2024/01/08');      // Might be parsed differently
const date3 = new Date('01-08-2024');      // Very ambiguous!

// Always use ISO 8601
const date = new Date('2024-01-08T00:00:00Z');
console.log(date.toISOString());  // Consistent across all browsers

数学オーバーフロー

const date = new Date(2024, 0, 31);

// Add 2 months to Jan 31
date.setMonth(date.getMonth() + 2);
console.log(date.toISOString());  // "2024-03-31T00:00:00.000Z" ✓

// Add 1 month to Jan 31 (February doesn't have 31!)
date.setMonth(date.getMonth() + 1);
console.log(date.toISOString());  // "2024-03-02T00:00:00.000Z" ✓

// JavaScript auto-adjusts overflow

利点: JavaScript は日付のオーバーフローを自動的に処理します (2 月 31 日 → 閏年に応じて 3 月 2 日または 3 日)。

ベストプラクティス

パフォーマンス

頻繁な日付作成を避ける

// BAD: Create new Date in loop
for (let i = 0; i < 1000; i++) {
  const now = new Date();
  // ... operations
}

// GOOD: Create once, reuse
const now = new Date();
const timestamp = now.getTime();
for (let i = 0; i < 1000; i++) {
  // ... operations with timestamp
}

比較にタイムスタンプを使用する

const date1 = new Date(2024, 0, 8);
const date2 = new Date(2024, 0, 15);

// BAD: Compare Date objects (slow)
if (date1 < date2) { }

// GOOD: Compare timestamps (fast)
if (date1.getTime() < date2.getTime()) { }

// Even better: Use timestamps directly
const ts1 = date1.getTime();
const ts2 = date2.getTime();
if (ts1 < ts2) { }

キャッシュのタイムゾーン オフセット

// Cache timezone offset (doesn't change during runtime)
const TZ_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;

// Use in conversions
function toLocalTime(timestamp) {
  return new Date(timestamp + TZ_OFFSET);
}

console.log(toLocalTime(Date.now()));

データの整合性

// Validate before operations
function safeDateOperation(callback) {
  try {
    const result = callback();
    if (isNaN(result.getTime())) {
      throw new Error('Invalid date result');
    }
    return result;
  } catch (error) {
    console.error('Date operation failed:', error);
    return new Date();  // Return current time as fallback
  }
}

// Usage
const result = safeDateOperation(() => {
  return new Date(invalidInput);
});

ストレージのベスト プラクティス

// Store as ISO 8601 string
function serializeDate(date) {
  return date.toISOString();
}

// Deserialize from ISO 8601
function deserializeDate(isoString) {
  return new Date(isoString);
}

// Usage in JSON
const data = {
  timestamp: Date.now(),
  isoDate: new Date().toISOString(),
  userCreated: serializeDate(new Date())
};

// Parse from API
const createdDate = deserializeDate(apiResponse.userCreated);

一般的な操作

ユーティリティ関数

一日の始まり/終わり

function startOfDay(date) {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  return d;
}

function endOfDay(date) {
  const d = new Date(date);
  d.setHours(23, 59, 59, 999);
  return d;
}

console.log(startOfDay(new Date()).toISOString());
// "2024-01-08T00:00:00.000Z"

週の始まり/終わり

function startOfWeek(date) {
  const d = new Date(date);
  const day = d.getDay();
  const diff = d.getDate() - day + (day === 0 ? -6 : 1);
  d.setDate(diff);
  return startOfDay(d);
}

function endOfWeek(date) {
  const d = startOfWeek(new Date(date));
  d.setDate(d.getDate() + 6);
  return endOfDay(d);
}

console.log(startOfWeek(new Date(2024, 0, 8)).toISOString());
// "2024-01-01T00:00:00.000Z" (Monday)

月の初め/終わり

function startOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}

function endOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth() + 1, 0);
}

console.log(startOfMonth(new Date(2024, 0, 15)).toISOString());
// "2024-01-01T00:00:00.000Z"

console.log(endOfMonth(new Date(2024, 0, 15)).toISOString());
// "2024-01-31T00:00:00.000Z"

年齢の計算

function calculateAge(birthDate) {
  const today = new Date();
  const birth = new Date(birthDate);

  let years = today.getFullYear() - birth.getFullYear();
  const monthDiff = today.getMonth() - birth.getMonth();

  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
    years--;
  }

  return years;
}

console.log(calculateAge('1990-06-15'));
// 33 (assuming current date is 2024-01-08)

営業日の計算

function addBusinessDays(startDate, days) {
  const result = new Date(startDate);
  let addedDays = 0;

  while (addedDays < days) {
    result.setDate(result.getDate() + 1);
    const dayOfWeek = result.getDay();

    if (dayOfWeek !== 0 && dayOfWeek !== 6) {  // Not weekend
      addedDays++;
    }
  }

  return result;
}

console.log(addBusinessDays(new Date(2024, 0, 8), 5).toISOString());
// "2024-01-15T00:00:00.000Z" (skips weekend)

例と使用例

カウントダウンタイマー

function countdown(targetDate) {
  const now = Date.now();
  const target = new Date(targetDate).getTime();
  const diff = target - now;

  if (diff <= 0) {
    return { expired: true };
  }

  const days = Math.floor(diff / (1000 * 60 * 60 * 24));
  const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
  const seconds = Math.floor((diff % (1000 * 60)) / 1000);

  return {
    expired: false,
    days,
    hours,
    minutes,
    seconds,
    totalMs: diff
  };
}

console.log(countdown('2024-12-31'));
// { expired: false, days: 357, hours: 11, minutes: 29, seconds: 12, totalMs: ... }

相対時間 (例: 「2 時間前」)

function timeAgo(timestamp) {
  const now = Date.now();
  const diff = now - timestamp;
  const seconds = Math.floor(diff / 1000);

  if (seconds < 60) return 'just now';
  const minutes = Math.floor(seconds / 60);
  if (minutes < 60) return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `${hours} hour${hours !== 1 ? 's' : ''} ago`;
  const days = Math.floor(hours / 24);
  if (days < 30) return `${days} day${days !== 1 ? 's' : ''} ago`;
  const months = Math.floor(days / 30);
  if (months < 12) return `${months} month${months !== 1 ? 's' : ''} ago`;
  const years = Math.floor(days / 365);
  return `${years} year${years !== 1 ? 's' : ''} ago`;
}

const oneHourAgo = Date.now() - (60 * 60 * 1000);
console.log(timeAgo(oneHourAgo));  // "1 hour ago"

日付範囲の検証

function isDateInRange(date, startDate, endDate) {
  const timestamp = date.getTime();
  return timestamp >= startDate.getTime() && timestamp <= endDate.getTime();
}

// Example: Check if date is in Q1 2024
const q1Start = new Date(2024, 0, 1);
const q1End = new Date(2024, 2, 31);
const testDate = new Date(2024, 1, 15);

console.log(isDateInRange(testDate, q1Start, q1End));  // true
console.log(isDateInRange(new Date(2024, 3, 1), q1Start, q1End));  // false

ベスト プラクティスの概要

JavaScript の日付チェックリスト

✅ Always use ISO 8601 format ('2024-01-08T14:30:00.000Z') for strings
✅ Work with timestamps internally, convert to Date only for display
✅ Use toISOString() for API calls and database storage
✅ Remember months are 0-indexed (0 = January, 11 = December)
✅ Cache timezone offset and Date.now() to avoid repeated calls
✅ Validate dates with isNaN(date.getTime())
✅ Use Intl.DateTimeFormat for i18n-aware formatting
✅ Consider libraries (date-fns, luxon, day.js) for complex operations
✅ Use timestamp arithmetic for precision (add/subtract milliseconds)
✅ Handle date overflow gracefully (JavaScript auto-adjusts)
❌ Don't use locale-specific strings for parsing (inconsistent across browsers)
❌ Don't mix UTC and local methods in same calculation
❌ Don't create Date objects in loops (reuse or use timestamps)
❌ Don't assume browser timezones (always validate with getTimezoneOffset)
❌ Don't rely on automatic string parsing (use ISO 8601)
❌ Don't forget about DST transitions when calculating business days

パフォーマンスのヒント

✅ Cache Date.now() instead of calling repeatedly
✅ Use timestamps for comparisons (faster than Date objects)
✅ Minimize Date object creation in loops
✅ Use Math.floor() instead of bitwise operators for readability
✅ Store timezone offset as constant for repeated calculations
❌ Don't use Date.parse() on non-ISO strings (unreliable)
❌ Don't create Date objects in hot code paths
❌ Don't use toLocaleString() in performance-critical sections

関連ツール

追加リソース

複雑な日付/時刻要件を持つ運用アプリケーションの場合は、次のようなライブラリの使用を検討してください。

  • date-fns: モジュール式の不変日付ユーティリティ
  • luxon: タイムゾーンをサポートする最新の API (Moment.js 作成者による)
  • day.js: Moment.js の軽量代替品 (2KB)
  • temporal-polyfill: 将来の TC39 Temporal API 提案

基本的な操作にはネイティブ日付で十分ですが、複雑な使用例ではライブラリを使用すると人間工学とタイムゾーンの処理が向上します。