JavaScript学习笔记:8.日期和时间
上一篇搞定了数字和字符串这两个"基础工具人",这一篇咱们来解锁JS的"时间管理大师"------日期和时间处理。如果说数字是"记账本",字符串是"日记本",那日期时间就是JS的"日程表",不管是做倒计时、预约功能,还是数据统计,都离不开它。
但JS的日期处理堪称"坑王聚集地":月份从0开始、时区错乱、字符串解析兼容问题,新手很容易写出让"12月变成11月""本地时间和UTC时间对不上"的bug。今天就用"生活化场景+踩坑实录"的方式,把Date对象的用法、坑点、实战技巧讲透,让你轻松搞定各种时间需求,再也不用对着代码挠头~
一、先搞懂:JS没有"日期类型",只有Date对象
首先明确一个核心知识点:JavaScript 压根没有专门的"日期数据类型"!所有日期和时间的处理,全靠内置的Date对象。它就像一个"时间工具箱",把时间存储为"自1970年1月1日00:00:00 UTC(纪元时间)以来的毫秒数"------这串数字叫时间戳,是时间的"唯一身份证",也是跨平台、跨时区处理时间的关键。
1. 创建Date对象:四种常用方式
创建Date对象就像"召唤时间管家",有四种常用姿势,按需选择:
js
// 姿势1:无参数 → 获取当前时间(本地时区)
const now = new Date();
console.log(now); // 输出类似:2025-08-20T10:30:00.000Z(UTC时间)或本地时间格式
// 姿势2:传入时间戳(毫秒数) → 按时间戳创建
const timestamp = 1750000000000;
const dateByTs = new Date(timestamp);
console.log(dateByTs); // 对应时间戳的日期
// 姿势3:传入日期字符串 → 解析字符串(推荐格式:YYYY-MM-DDTHH:mm:ss.sssZ)
const dateByStr = new Date("2025-12-25T09:30:00");
console.log(dateByStr); // 2025年12月25日09:30:00(注意:字符串格式不规范会解析失败)
// 姿势4:传入整数参数 → 年, 月(0-11), 日, 时, 分, 秒
const dateByNum = new Date(2025, 11, 25, 9, 30, 0);
console.log(dateByNum); // 2025年12月25日09:30:00(重点:月份是0开始!)
避坑第一弹:月份从0开始,JS的"时间小癖好"
这是最经典的坑!JS的月份是0=1月,1=2月,...,11=12月,相当于"月份值=实际月份-1"。新手很容易把12月写成12,结果变成次年1月:
js
// 反面例子:想创建12月,却写成12,实际是次年1月
const wrongDate = new Date(2025, 12, 25);
console.log(wrongDate.getMonth()); // 0(对应1月,翻车!)
// 正面例子:12月对应11
const rightDate = new Date(2025, 11, 25);
console.log(rightDate.getMonth()); // 11(正确)
二、核心方法:Date对象的"时间操作手册"
Date对象的方法分四大类:get(获取时间)、set(设置时间)、to(转换为字符串)、parse(解析字符串)。重点记高频方法,不用死记所有。
1. get系列:获取时间的"精准工具"
用于从Date对象中提取年、月、日、时、分、秒,核心方法如下(区分本地时间和UTC时间):
| 方法 | 作用 | 范围/说明 |
|---|---|---|
getFullYear() |
获取年份(4位数) | 如2025(推荐,替代getYear()) |
getMonth() |
获取月份(本地时间) | 0-11(记得+1才是实际月份) |
getDate() |
获取日期(本地时间) | 1-31(月份中的第几天,不是星期!) |
getDay() |
获取星期(本地时间) | 0-6(0=周日,6=周六) |
getHours() |
获取小时(本地时间) | 0-23(24小时制) |
getMinutes() |
获取分钟 | 0-59 |
getSeconds() |
获取秒 | 0-59 |
getTime() |
获取时间戳(毫秒数) | 核心方法,跨时区对比的关键 |
getUTC*() |
获取UTC时间(如getUTCMonth()) |
与本地时间方法对应,不受时区影响 |
实用示例:获取当前日期的"年-月-日 星期"
js
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1; // 月份+1
const date = now.getDate();
const week = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"][now.getDay()];
console.log(`${year}年${month}月${date}日 ${week}`); // 输出:2025年8月20日 周三(示例)
2. set系列:修改时间的"调整工具"
用于修改Date对象的时间,方法和get系列对应,修改后会直接改变原对象:
js
const date = new Date(2025, 11, 25); // 2025-12-25
// 修改年份为2026
date.setFullYear(2026);
console.log(date.getFullYear()); // 2026
// 修改月份为3(对应4月)
date.setMonth(3);
console.log(date.getMonth() + 1); // 4
// 修改日期为10
date.setDate(10);
console.log(date.getDate()); // 10
// 最终日期:2026-04-10
避坑第二弹:set方法会"自动进位"
比如给日期设为32,会自动进位到下个月;给小时设为25,会进位到第二天:
js
const date = new Date(2025, 11, 25); // 2025-12-25
// 日期设为32,自动进位到2026年1月1日
date.setDate(32);
console.log(date); // 2026-01-01(正确进位,不是报错!)
3. 时间戳:跨时区处理的"万能钥匙"
时间戳是"自纪元时间以来的毫秒数",不受时区、格式影响,是处理时间的"统一标准",核心用法:
js
// 1. 获取当前时间戳(三种方式,推荐前两种)
const ts1 = new Date().getTime();
const ts2 = Date.now(); // ES5+,更简洁
const ts3 = +new Date(); // 隐式转换,简洁但可读性差
// 2. 时间戳转Date对象
const date = new Date(ts1);
// 3. 两个日期对比(用时间戳相减)
const date1 = new Date(2025, 11, 25);
const date2 = new Date(2025, 11, 30);
const diffMs = date2.getTime() - date1.getTime(); // 时间差(毫秒)
const diffDays = diffMs / (1000 * 60 * 60 * 24); // 转换为天数
console.log(diffDays); // 5(正确)
实战场景:计算今年剩余天数
js
function getDaysLeftInYear() {
const today = new Date();
const endOfYear = new Date(today.getFullYear(), 11, 31, 23, 59, 59); // 当年12月31日23:59:59
const diffMs = endOfYear.getTime() - today.getTime();
return Math.ceil(diffMs / (1000 * 60 * 60 * 24)); // 向上取整,避免小数天
}
console.log(getDaysLeftInYear()); // 输出今年剩余天数(示例:130)
4. 字符串解析与转换:别踩"格式兼容坑"
(1)Date对象转字符串:to系列方法
用于将Date对象转为不同格式的字符串,按需选择:
js
const date = new Date(2025, 11, 25, 9, 30, 0);
// 1. 标准格式(UTC):2025-12-25T01:30:00.000Z(带时区)
console.log(date.toISOString());
// 2. 本地时间字符串:2025/12/25 09:30:00(根据本地时区)
console.log(date.toLocaleString());
// 3. 自定义格式(推荐,避免兼容性问题)
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // 补0成两位
const day = String(date.getDate()).padStart(2, "0");
const hour = String(date.getHours()).padStart(2, "0");
const minute = String(date.getMinutes()).padStart(2, "0");
return `${year}-${month}-${day} ${hour}:${minute}`;
}
console.log(formatDate(date)); // 2025-12-25 09:30(自定义格式,兼容所有环境)
(2)字符串转Date对象:Date.parse()
解析日期字符串为时间戳,再转Date对象(推荐用标准格式,避免兼容问题):
js
// 推荐格式:YYYY-MM-DDTHH:mm:ss(兼容所有浏览器)
const ts = Date.parse("2025-12-25T09:30:00");
const date = new Date(ts);
console.log(date); // 2025-12-25 09:30:00
// 避坑:非标准格式可能解析失败(如"2025/12/25"在部分浏览器可能有问题)
const wrongTs = Date.parse("2025/12/25");
console.log(wrongTs); // 可能返回NaN,不推荐!
避坑第三弹:时区导致的"日期偏移"
如果字符串不带时区标识(如Z表示UTC),JS会按本地时区解析,可能导致日期"差一天":
js
// 字符串不带时区,按本地时区解析
const date1 = new Date("2025-12-25");
console.log(date1.toISOString()); // 可能输出2025-12-24T16:00:00.000Z(本地时区比UTC晚8小时)
// 带Z标识,按UTC解析
const date2 = new Date("2025-12-25T00:00:00Z");
console.log(date2.toISOString()); // 2025-12-25T00:00:00.000Z(正确)
三、常见实战场景:直接套用不翻车
1. 场景1:日期格式化(最常用)
将Date对象转为"YYYY-MM-DD HH:mm:ss"格式,兼容所有环境:
js
function formatDateTime(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hour = String(date.getHours()).padStart(2, "0");
const minute = String(date.getMinutes()).padStart(2, "0");
const second = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
// 调用
const now = new Date();
console.log(formatDateTime(now)); // 2025-08-20 14:30:25(示例)
2. 场景2:倒计时功能(如活动结束倒计时)
js
function countdownTo(targetDateStr) {
const targetTs = new Date(targetDateStr).getTime();
setInterval(() => {
const nowTs = Date.now();
const diffMs = targetTs - nowTs;
if (diffMs <= 0) {
console.log("活动结束!");
return;
}
// 转换为天、时、分、秒
const days = Math.floor(diffMs / (1000 * 60 * 60 * 24));
const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diffMs % (1000 * 60)) / 1000);
console.log(`倒计时:${days}天${hours}时${minutes}分${seconds}秒`);
}, 1000);
}
// 调用:倒计时到2025年12月25日00:00:00
countdownTo("2025-12-25T00:00:00Z");
3. 场景3:判断两个日期是否是同一天
js
function isSameDay(date1, date2) {
return (
date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate()
);
}
// 调用
const dateA = new Date(2025, 11, 25);
const dateB = new Date(2025, 11, 25, 18, 30);
const dateC = new Date(2025, 11, 26);
console.log(isSameDay(dateA, dateB)); // true(同一天)
console.log(isSameDay(dateA, dateC)); // false(不同天)
四、核心避坑总结:时间处理的"生存法则"
- 记住月份从0开始:实际月份 = getMonth() + 1,设置时 = 实际月份 - 1。
- 优先用时间戳对比:跨时区、跨格式对比时间,直接用getTime()取时间戳相减,避免时区干扰。
- 字符串用标准格式:解析字符串时用"YYYY-MM-DDTHH:mm:ssZ",避免兼容性问题。
- 警惕时区偏移:不带时区的字符串会按本地时区解析,可能导致日期差一天,重要场景带Z标识。
- 自定义格式化:别依赖toLocaleString()(不同浏览器格式可能不同),自己写格式化函数更靠谱。
五、结尾:时间处理,稳字当头
JS的日期时间处理看似复杂,实则核心就三点:掌握Date对象的创建和常用方法、避开月份和时区的坑、用时间戳统一处理跨场景需求。只要记住这些,日常开发中的时间格式化、倒计时、日期对比等需求都能轻松搞定。