Yii框架时间戳行为错误主因是配置时机、时区不一致或字段类型不匹配;INT型字段须用time(),DATETIME/TIMESTAMP宜用NOW()表达式,并确保PHP、MySQL及Yii formatter时区统一为Asia/Shanghai。

Yii框架中时间戳行为(TimestampBehavior)引入错误,多数不是行为类本身写错了,而是配置时机、时区对齐或数据库字段类型不匹配导致的。核心问题往往出在“值生成方式”和“底层时区”没统一。
检查 TimestampBehavior 的 value 配置是否适配字段类型
MySQL 的 DATETIME 和 TIMESTAMP 字段对 NOW() 表达式支持良好,但若字段是 INT 类型(存 Unix 时间戳),就不能直接用 'value' => new \yii\db\Expression('NOW()')——这会插入非法值,报 SQL 错误或写入 0。
- INT 类型时间戳字段(如 created_at int(11)),应改用 PHP 时间函数:
'value' => time()或'value' => function () { return time(); } - DATETIME/TIMESTAMP 字段,推荐用
'value' => new \yii\db\Expression('NOW()'),由数据库生成,精度高且避免 PHP 与 DB 时区差 - 别混用:比如字段是 DATETIME 却设
'value' => date('Y-m-d H:i:s'),既丧失数据库自动更新能力,又可能因 PHP 时区未设导致写入偏移
确认 PHP 和数据库时区已全局对齐
即使 TimestampBehavior 写对了,若 PHP 或 MySQL 时区是 UTC,而你期望北京时间(Asia/Shanghai),写入的“NOW()”就是 UTC 时间,看起来像晚了 8 小时——这不是行为错,是环境错。
- PHP 层:确保
php.ini中date.timezone = "Asia/Shanghai",并重启 PHP-FPM 和 Web 服务 - MySQL 层:执行
SET GLOBAL time_zone = '+08:00';,或在 my.cnf 中配置default-time-zone='+08:00' - Yii2 应用层:在
config/web.php的'components'中补上'formatter' => ['timeZone' => 'Asia/Shanghai'],避免 GridView 等组件显示错乱
验证模型属性是否被其他逻辑覆盖
TimestampBehavior 只在指定事件(如 EVENT_BEFORE_INSERT)触发,但如果模型里手动赋值了 $model->created_at = ...,就会绕过行为,导致时间不生效或冲突。
- 检查模型代码中是否在
beforeSave()或构造函数里直接设置了时间字段 - 查看 rules() 是否把时间字段加进了
safe或required,导致批量赋值时被意外写入空值或旧值 - 调试技巧:在行为的
value回调里临时加file_put_contents('/tmp/tb.log', date('c')."\n", FILE_APPEND);,确认行为是否真的触发
Yii1.1 项目需额外注意初始化顺序
Yii1.1 不自动读取 php.ini 的时区,且 CActiveRecord 初始化早于行为绑定。如果入口文件没第一时间设时区,TimestampBehavior 用的仍是系统默认(常为 UTC)。
- 打开
index.php,在require_once('yii.php');之前第一行加入:date_default_timezone_set('Asia/Shanghai'); - 禁止在组件、控制器或模型中重复调用
date_default_timezone_set(),否则 CDateTimeParser 等内部类会缓存旧规则,造成解析异常 - Yii1.1 的时间戳行为类是
CTimestampBehavior,配置键名略有不同:'createAttribute' => 'created_at',不是createdAtAttribute


















