
Date 对象
JavaScript 的 Date 表示自 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)以来的毫秒数。
// 创建日期
new Date() // 当前时刻
new Date(timestamp) // 从毫秒数
new Date('2026-05-26') // 从 ISO 字符串(UTC 午夜)
new Date('2026-05-26T14:30:00Z') // 带 UTC 时间的 ISO
new Date('2026-05-26T14:30:00+05:30') // 带时区偏移的 ISO
new Date(2026, 4, 26) // 年、月(从0开始!)、日——本地时间
new Date(2026, 4, 26, 14, 30, 0) // 带小时、分钟、秒
注意: 月份从 0 开始(0=一月,11=十二月),日期从 1 开始。这种不一致性经常让人困惑。

获取当前时间戳
Date.now() // 自纪元以来的毫秒数(最高效)
new Date().getTime() // 相同
+new Date() // 相同,通过强制转换(避免——可读性差)
提取组件
const d = new Date('2026-05-26T14:30:00Z');
// UTC 方法——独立于系统时区
d.getUTCFullYear() // 2026
d.getUTCMonth() // 4(五月,从0开始)
d.getUTCDate() // 26(月中的日)
d.getUTCHours() // 14
d.getUTCMinutes() // 30
d.getUTCSeconds() // 0
d.getUTCDay() // 1(星期一,0=星期日)
// 本地方法——依赖于系统时区
d.getFullYear() // 可能因时区而异
d.getMonth() // 同样注意
d.getDate()
d.getHours()
规则: 除非你特别需要本地时间行为,否则使用 UTC 方法。混合使用会导致微妙的错误。
格式化日期
Intl.DateTimeFormat(内置,无需库)
const d = new Date('2026-05-26T14:30:00Z');
// 美国格式
new Intl.DateTimeFormat('en-US').format(d)
// => "5/26/2026"
// 英国格式
new Intl.DateTimeFormat('en-GB').format(d)
// => "26/05/2026"
// 完整可读格式
new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZone: 'America/New_York',
}).format(d)
// => "May 26, 2026 at 10:30 AM"
// 相对时间(需要参考点)
new Intl.RelativeTimeFormat('en').format(-3, 'days')
// => "3 days ago"
ISO 8601 字符串
new Date().toISOString()
// => "2026-05-26T14:30:00.000Z"
// 仅日期
new Date().toISOString().split('T')[0]
// => "2026-05-26"

手动格式化
function formatDate(date, format = 'YYYY-MM-DD') {
const y = date.getUTCFullYear();
const m = String(date.getUTCMonth() + 1).padStart(2, '0');
const d = String(date.getUTCDate()).padStart(2, '0');
const H = String(date.getUTCHours()).padStart(2, '0');
const M = String(date.getUTCMinutes()).padStart(2, '0');
return format
.replace('YYYY', y)
.replace('MM', m)
.replace('DD', d)
.replace('HH', H)
.replace('mm', M);
}
formatDate(new Date(), 'YYYY-MM-DD HH:mm')
// => "2026-05-26 14:30"
日期运算
JavaScript 日期没有内置的算术方法。使用时间戳:
const now = new Date();
// 加天数
const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
// 加月份(时区安全)
const nextMonth = new Date(now);
nextMonth.setUTCMonth(nextMonth.getUTCMonth() + 1);
// 天数差
function daysBetween(a, b) {
const msPerDay = 24 * 60 * 60 * 1000;
return Math.round((b.getTime() - a.getTime()) / msPerDay);
}
daysBetween(new Date('2026-01-01'), new Date('2026-05-26'))
// => 145
比较日期
const a = new Date('2026-05-26');
const b = new Date('2026-06-01');
// 比较时间戳
a < b // true
a > b // false
a <= b // true
// 检查相等性(不能使用 == 或 === —— 比较对象引用)
a.getTime() === b.getTime() // false
a.toISOString() === b.toISOString() // false
// 日期是否在过去?
new Date('2026-01-01') < Date.now() // true(自动强制转换有效)
时区
处理日期最困难的部分。JavaScript 的 Date 内部存储 UTC;显示受系统本地时区影响。
const d = new Date('2026-05-26T12:00:00Z'); // UTC 中午
// 在不同时区中这是什么时间?
d.toLocaleTimeString('en-US', { timeZone: 'America/New_York' })
// => "8:00:00 AM" (EDT, UTC-4)
d.toLocaleTimeString('en-US', { timeZone: 'Asia/Tokyo' })
// => "9:00:00 PM" (JST, UTC+9)
d.toLocaleTimeString('en-US', { timeZone: 'Europe/Berlin' })
// => "2:00:00 PM" (CEST, UTC+2)
转换为特定时区
// 获取特定时刻的时区 UTC 偏移量
function getTimezoneOffset(timezone, date = new Date()) {
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }));
return (utcDate - tzDate) / 60000; // 分钟
}
// 将本地时间字符串解析为特定时区的时间
function parseDateInTimezone(dateStr, timezone) {
return new Date(
new Intl.DateTimeFormat('en-CA', {
timeZone: timezone,
year: 'numeric', month: '2-digit', day: '2-digit',
}).format(new Date(dateStr))
);
}

最佳实践:存储 UTC,显示本地时间
// ✅ 以 UTC 存储时间戳(ISO 8601 或 Unix 毫秒)
const event = {
title: '团队站会',
startTime: '2026-05-26T09:00:00Z', // UTC
timezone: 'America/New_York', // 创建者的时区
};
// 以用户的本地时区显示
function displayEventTime(event, userTimezone) {
return new Intl.DateTimeFormat('en-US', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: userTimezone,
}).format(new Date(event.startTime));
}
常见模式
一天的开始 / 一天的结束(UTC)
function startOfDay(date) {
const d = new Date(date);
d.setUTCHours(0, 0, 0, 0);
return d;
}
function endOfDay(date) {
const d = new Date(date);
d.setUTCHours(23, 59, 59, 999);
return d;
}
是否为同一天?
function isSameDay(a, b, timezone = 'UTC') {
const fmt = new Intl.DateTimeFormat('en-CA', {
timeZone: timezone,
year: 'numeric', month: '2-digit', day: '2-digit',
});
return fmt.format(a) === fmt.format(b);
}
格式化“时间之前”
function timeAgo(date) {
const seconds = Math.floor((Date.now() - new Date(date).getTime()) / 1000);
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
if (seconds < 60) return rtf.format(-seconds, 'second');
if (seconds < 3600) return rtf.format(-Math.floor(seconds / 60), 'minute');
if (seconds < 86400) return rtf.format(-Math.floor(seconds / 3600), 'hour');
if (seconds < 2592000) return rtf.format(-Math.floor(seconds / 86400), 'day');
if (seconds < 31536000) return rtf.format(-Math.floor(seconds / 2592000), 'month');
return rtf.format(-Math.floor(seconds / 31536000), 'year');
}
timeAgo(new Date(Date.now() - 3 * 60 * 1000)) // "3 minutes ago"
timeAgo(new Date(Date.now() - 2 * 3600 * 1000)) // "2 hours ago"
Temporal API(即将推出的标准)
Temporal API 是一个新标准(截至 2026 年为 Stage 3 提案),通过为不同概念提供单独的类型来修复 Date 的设计缺陷:
// Polyfill: npm install @js-temporal/polyfill
import { Temporal } from '@js-temporal/polyfill';
// PlainDate:不带时间的日期
const date = Temporal.PlainDate.from('2026-05-26');
date.year; // 2026
date.month; // 5(从1开始,与 Date 不同!)
date.day; // 26
// ZonedDateTime:日期 + 时间 + 时区
const zdt = Temporal.ZonedDateTime.from('2026-05-26T09:00:00[America/New_York]');
zdt.toInstant().epochMilliseconds; // UTC 毫秒
// 算术
const tomorrow = date.add({ days: 1 });
const nextMonth = date.add({ months: 1 });
// 比较
Temporal.PlainDate.compare(date, tomorrow) // -1 (date < tomorrow)
Temporal 提供了不可变的日期对象、正确的时区处理以及从 1 开始的月份——这些都是 Date 做错的地方。
→ 使用 日期时间转换器 在日期格式和时间戳之间进行转换。