JS 获取当前日期并格式化为 YYYY-MM-DD
详细讲解在 JavaScript 中获取当前日期并格式化为 YYYY-MM-DD 字符串的常用方法,包括基于 Date 对象的 padStart 补零拼接、现代 Intl.DateTimeFormat API 以及处理 toISOString 时区陷阱的正确方案。
YYYY-MM-DD 格式的最稳妥方案,是通过 new Date() 提取本地年月日数字,再利用 String.prototype.padStart() 对单数月份和日期前置补零后拼接。该方法直接使用系统本地时区,不依赖第三方库,且避开了 UTC 转换引发的隔日偏差。
一、推荐做法:基于 padStart 的三步格式化
在现代 JavaScript(ES2017+)环境中,最通用的格式化方式是先通过 Date 实例的方法提取本地年、月、日,再将不足两位的月和日补齐前导零。
// 1. 获取当前时间实例
const now = new Date();
// 2. 提取年、月、日,并对月和日补零
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
// 3. 模板字面量拼接
const formattedDate = `${year}-${month}-${day}`;
console.log(formattedDate); // 示例输出:"2026-11-02"
该方案由三个关键动作组成:
- 使用
getFullYear():返回四位数的公历年份(例如2026)。切勿使用已废弃的getYear(),后者返回的是相对 1900 年的差值。 - 月份需要加 1:JavaScript 中
getMonth()的返回值从0(一月)到11(十二月),因此真实月份必须显式+ 1。 - 使用
padStart(2, '0')补零:padStart是字符串原型方法,作用是当字符串长度不足目标位数时,在左侧填充指定字符。因此先用String()转为字符串,再进行补位。如果月份是5,补位后即为"05";如果是11,长度已达到 2,保持原样。
二、关键陷阱:为什么慎用 toISOString().slice(0, 10)
网络上常能见到一种极简写法:new Date().toISOString().slice(0, 10),或者使用 split('T')[0]。这种写法虽然只有一行,但在非零时区(例如中国的东八区 UTC+8)存在严重的隔日偏差问题。
Date.prototype.toISOString() 总是返回以 UTC 零时区为基准的 ISO 8601 字符串(末尾带有字母 Z)。
假设在北京时间 2026 年 11 月 2 日清晨 06:30:00 执行代码:
- 北京时间为 UTC+8,时间是
2026-11-02 06:30:00。 - 对应的世界协调时(UTC)需要减去 8 小时,即
2026-11-01 22:30:00Z。 - 调用
toISOString()得到的是"2026-11-01T22:30:00.000Z"。 - 截取前 10 位得到的结果是
"2026-11-01",比本地日期整整少了一天。
三、进阶方案:使用现代 Intl.DateTimeFormat API
ECMAScript 国际化标准提供了 Intl.DateTimeFormat API。利用这个 API,可以通过指定语言区域代码(Locale)或格式部件,直接生成符合要求的日期字符串,还支持显式指定时区。
方法 1:利用加拿大英语区(en-CA)的默认 ISO 输出
在国际标准中,加拿大(en-CA)的标准短日期书写格式恰好是 YYYY-MM-DD。
const formatter = new Intl.DateTimeFormat('en-CA', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
const formattedDate = formatter.format(new Date());
console.log(formattedDate); // 示例输出:"2026-11-02"
如果希望明确按某个特定时区(例如上海时间)格式化,即使服务器部署在 UTC 或其他时区的容器内,也可以直接传入 timeZone 参数:
const bjFormatter = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
console.log(bjFormatter.format(new Date())); // 始终输出上海当前日期
方法 2:使用 formatToParts 自由解构组装
如果不想依赖 en-CA 的区域习惯,可以使用 formatToParts() 方法。它将日期拆分为类型与值的对象数组,便于自由拼装:
const now = new Date();
const parts = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).formatToParts(now);
// 将数组转为以 type 为 key 的普通对象
const { year, month, day } = Object.fromEntries(
parts.map(p => [p.type, p.value])
);
const formattedDate = `${year}-${month}-${day}`;
console.log(formattedDate); // 示例输出:"2026-11-02"
四、方案对比与选型依据
为了帮助在实际开发中做出合适的技术选型,以下将原生 padStart 拼接与 Intl.DateTimeFormat 的关键差异总结如下:
| 对比维度 | padStart 原生拼接 | Intl.DateTimeFormat |
|---|---|---|
| 环境依赖 | 现代浏览器全支持,Node.js 8+ | 现代浏览器全支持,Node.js 12+ |
| 执行性能 | 极高(简单的原生属性读取与字符操作) | 中等(实例创建相对耗时,建议复用 formatter 实例) |
| 时区控制 | 默认基于执行环境的本地时间 | 支持任意指定 IANA 时区(如 Asia/Shanghai) |
| 语义直观度 | 直观、透明、易理解,符合绝大部分日常业务 | 配置参数丰富,适合复杂或跨国别应用 |
| 代码体积 | 0 依赖,仅 3~4 行代码 | 0 依赖,内置原生 API |
五、可直接复用的工具函数封装
在实际项目开发中,通常建议将日期格式化封装为一个简短的通用函数,支持传入可选的日期对象与自定义分隔符:
/**
* 获取指定日期(默认当前时间)并格式化为 YYYY-MM-DD
* @param {Date} [date=new Date()] 要格式化的日期实例
* @param {string} [separator='-'] 分隔符,默认为短横线 '-'
* @returns {string} 格式化后的日期字符串
*/
function formatDate(date = new Date(), separator = '-') {
// 防御性校验:如果传入无效对象,自动回退到当前时间
const d = date instanceof Date && !isNaN(date.getTime()) ? date : new Date();
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}${separator}${month}${separator}${day}`;
}
// 实际使用示例:
console.log(formatDate()); // 默认:"2026-11-02"
console.log(formatDate(new Date(), '/')); // 自定义分隔符:"2026/11/02"
console.log(formatDate(new Date(), '')); // 无分隔符:"20261102"
getDate() 返回的是当月的几号(1 到 31),千万不要误写成 getDay(),后者返回的是星期几(0 代表周日,1 到 6 代表周一到周六)。
JS空字符串、null和undefined转数字的结果是什么
2026-11-05 14:49:16
CodePen、JSFiddle与StackBlitz:主流JS在线编辑器对比
2026-11-05 13:38:29
JS怎么将时间戳转换为“刚刚”、“几分钟前”等相对时间
2026-11-05 12:55:14
JavaScript将儒略日逆向还原为公历日期时间的实现方法
2026-11-04 23:51:05
能在我的世界手机版直接修改JS代码吗
2026-11-04 19:02:53
相关标签:








