DateTimeZone 时区处理
DateTimeZone 类封装了时区信息,是 DateTime 操作的重要组成部分。正确的时区处理对于国际化应用、日志记录和定时任务至关重要。本节将讲解 PHP 时区的创建、转换和使用。
前置知识
阅读本节前,建议先了解:DateTime 类
基础概念
PHP 时区设置
php
<?php
declare(strict_types=1);
// php.ini 设置默认时区
// date.timezone = Asia/Shanghai
// 运行时设置
date_default_timezone_set('Asia/Shanghai');
// 获取当前默认时区
echo "默认时区: " . date_default_timezone_get() . PHP_EOL;
// 获取所有支持的时区列表
$zones = DateTimeZone::listIdentifiers();
echo "支持 " . count($zones) . " 个时区" . PHP_EOL;
// 按地区获取时区
$asiaZones = DateTimeZone::listIdentifiers(DateTimeZone::ASIA);
$europeZones = DateTimeZone::listIdentifiers(DateTimeZone::EUROPE);创建 DateTimeZone
php
<?php
declare(strict_types=1);
// 从时区标识符创建
$shanghai = new DateTimeZone('Asia/Shanghai');
$tokyo = new DateTimeZone('Asia/Tokyo');
$utc = new DateTimeZone('UTC');
$est = new DateTimeZone('America/New_York');
// 从缩写创建(不推荐,可能有歧义)
// $cst = new DateTimeZone('CST'); // 可能是 Chicago 或 Cuba 等
// 从偏移量创建
$offset = new DateTimeZone('+08:00');
$offsetNeg = new DateTimeZone('-05:00');时区转换
php
<?php
declare(strict_types=1);
// 创建 UTC 时间
$utcTime = new DateTimeImmutable('2024-01-15 14:30:00', new DateTimeZone('UTC'));
echo "UTC: " . $utcTime->format('Y-m-d H:i:s T') . PHP_EOL;
// 转换为北京时间
$shanghai = $utcTime->setTimezone(new DateTimeZone('Asia/Shanghai'));
echo "上海: " . $shanghai->format('Y-m-d H:i:s T') . PHP_EOL;
// 转换为东京时间
$tokyo = $utcTime->setTimezone(new DateTimeZone('Asia/Tokyo'));
echo "东京: " . $tokyo->format('Y-m-d H:i:s T') . PHP_EOL;
// 转换为纽约时间
$ny = $utcTime->setTimezone(new DateTimeZone('America/New_York'));
echo "纽约: " . $ny->format('Y-m-d H:i:s T') . PHP_EOL;
// 输出多个时区的当前时间
$zones = ['UTC', 'Asia/Shanghai', 'Asia/Tokyo', 'America/New_York', 'Europe/London'];
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
foreach ($zones as $zoneName) {
$zoned = $now->setTimezone(new DateTimeZone($zoneName));
echo "{$zoneName}: " . $zoned->format('Y-m-d H:i:s e') . PHP_EOL;
}时区偏移信息
php
<?php
declare(strict_types=1);
$zone = new DateTimeZone('Asia/Shanghai');
// 获取偏移量(秒)
$offset = $zone->getOffset(new DateTime('2024-01-15'));
echo "偏移秒数: {$offset}" . PHP_EOL; // 28800 (8小时)
echo "偏移小时: " . ($offset / 3600) . PHP_EOL; // 8
// 获取时区名称
echo "时区名: " . $zone->getName() . PHP_EOL;
// 获取时区缩写
$transitions = $zone->getTransitions(time() - 86400, time() + 86400);
if (!empty($transitions)) {
echo "缩写: " . $transitions[0]['abbr'] . PHP_EOL;
echo "是否 DST: " . ($transitions[0]['isdst'] ? '是' : '否') . PHP_EOL;
echo "偏移: " . $transitions[0]['offset'] . PHP_EOL;
}跨时区计算
php
<?php
declare(strict_types=1);
/**
* 获取两个时区之间的时差
*/
function getTimezoneDiff(string $tz1, string $tz2, string $date = 'now'): int
{
$zone1 = new DateTimeZone($tz1);
$zone2 = new DateTimeZone($tz2);
$dt = new DateTimeImmutable($date, $zone1);
$converted = $dt->setTimezone($zone2);
$offset1 = $zone1->getOffset($dt);
$offset2 = $zone2->getOffset($converted);
return ($offset2 - $offset1) / 3600;
}
echo "上海-纽约时差: " . getTimezoneDiff('Asia/Shanghai', 'America/New_York') . " 小时" . PHP_EOL;注意事项
- 使用 IANA 时区标识符(如
Asia/Shanghai),不要用缩写 setTimezone()不会改变时间点,只是切换显示时区date_default_timezone_set()是全局设置,影响所有日期函数
下一节
继续学习:日期格式化与解析