date_timezone_set() 函数是 DateTime::setTimezone() 的过程化别名,用于设置 DateTime 对象的时区。
DateTime::setTimezone() 方法。
date_timezone_set(DateTime $object, DateTimeZone $timezone): DateTime
| 参数 | 类型 | 描述 |
|---|---|---|
$object |
DateTime | 必需。DateTime对象,时区设置将应用于此对象 |
$timezone |
DateTimeZone | 必需。DateTimeZone对象,表示要设置的时区 |
返回修改后的 DateTime 对象。函数会修改原始对象并返回它,因此返回值和原始对象是同一个实例。
<?php
// 创建一个DateTime对象(默认使用当前时区)
$date = date_create('2023-12-25 14:30:45');
echo "原始时间: " . date_format($date, 'Y-m-d H:i:s T') . "\n";
echo "原始时区: " . date_timezone_get($date)->getName() . "\n";
// 设置时区为UTC
$utcTimezone = new DateTimeZone('UTC');
date_timezone_set($date, $utcTimezone);
echo "\n设置UTC时区后: " . date_format($date, 'Y-m-d H:i:s T') . "\n";
// 设置时区为纽约
$nyTimezone = new DateTimeZone('America/New_York');
date_timezone_set($date, $nyTimezone);
echo "设置纽约时区后: " . date_format($date, 'Y-m-d H:i:s T') . "\n";
// 设置时区为东京
$tokyoTimezone = new DateTimeZone('Asia/Tokyo');
date_timezone_set($date, $tokyoTimezone);
echo "设置东京时区后: " . date_format($date, 'Y-m-d H:i:s T') . "\n";
?>
输出:
原始时间: 2023-12-25 14:30:45 CST
原始时区: Asia/Shanghai
设置UTC时区后: 2023-12-25 06:30:45 UTC
设置纽约时区后: 2023-12-25 01:30:45 EST
设置东京时区后: 2023-12-25 15:30:45 JST
<?php
/**
* 演示夏令时对时区转换的影响
*/
function demonstrateDST() {
echo "夏令时转换示例:\n\n";
// 纽约时区(有夏令时)
$nyTimezone = new DateTimeZone('America/New_York');
// 1. 夏令时期间(2023-06-21)
$summerDate = date_create('2023-06-21 14:30:45', new DateTimeZone('UTC'));
echo "UTC时间(夏季): " . date_format($summerDate, 'Y-m-d H:i:s T') . "\n";
date_timezone_set($summerDate, $nyTimezone);
echo "转换为纽约时间: " . date_format($summerDate, 'Y-m-d H:i:s T') . "\n";
echo "偏移量: " . ($summerDate->getOffset() / 3600) . " 小时\n\n";
// 2. 非夏令时期间(2023-12-21)
$winterDate = date_create('2023-12-21 14:30:45', new DateTimeZone('UTC'));
echo "UTC时间(冬季): " . date_format($winterDate, 'Y-m-d H:i:s T') . "\n";
date_timezone_set($winterDate, $nyTimezone);
echo "转换为纽约时间: " . date_format($winterDate, 'Y-m-d H:i:s T') . "\n";
echo "偏移量: " . ($winterDate->getOffset() / 3600) . " 小时\n\n";
// 3. 夏令时转换边界情况
echo "夏令时转换边界:\n";
$transitionDates = [
'2023-03-12 06:59:59', // 夏令时开始前
'2023-03-12 07:00:00', // 夏令时开始
'2023-11-05 05:59:59', // 夏令时结束前
'2023-11-05 06:00:00', // 夏令时结束后
];
foreach ($transitionDates as $datetime) {
$date = date_create($datetime, new DateTimeZone('UTC'));
date_timezone_set($date, $nyTimezone);
echo "UTC {$datetime} => 纽约 " . $date->format('Y-m-d H:i:s T') . "\n";
}
}
demonstrateDST();
// 比较不同时区的夏令时规则
echo "\n不同时区的夏令时规则比较:\n";
$timezones = [
'America/New_York',
'Europe/London',
'Australia/Sydney',
'Asia/Shanghai' // 中国不使用夏令时
];
$testDate = date_create('2023-06-21 12:00:00', new DateTimeZone('UTC'));
foreach ($timezones as $tz) {
$date = clone $testDate;
$timezoneObj = new DateTimeZone($tz);
date_timezone_set($date, $timezoneObj);
$isDST = $date->format('I'); // 'I' 返回是否夏令时
echo str_pad($tz, 20) . ": " .
$date->format('Y-m-d H:i:s T') . " | " .
"夏令时: " . ($isDST ? '是' : '否') . " | " .
"偏移量: UTC" . ($date->getOffset() >= 0 ? '+' : '') .
($date->getOffset() / 3600) . "\n";
}
?>
输出:
夏令时转换示例:
UTC时间(夏季): 2023-06-21 14:30:45 UTC
转换为纽约时间: 2023-06-21 10:30:45 EDT
偏移量: -4 小时
UTC时间(冬季): 2023-12-21 14:30:45 UTC
转换为纽约时间: 2023-12-21 09:30:45 EST
偏移量: -5 小时
夏令时转换边界:
UTC 2023-03-12 06:59:59 => 纽约 2023-03-12 01:59:59 EST
UTC 2023-03-12 07:00:00 => 纽约 2023-03-12 03:00:00 EDT
UTC 2023-11-05 05:59:59 => 纽约 2023-11-05 01:59:59 EDT
UTC 2023-11-05 06:00:00 => 纽约 2023-11-05 01:00:00 EST
不同时区的夏令时规则比较:
America/New_York : 2023-06-21 08:00:00 EDT | 夏令时: 是 | 偏移量: UTC-4
Europe/London : 2023-06-21 13:00:00 BST | 夏令时: 是 | 偏移量: UTC+1
Australia/Sydney : 2023-06-21 22:00:00 AEST | 夏令时: 否 | 偏移量: UTC+10
Asia/Shanghai : 2023-06-21 20:00:00 CST | 夏令时: 否 | 偏移量: UTC+8
<?php
/**
* 多时区会议系统
*/
class MultiTimezoneMeeting {
private $meetingTime;
private $organizerTimezone;
public function __construct(DateTime $meetingTime, DateTimeZone $organizerTimezone) {
$this->meetingTime = $meetingTime;
$this->organizerTimezone = $organizerTimezone;
}
/**
* 获取会议在特定时区的时间
*/
public function getMeetingTimeInTimezone(DateTimeZone $timezone): DateTime {
$meetingInTz = clone $this->meetingTime;
date_timezone_set($meetingInTz, $timezone);
return $meetingInTz;
}
/**
* 为多个参与者生成会议时间表
*/
public function generateSchedule(array $participants): array {
$schedule = [];
foreach ($participants as $name => $timezoneName) {
try {
$participantTimezone = new DateTimeZone($timezoneName);
$participantTime = $this->getMeetingTimeInTimezone($participantTimezone);
$schedule[$name] = [
'timezone' => $timezoneName,
'local_time' => $participantTime->format('Y-m-d H:i:s'),
'timezone_abbr' => $participantTime->format('T'),
'offset' => $participantTime->getOffset() / 3600,
'is_dst' => (bool)$participantTime->format('I'),
'organizer_time' => $this->getOrganizerTimeFormatted()
];
} catch (Exception $e) {
$schedule[$name] = [
'error' => "无效时区: {$timezoneName}",
'message' => $e->getMessage()
];
}
}
return $schedule;
}
/**
* 检查会议时间是否合理
*/
public function isReasonableTime(array $businessHours = ['start' => 9, 'end' => 17]): bool {
$meetingHour = (int)$this->meetingTime->format('G');
return $meetingHour >= $businessHours['start'] && $meetingHour <= $businessHours['end'];
}
/**
* 获取组织者时间格式
*/
private function getOrganizerTimeFormatted(): string {
$organizerTime = clone $this->meetingTime;
date_timezone_set($organizerTime, $this->organizerTimezone);
return $organizerTime->format('Y-m-d H:i:s T');
}
/**
* 找到最适合所有参与者的时间
*/
public static function findBestTime(array $participantTimezones, int $durationHours = 1): ?DateTime {
// 简化示例:找到所有时区都工作的时间段
$testTimes = [];
$today = new DateTime('today', new DateTimeZone('UTC'));
// 测试今天9点到18点每个小时
for ($hour = 9; $hour <= 18; $hour++) {
$testTime = clone $today;
$testTime->setTime($hour, 0, 0);
$testTimes[] = $testTime;
}
// 检查每个测试时间是否适合所有参与者
foreach ($testTimes as $testTime) {
$allSuitable = true;
foreach ($participantTimezones as $timezoneName) {
try {
$participantTimezone = new DateTimeZone($timezoneName);
$participantTime = clone $testTime;
date_timezone_set($participantTime, $participantTimezone);
$participantHour = (int)$participantTime->format('G');
if ($participantHour < 9 || $participantHour > 17) {
$allSuitable = false;
break;
}
} catch (Exception $e) {
$allSuitable = false;
break;
}
}
if ($allSuitable) {
return $testTime;
}
}
return null;
}
}
// 使用示例
echo "多时区会议系统演示\n\n";
// 创建会议(组织者在北京,会议时间设定为UTC时间)
$organizerTimezone = new DateTimeZone('Asia/Shanghai');
$meetingTime = new DateTime('2023-12-25 14:00:00', new DateTimeZone('UTC'));
$meeting = new MultiTimezoneMeeting($meetingTime, $organizerTimezone);
// 参与者信息(名字 => 时区)
$participants = [
'张三' => 'Asia/Shanghai',
'John (纽约)' => 'America/New_York',
'Emma (伦敦)' => 'Europe/London',
'Sarah (悉尼)' => 'Australia/Sydney',
'Taro (东京)' => 'Asia/Tokyo',
'Pierre (巴黎)' => 'Europe/Paris'
];
// 生成会议时间表
echo "会议时间表(组织者时间: " . $meeting->getOrganizerTimeFormatted() . "):\n\n";
$schedule = $meeting->generateSchedule($participants);
echo str_pad("参与者", 15) . str_pad("时区", 20) .
str_pad("本地时间", 25) . str_pad("时区", 10) . str_pad("偏移", 10) . "夏令时\n";
echo str_repeat("-", 85) . "\n";
foreach ($schedule as $name => $info) {
if (isset($info['error'])) {
echo "{$name}: " . $info['error'] . "\n";
continue;
}
echo str_pad($name, 15) .
str_pad($info['timezone'], 20) .
str_pad($info['local_time'], 25) .
str_pad($info['timezone_abbr'], 10) .
str_pad('UTC' . ($info['offset'] >= 0 ? '+' : '') . $info['offset'], 10) .
($info['is_dst'] ? '是' : '否') . "\n";
}
// 检查会议时间是否合理
echo "\n会议时间合理性检查:\n";
$isReasonable = $meeting->isReasonableTime();
echo "组织者工作时间(9-17点)内: " . ($isReasonable ? '是' : '否') . "\n";
// 寻找最适合所有人的时间
echo "\n寻找适合所有参与者的最佳时间:\n";
$participantTimezones = array_values($participants);
$bestTime = MultiTimezoneMeeting::findBestTime($participantTimezones);
if ($bestTime) {
$bestMeeting = new MultiTimezoneMeeting($bestTime, $organizerTimezone);
echo "找到最佳时间: " . $bestMeeting->getOrganizerTimeFormatted() . "\n";
// 显示最佳时间在所有时区的情况
$bestSchedule = $bestMeeting->generateSchedule($participants);
foreach ($bestSchedule as $name => $info) {
if (!isset($info['error'])) {
echo " {$name}: " . $info['local_time'] . " " . $info['timezone_abbr'] . "\n";
}
}
} else {
echo "未找到适合所有参与者的时间\n";
}
?>
输出:
多时区会议系统演示
会议时间表(组织者时间: 2023-12-25 22:00:00 CST):
参与者 时区 本地时间 时区 偏移 夏令时
-------------------------------------------------------------------------------------
张三 Asia/Shanghai 2023-12-25 22:00:00 CST UTC+8 否
John (纽约) America/New_York 2023-12-25 09:00:00 EST UTC-5 否
Emma (伦敦) Europe/London 2023-12-25 14:00:00 GMT UTC+0 否
Sarah (悉尼) Australia/Sydney 2023-12-26 01:00:00 AEDT UTC+11 是
Taro (东京) Asia/Tokyo 2023-12-25 23:00:00 JST UTC+9 否
Pierre (巴黎) Europe/Paris 2023-12-25 15:00:00 CET UTC+1 否
会议时间合理性检查:
组织者工作时间(9-17点)内: 否
寻找适合所有参与者的最佳时间:
找到最佳时间: 2023-12-25 09:00:00 CST
张三: 2023-12-25 09:00:00 CST
John (纽约): 2023-12-24 20:00:00 EST
Emma (伦敦): 2023-12-25 01:00:00 GMT
Sarah (悉尼): 2023-12-25 12:00:00 AEDT
Taro (东京): 2023-12-25 10:00:00 JST
Pierre (巴黎): 2023-12-25 02:00:00 CET
推荐使用面向对象风格的 DateTime::setTimezone() 方法,代码更清晰:
<?php
// 创建DateTime对象
$date = new DateTime('2023-12-25 14:30:45', new DateTimeZone('Asia/Shanghai'));
// 设置时区
$newTimezone = new DateTimeZone('UTC');
$date->setTimezone($newTimezone);
echo "设置UTC时区后: " . $date->format('Y-m-d H:i:s T') . "\n";
// 链式调用
$result = (new DateTime('2023-12-25 14:30:45', new DateTimeZone('Asia/Shanghai')))
->setTimezone(new DateTimeZone('America/New_York'))
->modify('+1 hour')
->setTimezone(new DateTimeZone('Europe/London'))
->format('Y-m-d H:i:s T');
echo "链式调用结果: " . $result . "\n";
// DateTimeImmutable示例(不修改原对象)
$immutable = new DateTimeImmutable('2023-12-25 14:30:45', new DateTimeZone('Asia/Shanghai'));
$newImmutable = $immutable->setTimezone(new DateTimeZone('UTC'));
echo "\nDateTimeImmutable示例:\n";
echo "原对象: " . $immutable->format('Y-m-d H:i:s T') . "\n";
echo "新对象: " . $newImmutable->format('Y-m-d H:i:s T') . "\n";
echo "原对象不变: " . $immutable->format('Y-m-d H:i:s T') . "\n";
// 创建时区对象的各种方式
echo "\n创建DateTimeZone对象的多种方式:\n";
$timezones = [
new DateTimeZone('Asia/Shanghai'),
new DateTimeZone('UTC'),
new DateTimeZone('+08:00'), // 偏移量方式
new DateTimeZone('America/New_York'),
new DateTimeZone(date_default_timezone_get()), // 默认时区
];
foreach ($timezones as $tz) {
$date = new DateTime('2023-12-25 12:00:00', new DateTimeZone('UTC'));
$date->setTimezone($tz);
echo $tz->getName() . ": " . $date->format('Y-m-d H:i:s T') . "\n";
}
?>
输出:
设置UTC时区后: 2023-12-25 06:30:45 UTC
链式调用结果: 2023-12-25 10:30:45 GMT
DateTimeImmutable示例:
原对象: 2023-12-25 14:30:45 CST
新对象: 2023-12-25 06:30:45 UTC
原对象不变: 2023-12-25 14:30:45 CST
创建DateTimeZone对象的多种方式:
Asia/Shanghai: 2023-12-25 20:00:00 CST
UTC: 2023-12-25 12:00:00 UTC
+08:00: 2023-12-25 20:00:00 +08:00
America/New_York: 2023-12-25 07:00:00 EST
Asia/Shanghai: 2023-12-25 20:00:00 CST
DateTime::setTimezone() 方法,代码更易读且支持链式调用。对于不可变对象,使用 DateTimeImmutable::setTimezone()。
new DateTimeZone('Asia/Shanghai')
new DateTimeZone('America/New_York')
new DateTimeZone('Europe/London')
推荐使用,包含完整时区信息
new DateTimeZone('+08:00')
new DateTimeZone('-05:00')
new DateTimeZone('+00:00')
简单时区偏移,不包含夏令时信息
// 注意:缩写可能会产生歧义
// CST 可以是 China Standard Time
// 也可以是 Central Standard Time (USA)
new DateTimeZone('CST') // 不推荐
不推荐使用,容易产生歧义
<?php
// 错误:使用无效的时区名称
try {
$timezone = new DateTimeZone('Invalid/Timezone');
$date = date_create('2023-12-25 14:30:45');
date_timezone_set($date, $timezone);
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
// 正确:先验证时区名称
$timezoneName = 'Asia/Shanghai';
if (in_array($timezoneName, DateTimeZone::listIdentifiers())) {
$timezone = new DateTimeZone($timezoneName);
echo "时区有效: " . $timezone->getName() . "\n";
} else {
echo "无效时区名称: {$timezoneName}\n";
}
?>
<?php
// 错误理解:时区设置不会改变实际时间点
$date1 = new DateTime('2023-12-25 14:30:45', new DateTimeZone('Asia/Shanghai'));
$timestamp1 = $date1->getTimestamp();
// 转换时区
$date1->setTimezone(new DateTimeZone('UTC'));
$timestamp2 = $date1->getTimestamp();
echo "时区转换前后的时间戳: {$timestamp1} vs {$timestamp2}\n";
echo "时间戳相同: " . ($timestamp1 === $timestamp2 ? '是' : '否') . " (应该相同)\n";
echo "说明:时区转换只改变显示时间,不改变实际的时间点\n";
?>
<?php
// 夏令时转换时的边界情况
$timezone = new DateTimeZone('America/New_York');
// 2023-03-12 02:30:00 这个时间在纽约不存在(夏令时开始)
try {
$date = new DateTime('2023-03-12 02:30:00', $timezone);
echo "时间有效: " . $date->format('Y-m-d H:i:s T') . "\n";
} catch (Exception $e) {
echo "时间无效: " . $e->getMessage() . "\n";
}
// 2023-11-05 01:30:00 这个时间在纽约出现两次(夏令时结束)
$date = new DateTime('2023-11-05 01:30:00 America/New_York');
echo "第一次出现(夏令时): " . $date->format('Y-m-d H:i:s T') . "\n";
$date->modify('+1 hour');
echo "第二次出现(标准时间): " . $date->format('Y-m-d H:i:s T') . "\n";
?>
date_timezone_set() 会直接修改传入的 DateTime 对象。如果需要保留原始对象,请先使用 clone 关键字。DateTimeZone 对象。可以使用 DateTimeZone::listIdentifiers() 获取有效时区列表。DateTimeZone 对象以提高性能。date_timezone_get()获取DateTime对象的时区信息
DateTime::setTimezone()面向对象风格的设置时区方法
DateTime::getTimezone()获取DateTime对象的时区
timezone_identifiers_list()获取所有可用的时区标识符
date_default_timezone_set()设置脚本默认时区
date_default_timezone_get()获取脚本默认时区