外观
日期处理
约 1869 字大约 6 分钟
2025-06-19
本文整理 PHP 中 DateTime 对象的常用操作,包括格式化、时间计算、时区处理等。
date基础
参数
format
输出的日期 string 格式。 参见下文中的 格式化选项。 同时,还可以使用 预定义日期常量 ,例如:常量 DATE_RSS 表示格式化字符串 'D, d M Y H:i:s'。
| format字符 | 说明 | 返回值例子 |
|---|---|---|
| 日 | ||
| d | 月份中的第几天,有前导零的 2 位数字 | 01 到 31 |
| D | 星期中的第几天,文本表示,3 个字母 | Mon 到 Sun |
| j | 月份中的第几天,没有前导零 | 1 到 31 |
| l(“L”的小写字母) | 星期几,完整的文本格式 | Sunday 到 Saturday |
| N | ISO-8601 格式数字表示的星期中的第几天(PHP 5.1.0 新加) | 1(表示星期一)到 7(表示星期天) |
| S | 每月天数后面的英文后缀,2 个字符 | st,nd,rd 或者 th。可以和 j 一起用 |
| w | 星期中的第几天,数字表示 | 0(表示星期天)到 6(表示星期六) |
| z | 年份中的第几天 | 0 到 365 |
| 星期 | ||
| W | ISO-8601 格式年份中的第几周,每周从星期一开始(PHP 4.1.0 新加的) | 例如:42(当年的第 42 周) |
| 月 | ||
| F | 月份,完整的文本格式,例如 January 或者 March | January 到 December |
| m | 数字表示的月份,有前导零 | 01 到 12 |
| M | 三个字母缩写表示的月份 | Jan 到 Dec |
| n | 数字表示的月份,没有前导零 | 1 到 12 |
| t | 指定的月份有几天 | 28 到 31 |
| 年 | ||
| L | 是否为闰年 | 如果是闰年为 1,否则为 0 |
| o | ISO-8601 格式年份数字。这和 Y 的值相同,只除了如果 ISO 的星期数(W)属于前一年或下一年,则用那一年。(PHP 5.1.0 新加) | Examples: 1999 or 2003 |
| Y | 4 位数字完整表示的年份 | 例如:1999 或 2003 |
| y | 2 位数字表示的年份 | 例如:99 或 03 |
| 时间 | ||
| a | 小写的上午和下午值 | am 或 pm |
| A | 大写的上午和下午值 | AM 或 PM |
| B | Swatch Internet 标准时 | 000 到 999 |
| g | 小时,12 小时格式,没有前导零 | 1 到 12 |
| G | 小时,24 小时格式,没有前导零 | 0 到 23 |
| h | 小时,12 小时格式,有前导零 | 01 到 12 |
| H | 小时,24 小时格式,有前导零 | 00 到 23 |
| i | 有前导零的分钟数 | 00 到 59 |
| s | 秒数,有前导零 | 00 到 59 |
| u | 毫秒 (PHP 5.2.2 新加)。需要注意的是 date() 函数总是返回 000000 因为它只接受 integer 参数, 而 DateTime::format() 才支持毫秒。 | 示例: 654321 |
| 时区 | ||
| e | 时区标识(PHP 5.1.0 新加) | 例如:UTC,GMT,Atlantic/Azores |
| I | 是否为夏令时 | 如果是夏令时为 1,否则为 0 |
| O | 与格林威治时间相差的小时数 | 例如:+0200 |
| P | 与格林威治时间(GMT)的差别,小时和分钟之间有冒号分隔(PHP 5.1.3 新加) | 例如:+02:00 |
| T | 本机所在的时区 | 例如:EST,MDT(【译者注】在 Windows 下为完整文本格式,例如“Eastern Standard Time”,中文版会显示“中国标准时间”)。 |
| Z | 时差偏移量的秒数。UTC 西边的时区偏移量总是负的,UTC 东边的时区偏移量总是正的。 | -43200 到 43200 |
| 完整的日期/时间 | ||
| c | ISO 8601 格式的日期(PHP 5 新加) | 2004-02-12T15:19:21+00:00 |
| r | RFC 822 格式的日期 | 例如:Thu, 21 Dec 2000 16:01:07 +0200 |
| U | 从 Unix 纪元(January 1 1970 00:00:00 GMT)开始至今的秒数 | 参见 time() |
| 预定义常量(从 PHP 5.1.0 开始可用) | ||
| DATE_ATOM | Atom | 例如:2013-04-12T15:52:01+00:00 |
| DATE_COOKIE | HTTP Cookies | 例如:Friday, 12-Apr-13 15:52:01 UTC |
| DATE_ISO8601 | ISO-8601 | 例如:2013-04-12T15:52:01+0000 |
| DATE_RFC822 | RFC 822 | 例如:Fri, 12 Apr 13 15:52:01 +0000 |
| DATE_RFC850 | RFC 850 | 例如:Friday, 12-Apr-13 15:52:01 UTC |
| DATE_RFC1036 | RFC 1036 | 例如:Fri, 12 Apr 13 15:52:01 +0000 |
| DATE_RFC1123 | RFC 1123 | 例如:Fri, 12 Apr 2013 15:52:01 +0000 |
| DATE_RFC2822 | RFC 2822 | Fri, 12 Apr 2013 15:52:01 +0000 |
| DATE_RFC3339 | 与 DATE_ATOM 相同 | 从 PHP 5.1.3 开始 |
| DATE_RSS | RSS | Fri, 12 Aug 2013 15:52:01 +0000 |
| DATE_W3C | 万维网联盟 | 例如:2013-04-12T15:52:01+00:00 |
DateTime 基础
创建时间对象
// 当前时间
$now = new DateTime();
$now = DateTime::createFromFormat('U', (string) time()); // 时间戳创建
// 指定时间
$time = new DateTime('2025-06-29 14:30:00');
$time = new DateTime('+1 day'); // 相对时间格式化输出
$now = new DateTime();
echo $now->format('Y-m-d'); // 2025-06-29
echo $now->format('Y-m-d H:i:s'); // 2025-06-29 14:30:00
echo $now->format('m/d/Y'); // 06/29/2025
echo $now->format('l, F j, Y'); // Sunday, June 29, 2025
echo $now->format('Y-m-dTH:i:sP'); // 2025-06-29T14:30:00+08:00时间戳转换
$now = new DateTime();
// DateTime → 时间戳
$timestamp = $now->getTimestamp();
// 时间戳 → DateTime
$time = DateTime::createFromFormat('U', (string) $timestamp);时间计算
加减时间
$time = new DateTime('2025-06-29');
// 使用 modify()
$time->modify('+1 day');
$time->modify('-3 months');
$time->modify('+1 week +2 days');
// 使用 DateInterval(推荐)
$time->add(new DateInterval('P1D')); // +1 天
$time->sub(new DateInterval('P3M')); // -3 个月
$time->add(new DateInterval('P1Y2M10D')); // +1 年 2 月 10 天ISO 8601 持续时间格式:
| 格式 | 含义 |
|---|---|
P3D | 3 天 |
P2W | 2 周 |
P1M | 1 月 |
P1Y | 1 年 |
PT30M | 30 分钟 |
PT2H30M | 2 小时 30 分 |
P1YT2H | 1 年 2 小时 |
时间差
$start = new DateTime('2025-01-01');
$end = new DateTime('2025-06-29');
$diff = $end->diff($start);
echo $diff->days; // 相隔总天数
echo $diff->y; // 年数差
echo $diff->m; // 月数差
echo $diff->d; // 天数差
echo $diff->format('%y 年 %m 月 %d 天'); // 格式化输出比较时间
$t1 = new DateTime('2025-01-01');
$t2 = new DateTime('2025-06-29');
$t1 < $t2; // true
$t1 > $t2; // false
$t1 == $t2; // false
$t1->format('Y-m-d') === $t2->format('Y-m-d'); // 仅比较日期时区处理
设置时区
// 创建时指定
$time = new DateTime('now', new DateTimeZone('Asia/Shanghai'));
// 修改已有对象
$time = new DateTime();
$time->setTimezone(new DateTimeZone('UTC'));
// 获取当前时区
echo $time->getTimezone()->getName(); // Asia/Shanghai常用时区标识
| 标识 | 含义 | UTC 偏移 |
|---|---|---|
Asia/Shanghai | 中国标准时间 | +08:00 |
America/New_York | 美国东部时间 | -05:00 |
Europe/London | 英国时间 | +00:00 |
UTC | 协调世界时 | +00:00 |
常用场景
获取当月第一天和最后一天
$now = new DateTime();
$firstDay = clone $now;
$firstDay->modify('first day of this month');
$lastDay = clone $now;
$lastDay->modify('last day of this month');判断是否是今天/昨天/明天
$target = new DateTime('2025-06-28');
$today = new DateTime();
if ($target->format('Y-m-d') === $today->format('Y-m-d')) {
echo '今天';
} elseif ($target->format('Y-m-d') === $today->modify('-1 day')->format('Y-m-d')) {
echo '昨天';
}工作日计算
$date = new DateTime('2025-06-29');
// 跳过周末,往后推 5 个工作日
for ($i = 0; $i < 5; $i++) {
$date->modify('+1 day');
if ((int) $date->format('N') >= 6) { // N: 1=周一 ... 7=周日
$date->modify('+1 day');
$i--; // 周末不计入
}
}
echo $date->format('Y-m-d');Carbon 推荐
生产环境中推荐使用 Carbon 库,它是 DateTime 的增强封装:
composer require nesbot/carbonuse Carbon\Carbon;
Carbon::now(); // 当前时间
Carbon::parse('2025-06-29'); // 解析字符串
Carbon::now()->addDays(5); // +5 天
Carbon::now()->subHours(2); // -2 小时
Carbon::now()->diffForHumans(Carbon::now()->subMinute()); // "1 分钟前"
Carbon::now()->isWeekend(); // 是否周末
Carbon::now()->startOfDay(); // 当天 00:00:00⚠️ strtotime 注意事项
strtotime() 在处理月末日期时容易产生意外结果:
// 2025-01-31 - 1 个月 → 2025-01-31(1 月没有 30 天前一天会进位)
date('Y-m-d', strtotime('2025-01-31 -1 month')); // 2025-01-31
// 推荐:使用 DateTime
$date = new DateTime('2025-01-31');
$date->modify('-1 month');
echo $date->format('Y-m-d'); // 2024-12-31涉及月份加减时,优先使用 DateTime::modify() 而非 strtotime()。
