JavaScript Date 对象(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在 JavaScript 开发中,日期和时间处理是一个高频且复杂的领域。无论是构建日历应用、计算年龄、处理时区转换,还是记录用户行为的时间戳,都离不开 Date 对象。然而,对于许多开发者而言,Date 对象的 API 设计和时区问题常常让人感到困惑。本文将从基础到进阶,系统性地讲解 Date 对象的核心概念与实用技巧,并通过案例解析常见问题。


一、Date 对象基础:时间的“容器”

1.1 创建 Date 实例

Date 对象可以理解为一个“时间容器”,用于存储和操作时间戳。创建 Date 实例有多种方式:

// 方法1:不带参数,返回当前时间  
const now = new Date();  
console.log(now); // 输出类似 "2023-10-05T08:45:23.123Z"  

// 方法2:传入时间戳(毫秒数)  
const specificTime = new Date(1755628800000);  
console.log(specificTime); // 输出对应的时间  

// 方法3:传入字符串(需符合 ISO 格式或本地时间)  
const birthday = new Date("1990-05-15");  

注意:字符串参数的格式需严格遵循 ISO 标准(如 YYYY-MM-DD),否则可能导致跨浏览器兼容性问题。


1.2 获取时间值:从年到毫秒

Date 对象提供了多个方法来提取时间的各个部分:

方法说明返回值范围
getFullYear()获取年份1900~9999
getMonth()获取月份(0~11)0(一月)到 11(十二月)
getDate()获取日期1~31
getDay()获取星期几(0~6)0(周日)到 6(周六)
getHours()获取小时0~23
getMinutes()获取分钟0~59
getSeconds()获取秒数0~59
getMilliseconds()获取毫秒0~999

示例

const date = new Date();  
console.log(  
  date.getFullYear(), // 2023  
  date.getMonth() + 1, // 注意月份需要 +1 才是实际月份  
  date.getDate()      // 5  
);  

1.3 时间戳与毫秒数

所有日期操作最终都会转化为 时间戳(自 1970-01-01 00:00:00 UTC 以来的毫秒数)。通过 getTime()valueOf() 可直接获取:

const timestamp = new Date().getTime();  
console.log(timestamp); // 输出类似 1696476323123  

二、时间操作:加减、比较与计算

2.1 时间加减:用毫秒值控制

通过修改时间戳,可以实现日期的增减:

// 示例:计算30天后的时间  
const now = new Date();  
const thirtyDaysLater = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);  

注意:这种方法不考虑闰年、时区变化等复杂场景,对于简单场景足够使用。


2.2 日期比较:判断时间先后

通过时间戳比较,可以轻松判断两个时间的先后:

function isEarlier(dateA, dateB) {  
  return dateA.getTime() < dateB.getTime();  
}  

const birthday = new Date("1990-05-15");  
const today = new Date();  
console.log(isEarlier(birthday, today)); // true  

2.3 计算年龄:从出生日期到当前时间

通过时间戳差值计算年龄:

function calculateAge(birthdayString) {  
  const birthday = new Date(birthdayString);  
  const ageDiff = new Date().getTime() - birthday.getTime();  
  const yearDiff = ageDiff / (365 * 24 * 60 * 60 * 1000);  
  return Math.floor(yearDiff);  
}  

console.log(calculateAge("1990-05-15")); // 输出 33  

三、时区处理:跨越不同时区的挑战

3.1 时区与 UTC 时间

JavaScript 的 Date 对象默认以 UTC 时间(协调世界时)为基准,但获取方法时会根据本地时区调整。例如:

const date = new Date("2023-10-05T12:00:00Z"); // UTC 时间  

console.log(date.toString()); // 输出本地时区的时间  
console.log(date.toUTCString()); // 输出 UTC 格式  

关键方法

  • getUTCHours() 等 UTC 相关方法直接返回 UTC 时间,无需考虑本地时区。
  • getTimezoneOffset() 返回本地时区与 UTC 的时差(分钟为单位)。

3.2 时区转换:从本地到目标时区

假设需要将一个日期对象转换为特定时区的时间:

