日期与时间处理

全面掌握JavaScript Date对象、时间处理、时区操作和日历功能

Date对象概述

JavaScript使用Date对象处理日期和时间:

  • 基于Unix时间戳(1970年1月1日以来的毫秒数)
  • 支持本地时间和UTC时间
  • 提供丰富的日期时间操作方法
  • 月份从0开始(0=1月,11=12月)
  • 星期从0开始(0=周日,6=周六)
  • 时间精度为毫秒级

创建Date对象

有多种方式可以创建Date对象:

创建Date对象
// 当前日期和时间
let now = new Date();
console.log(now);  // 当前时间的字符串表示

// 从时间戳创建
let timestamp = new Date(1640995200000);  // 2022-01-01

// 从日期字符串创建
let dateStr = new Date("2023-12-25");
let dateStr2 = new Date("December 25, 2023");

// 从年、月、日等参数创建
let specificDate = new Date(2023, 11, 25);  // 2023年12月25日 (月从0开始)
let specificTime = new Date(2023, 11, 25, 15, 30, 0);  // 2023-12-25 15:30:00

// Date.now() - 当前时间戳
let currentTimestamp = Date.now();
console.log(currentTimestamp);  // 当前时间的毫秒数

获取日期时间信息

获取日期时间信息
let date = new Date(2023, 11, 25, 15, 30, 45, 123);

// 获取时间戳
console.log(date.getTime());        // 时间戳 (毫秒)
console.log(date.valueOf());        // 同上

// 获取年、月、日
console.log(date.getFullYear());    // 2023 (推荐)
console.log(date.getYear());        // 123 (不推荐, 返回年份-1900)
console.log(date.getMonth());       // 11 (0-11)
console.log(date.getDate());        // 25 (1-31)
console.log(date.getDay());         // 1 (星期几, 0=周日, 6=周六)

// 获取时间
console.log(date.getHours());       // 15 (0-23)
console.log(date.getMinutes());     // 30 (0-59)
console.log(date.getSeconds());     // 45 (0-59)
console.log(date.getMilliseconds());// 123 (0-999)

// UTC时间方法 (在方法名后加UTC)
console.log(date.getUTCFullYear()); // UTC年份
console.log(date.getUTCHours());    // UTC小时

设置日期时间

设置日期时间
let date = new Date();

// 设置年、月、日
date.setFullYear(2024);
date.setMonth(5);        // 6月 (0-11)
date.setDate(15);

// 设置时间
date.setHours(14);
date.setMinutes(30);
date.setSeconds(0);
date.setMilliseconds(0);

console.log(date);  // 2024-06-15 14:30:00

// 使用时间戳设置
date.setTime(1640995200000);  // 设置为2022-01-01

// UTC设置方法
date.setUTCFullYear(2024);
date.setUTCHours(12);

// 自动调整日期 (设置32会自动转到下个月)
let testDate = new Date(2023, 0, 32);  // 2023-02-01
console.log(testDate);

日期格式化

日期格式化
let date = new Date(2023, 11, 25, 15, 30, 45);

// 内置格式化方法
console.log(date.toString());      // "Mon Dec 25 2023 15:30:45 GMT+0800 (中国标准时间)"
console.log(date.toDateString());  // "Mon Dec 25 2023"
console.log(date.toTimeString());  // "15:30:45 GMT+0800 (中国标准时间)"
console.log(date.toLocaleString());// "2023/12/25 15:30:45" (本地格式)
console.log(date.toLocaleDateString()); // "2023/12/25"
console.log(date.toLocaleTimeString()); // "15:30:45"

// ISO格式
console.log(date.toISOString());   // "2023-12-25T07:30:45.000Z" (UTC时间)
console.log(date.toJSON());        // 同上

// UTC格式
console.log(date.toUTCString());   // "Mon, 25 Dec 2023 07:30:45 GMT"

// 自定义格式化函数
function formatDate(date, format = 'YYYY-MM-DD') {
    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 format
        .replace('YYYY', year)
        .replace('MM', month)
        .replace('DD', day)
        .replace('HH', hours)
        .replace('mm', minutes)
        .replace('ss', seconds);
}

console.log(formatDate(date));                     // "2023-12-25"
console.log(formatDate(date, 'YYYY/MM/DD HH:mm:ss'));  // "2023/12/25 15:30:45"
console.log(formatDate(date, 'DD-MM-YYYY'));          // "25-12-2023"

日期计算

日期计算
// 日期比较
let date1 = new Date(2023, 0, 1);
let date2 = new Date(2023, 0, 15);

console.log(date1 < date2);   // true
console.log(date1 > date2);   // false
console.log(date1.getTime() === date2.getTime());  // false

// 日期差值计算 (毫秒)
let diffMs = date2 - date1;
let diffDays = diffMs / (1000 * 60 * 60 * 24);
console.log(diffDays);  // 14

// 添加天数
function addDays(date, days) {
    let result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
}

let futureDate = addDays(new Date(), 7);
console.log(futureDate);  // 7天后的日期

// 计算两个日期之间的天数
function daysBetween(date1, date2) {
    const oneDay = 1000 * 60 * 60 * 24;
    const diffMs = Math.abs(date2 - date1);
    return Math.floor(diffMs / oneDay);
}

console.log(daysBetween(new Date(2023, 0, 1), new Date(2023, 0, 15)));  // 14

// 计算年龄
function calculateAge(birthDate) {
    const today = new Date();
    let age = today.getFullYear() - birthDate.getFullYear();
    const monthDiff = today.getMonth() - birthDate.getMonth();
    
    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
        age--;
    }
    
    return age;
}

let birthDate = new Date(1990, 5, 15);
console.log(calculateAge(birthDate));  // 当前年龄

时间戳操作

时间戳操作
// 获取各种时间戳
let now = new Date();

console.log(now.getTime());        // 毫秒时间戳
console.log(now.valueOf());        // 同上
console.log(Date.now());          // 当前时间戳
console.log(+now);                 // 同上 (使用一元加运算符)

// 时间戳转换
function timestampToDate(timestamp) {
    return new Date(timestamp);
}

function dateToTimestamp(date) {
    return date.getTime();
}

// 性能测量
let startTime = Date.now();

// 模拟耗时操作
for (let i = 0; i < 1000000; i++) {
    // 空循环
}

let endTime = Date.now();
console.log(`操作耗时: ${endTime - startTime} 毫秒`);

// 高精度时间戳 (performance.now())
let perfStart = performance.now();
// 一些操作...
let perfEnd = performance.now();
console.log(`高精度耗时: ${perfEnd - perfStart} 毫秒`);

时区处理

时区处理
let date = new Date();

// 获取时区信息
console.log(date.getTimezoneOffset());  // 时区偏移 (分钟)
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone);  // 时区名称

// 本地时间 vs UTC时间
console.log(`本地时间: ${date.toString()}`);
console.log(`UTC时间: ${date.toUTCString()}`);
console.log(`ISO时间: ${date.toISOString()}`);

// 国际化日期格式
let formatter = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    weekday: 'long',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    timeZoneName: 'long'
});

console.log(formatter.format(date));  // "2023年12月25日星期一 15:30:45 中国标准时间"

// 不同地区的日期格式
let usFormatter = new Intl.DateTimeFormat('en-US');
let deFormatter = new Intl.DateTimeFormat('de-DE');

console.log(usFormatter.format(date));  // "12/25/2023"
console.log(deFormatter.format(date));  // "25.12.2023"

日历功能实现

使用JavaScript实现日历功能,包括日期选择、月份切换等:

简单日历实现
// 生成一个月历
function generateCalendar(year, month) {
    let firstDay = new Date(year, month, 1);
    let lastDay = new Date(year, month + 1, 0);
    
    // 获取第一天是星期几 (0=周日)
    let firstDayOfWeek = firstDay.getDay();
    
    // 日历数组
    let calendar = [];
    let week = [];
    
    // 填充前面的空白
    for (let i = 0; i < firstDayOfWeek; i++) {
        week.push(null);
    }
    
    // 填充日期
    for (let day = 1; day <= lastDay.getDate(); day++) {
        week.push(day);
        
        // 如果一周满了,开始新的一周
        if (week.length === 7) {
            calendar.push(week);
            week = [];
        }
    }
    
    // 填充后面的空白
    if (week.length > 0) {
        while (week.length < 7) {
            week.push(null);
        }
        calendar.push(week);
    }
    
    return calendar;
}

// 使用示例
let calendar = generateCalendar(2023, 11); // 2023年12月
console.log(calendar);

日期验证和处理

验证日期格式和有效性:

日期验证函数
// 验证日期字符串是否有效
function isValidDate(dateString) {
    let date = new Date(dateString);
    return date instanceof Date && !isNaN(date);
}

// 检查是否是闰年
function isLeapYear(year) {
    return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

// 获取月份天数
function getDaysInMonth(year, month) {
    return new Date(year, month + 1, 0).getDate();
}

// 使用示例
console.log(isValidDate("2023-02-30"));  // false
console.log(isValidDate("2023-12-25"));  // true
console.log(isLeapYear(2024));            // true
console.log(getDaysInMonth(2023, 1));    // 28 (2月)

常用日期库推荐

对于复杂的日期处理,推荐使用以下库:

  • Moment.js - 功能强大的日期处理库
  • date-fns - 轻量级、模块化的日期工具库
  • Day.js - Moment.js的轻量级替代品
  • Luxon - 现代化的日期和时间库
date-fns使用示例
// 使用date-fns库的示例
// 首先需要安装: npm install date-fns

// import { format, addDays, differenceInDays } from 'date-fns';

// 格式化日期
// console.log(format(new Date(), 'yyyy-MM-dd'));

// 添加天数
// console.log(addDays(new Date(), 7));

// 计算日期差
// console.log(differenceInDays(new Date(2023, 11, 25), new Date()));

实践练习

最佳实践

  • 使用Date.now()而不是new Date().getTime()获取时间戳
  • 处理用户输入时总是验证日期格式
  • 在存储和传输时使用ISO格式或时间戳
  • 考虑使用库如moment.js或date-fns处理复杂日期操作
  • 注意月份从0开始,星期从0(周日)开始
  • 使用Intl.DateTimeFormat进行国际化日期显示
  • 对于性能敏感的代码,避免频繁创建Date对象
  • 在服务器和客户端之间传递日期时,使用UTC时间

下一步学习

掌握了日期与时间后,接下来可以学习: