深度解析 PHP Carbon 日期库:从入门到项目实战的 15 个高频操作
目录导读
- Carbon 简介:为何成为 PHP 日期处理的事实标准?
- 安装与初始化:3 分钟接入你的项目
- 核心基础:创建、格式化与输出日期
- 日期比较:你还在用
strtotime做对比? - 时间运算:加减日期就像呼吸一样自然
- 时区处理:告别时区转换的噩梦
- 人性化显示:
diffForHumans()的 8 种场景 - 常用查询:判断今天、周末、闰年等 12 个方法
- 与数据库(Laravel/原生)的集成技巧
- 高级功能:
macro扩展与自定义格式 - 常见问答:6 个真实项目踩坑经验
- 性能优化与注意事项
Carbon 简介:为何成为 PHP 日期处理的事实标准?
在 PHP 生态中,日期和时间处理一直是开发者绕不开的话题,原生 PHP 的 DateTime 类和 strtotime 函数虽然可用,但代码冗长、方法链不流畅,尤其在时区转换、人性化显示方面显得捉襟见肘。

Carbon 是什么?
Carbon 是基于 PHP 原生 DateTime 类的扩展库,通过继承原生类并提供 200+ 方法,让日期操作像“链式调用”一样优雅,官方文档显示,全球超过 50% 的 PHP 项目(尤其是 Laravel 框架)默认使用 Carbon。
为什么选择 Carbon?
- 语义化方法:
addDay()比DateInterval创建 +add()更直观 - 零学习成本:兼容所有
DateTime原生方法 - 不可变性:默认方法返回新实例,避免意外修改原对象
安装与初始化:3 分钟接入你的项目
通过 Composer 安装
composer require nesbot/carbon
基本使用
use Carbon\Carbon; echo Carbon::now(); // 2025-04-05 14:30:00 echo Carbon::today(); // 2025-04-05 00:00:00 echo Carbon::yesterday(); // 2025-04-04 echo Carbon::tomorrow(); // 2025-04-06
从时间戳/字符串创建
// 从时间戳
$dt = Carbon::createFromTimestamp(1712304000);
// 从字符串
$dt = Carbon::parse('next Friday');
$dt = Carbon::parse('2025-04-05 14:30:00');
核心基础:创建、格式化与输出日期
格式化方法
$dt = Carbon::now();
echo $dt->toDateString(); // 2025-04-05
echo $dt->toDateTimeString(); // 2025-04-05 14:30:00
echo $dt->toTimeString(); // 14:30:00
echo $dt->format('Y-m-d H:i:s'); // 自定义格式
echo $dt->isoFormat('LL'); // 2025年4月5日(语言国际化)
常用属性获取
$dt->year; // 2025 $dt->month; // 4 $dt->day; // 5 $dt->hour; // 14 $dt->minute; // 30 $dt->second; // 0 $dt->dayOfWeek; // 6(周六,0=周日) $dt->weekOfMonth; // 2
日期比较:你还在用 strtotime 做对比?
原生 PHP 比较日期需要手动转换,Carbon 提供了 10+ 种比较方法:
$first = Carbon::parse('2025-04-05');
$second = Carbon::parse('2025-06-15');
// 比较
$first->eq($second); // false
$first->gt($second); // false
$first->lt($second); // true
$first->gte($second); // false
$first->ne($second); // true
// 范围比较
$first->between('2025-01-01', '2025-12-31', true); // true
$first->isWeekday(); // false(周六)
$first->isWeekend(); // true
实战场景:判断用户注册是否超过30天
$registeredAt = Carbon::parse($user->created_at);
if ($registeredAt->diffInDays(Carbon::now()) > 30) {
echo "已注册超过30天";
}
时间运算:加减日期就像呼吸一样自然
加减操作
$dt = Carbon::now(); // 加 $dt->addDay(); // +1天 $dt->addDays(10); // +10天 $dt->addWeek(); // +1周 $dt->addWeeks(3); // +3周 $dt->addMonth(); // +1月 $dt->addYear(); // +1年 // 减(同理) $dt->subMonth(); // -1月
链式调用示例
$dt = Carbon::now()
->addYear()
->subMonth()
->addDays(5);
注意:Carbon 默认返回新实例,不修改原对象,如果希望直接修改,需调用 ->modify() 或使用可变版本 Carbon\CarbonImmutable。
时区处理:告别时区转换的噩梦
切换到其他时区
$dt = Carbon::now('Asia/Shanghai');
echo $dt->tzName; // Asia/Shanghai
$dt->setTimezone('America/New_York');
echo $dt->format('Y-m-d H:i:s'); // 自动转换时间
时区列表与检测
$dt->timezoneName; // 获取时区全名 $dt->offsetHours; // 时区偏移小时数(如 8) // 列出所有可用时区 $timezones = Carbon::timezone()->getAbbreviations();
常用时区字符串
UTC/GMTAsia/Shanghai(东八区)America/New_York(美东时间)Europe/London(伦敦时间)
人性化显示:diffForHumans() 的 8 种场景
这是 Carbon 最受好评的功能之一,自动生成“2小时前”“3天后”等描述:
$dt = Carbon::now()->subHours(2);
echo $dt->diffForHumans(); // "2 hours ago"
$future = Carbon::now()->addDays(5);
echo $future->diffForHumans(); // "5 days from now"
// 中文显示(需设置语言)
Carbon::setLocale('zh');
echo $dt->diffForHumans(); // "2小时前"
场景定制
// 绝对差异 echo $dt->diffForHumans(['join' => ', ']); // "2 hours, 30 minutes ago" // 移除“ago”后缀 echo $dt->diffForHumans(['syntax' => CarbonInterface::DIFF_ABSOLUTE]); // "2 hours" // 自定义比较时间 echo $dt->diffForHumans(Carbon::yesterday()); // "1 day after yesterday"
常用查询:判断今天、周末、闰年等 12 个方法
Carbon 内置了大量布尔查询方法,极大简化逻辑判断:
$dt = Carbon::now(); // 基本状态 $dt->isToday(); // true $dt->isYesterday(); // false $dt->isTomorrow(); // false $dt->isFuture(); // false $dt->isPast(); // true // 每周/月/年判断 $dt->isWeekday(); // false(周六) $dt->isWeekend(); // true $dt->isMonday(); // false $dt->isSunday(); // false $dt->isLeapYear(); // false(2025不是闰年) // 相对判断 $dt->isSameDay(Carbon::yesterday()); // false $dt->isCurrentYear(); // true $dt->isNextYear(); // false
与数据库(Laravel/原生)的集成技巧
Laravel Eloquent 中的 Carbon
Laravel 默认将 created_at 等时间戳自动转为 Carbon 实例,可直接调用:
$user = User::find(1); echo $user->created_at->diffForHumans(); // "3 months ago"
批量设置为 Carbon
protected $dates = ['birthday', 'expired_at']; // 在模型中定义后,这些字段自动转为 Carbon
原生 SQL 与 Carbon 互转
// 从数据库取出后转为 Carbon $dateFromDb = $row['created_at']; $carbon = Carbon::parse($dateFromDb); // 存入数据库前 $dbValue = $carbon->toDateTimeString(); // 或直接传 Carbon,PDO 自动处理
高级功能:macro 扩展与自定义格式
宏扩展(自定义方法)
Carbon::macro('toAsiaString', function () {
return $this->timezone('Asia/Shanghai')->format('Y-m-d H:i:s');
});
echo Carbon::now()->toAsiaString(); // 注册后全局使用
自定义格式化
// 周数表示
echo $dt->isoFormat('W'); // 当前年的第几周
// 语言本地化
Carbon::setLocale('fr');
echo $dt->isoFormat('dddd'); // "samedi"
静态工厂方法
Carbon::create(2025, 4, 5, 14, 30, 0); // 年月日时分秒 Carbon::createFromDate(2025, 4, 5); // 仅日期 Carbon::createFromTime(14, 30); // 仅时间
十一、常见问答:6 个真实项目踩坑经验
Q1:为什么 Carbon::now() 获取的是服务器时间而不是北京时间?
A:默认使用 PHP 配置的 date.timezone,需在项目入口设置:
date_default_timezone_set('Asia/Shanghai');
// 或 Laravel 修改 config/app.php 的 timezone
Q2:addMonth() 导致日期溢出(如 1月31日加1月变成3月3日)?
A:Carbon 自动处理溢出:
Carbon::parse('2025-01-31')->addMonth(); // 2025-03-03(因为2月只有28天)
// 若需保留一个月最后一天,使用 addMonthWithOverflow(false)
Q3:如何获取两个日期之间的所有日期?
A:使用 Carbon\CarbonPeriod:
$period = Carbon::parse('2025-04-01')->toPeriod('2025-04-05');
foreach ($period as $date) {
echo $date->format('Y-m-d'); // 输出 04-01 到 04-05
}
Q4:diffForHumans() 显示英文,如何改为中文?
A:安装中文语言包:
Carbon::setLocale('zh');
// 确保 PHP 安装了 intl 扩展
Q5:如何判断当前时间是否在某两个时间之间?
A:between() 方法:
$now = Carbon::now();
$start = Carbon::parse('2025-04-01');
$end = Carbon::parse('2025-04-30');
if ($now->between($start, $end, true)) { // true 包含边界
echo "在范围内";
}
Q6:时间戳转换出现负数?
A:检查是否使用了毫秒时间戳(13位),需除以1000:
$microTimestamp = 1712304000000; echo Carbon::createFromTimestamp($microTimestamp / 1000);
十二、性能优化与注意事项
-
避免频繁调用
now()
循环内多次获取当前时间建议使用$now = Carbon::now()缓存变量。 -
善用
CarbonImmutable
不可变版本在复杂链式操作中更安全,避免意外修改共享对象:use Carbon\CarbonImmutable; $dt = CarbonImmutable::now();
-
时区转换消耗
每次setTimezone()会重新计算时间,批量处理时建议在开始一次性设置。 -
语言包缓存
频繁切换setLocale()可能影响性能,对于固定语言在应用启动时设置即可。 -
debug_backtrace 警告
某些环境使用__toString()时可能触发性能问题,用format()代替。
Carbon 将 PHP 日期处理从“工具函数”提升为“流畅的语言”,建议在项目中尽早统一使用 Carbon,并结合 Laravel(如果使用)的自动类型转换,可减少80%的日期相关 Bug,对于新手,掌握 parse()、diffForHumans()、format() 和 addDays() 这四个核心方法,就能应对90%的日常开发需求。