function convertToTimezone(date, targetOffset) {  
  const utc = date.getTime() + (date.getTimezoneOffset() * 60 * 1000);  
  const targetTime = new Date(utc + (targetOffset * 60 * 60 * 1000));  
  return targetTime;  
}  

// 将本地时间转换为 UTC+8  
const converted = convertToTimezone(new Date(), 8);  

四、格式化日期:让时间“更易读”

4.1 原生方法的局限性

JavaScript 原生方法(如 toLocaleString())依赖浏览器实现,格式可能不一致:

const date = new Date();  
console.log(date.toDateString()); // 输出类似 "Thu Oct 05 2023"  
console.log(date.toLocaleString()); // 输出格式可能因浏览器或系统设置而异  

4.2 手动格式化:拼接字符串

通过组合 Date 方法实现自定义格式:

function formatDate(date) {  
  return [  
    date.getFullYear(),  
    String(date.getMonth() + 1).padStart(2, "0"),  
    String(date.getDate()).padStart(2, "0")  
  ].join("-");  
}  

console.log(formatDate(new Date())); // 输出 "2023-10-05"  

4.3 使用第三方库:Moment.js 或 date-fns

对于复杂需求,推荐使用成熟库:

// 使用 date-fns  
import { format } from "date-fns";  

const formatted = format(new Date(), "yyyy-MM-dd HH:mm:ss");  
console.log(formatted); // 输出 "2023-10-05 14:30:22"  

五、常见陷阱与解决方案

5.1 字符串解析的兼容性问题

某些日期字符串可能被不同浏览器解析为无效日期:

// 错误示例:非标准格式可能导致解析失败  
const invalidDate = new Date("05/15/1990"); // 在部分浏览器中可能无效  

// 解决方案:使用 ISO 标准格式  
const validDate = new Date("1990-05-15");  

5.2 时区偏移的计算错误

直接对日期对象的小时、分钟操作可能导致时区偏移问题:

// 错误示例:直接设置小时可能导致时区变化  
const date = new Date();  
date.setHours(25); // 可能实际增加 1 天,而非 25 小时  

// 解决方案:通过时间戳操作  
const newDate = new Date(date.getTime() + 25 * 60 * 60 * 1000);  

5.3 跨年、跨月的边界条件

处理日期增减时需考虑不同月份的天数差异:

// 错误示例:简单加 1 个月可能导致月份越界  
const date = new Date("2023-01-31");  
date.setMonth(date.getMonth() + 1); // 结果是 "2023-02-28"  

// 解决方案:手动判断天数  
function addMonths(date, months) {  
  const newDate = new Date(date);  
  newDate.setMonth(newDate.getMonth() + months);  
  if (newDate.getDate() !== date.getDate()) {  
    newDate.setDate(0); // 回退到上月最后一天  
  }  
  return newDate;  
}  

六、进阶应用:与服务器时间同步

6.1 通过 API 获取标准时间

在需要高精度的场景中,可从服务器获取时间戳:

// 假设后端提供一个返回当前时间戳的接口  
fetch("/api/current-time")  
  .then(response => response.json())  
  .then(data => {  
    const serverTime = new Date(data.timestamp);  
    // 使用服务器时间进行后续操作  
  });  

6.2 处理时区差异的“时区感知”对象

在复杂项目中,推荐使用 LuxonDay.js 等现代库:

import { DateTime } from "luxon";  

const dateTime = DateTime.now().setZone("Asia/Shanghai");  
console.log(dateTime.toFormat("yyyy-MM-dd HH:mm:ss"));  

结论

JavaScript 的 Date 对象是开发者必备的工具,但其复杂性也容易导致陷阱。本文通过基础用法、操作技巧、时区处理、格式化方案及常见问题的解析,帮助开发者系统性地掌握这一对象的核心能力。无论是构建日历应用、处理用户行为分析,还是实现国际化时间显示,都可通过本文提供的方法和案例快速落地。

最后提醒:在涉及跨时区或高精度需求时,建议优先使用成熟的第三方库,以避免因浏览器差异或计算错误导致的问题。实践是掌握的关键,建议读者通过实际项目不断巩固所学知识。

最新发布