timezone_offset_get() 函数是 DateTimeZone 类的方法,用于返回相对于 GMT 的时区偏移量。这个函数需要传入一个 DateTime 对象作为参数,以便计算特定时间点的偏移量(考虑夏令时等因素)。
注意:这不是一个独立的函数,而是 DateTimeZone 对象的实例方法,需要通过 DateTimeZone 对象调用。
DateTimeZone::getOffset(DateTimeInterface $datetime) : int
| 参数 | 描述 |
|---|---|
| datetime |
必需。 一个 由于时区偏移量可能因夏令时而变化,所以需要指定具体的时间。 |
返回相对于 GMT 的偏移量(以秒为单位)。正值表示东时区,负值表示西时区。
<?php
// 创建 DateTimeZone 对象
$timezone = new DateTimeZone('America/New_York');
// 创建当前时间的 DateTime 对象
$datetime = new DateTime('now');
// 获取时区偏移量
$offset = $timezone->getOffset($datetime);
echo "时区: " . $timezone->getName() . "<br>";
echo "当前时间: " . $datetime->format('Y-m-d H:i:s') . "<br>";
echo "偏移量: " . $offset . " 秒<br>";
echo "偏移量: " . ($offset / 3600) . " 小时<br>";
// 输出类似:
// 时区: America/New_York
// 当前时间: 2023-08-15 10:30:45
// 偏移量: -14400 秒
// 偏移量: -4 小时
?>
<?php
// 比较不同时区在同一时间的偏移量
$datetime = new DateTime('2023-08-15 10:30:45');
$timezones = [
'America/New_York',
'Asia/Shanghai',
'Europe/London',
'Australia/Sydney',
'UTC',
'Pacific/Honolulu'
];
echo "<h4>比较不同时区在 " . $datetime->format('Y-m-d H:i:s') . " 的偏移量:</h4>";
echo "<table border='1'>";
echo "<tr><th>时区</th><th>偏移量(秒)</th><th>偏移量(小时)</th><th>GMT偏移</th></tr>";
foreach ($timezones as $tz) {
$timezone = new DateTimeZone($tz);
$offset = $timezone->getOffset($datetime);
$hours = $offset / 3600;
echo "<tr>";
echo "<td>" . $tz . "</td>";
echo "<td>" . $offset . "</td>";
echo "<td>" . $hours . "</td>";
echo "<td>GMT" . ($hours >= 0 ? '+' : '') . $hours . "</td>";
echo "</tr>";
}
echo "</table>";
// 输出类似:
// 比较不同时区在 2023-08-15 10:30:45 的偏移量:
// 时区 偏移量(秒) 偏移量(小时) GMT偏移
// America/New_York -14400 -4 GMT-4
// Asia/Shanghai 28800 8 GMT+8
// Europe/London 3600 1 GMT+1
// Australia/Sydney 36000 10 GMT+10
// UTC 0 0 GMT+0
// Pacific/Honolulu -36000 -10 GMT-10
?>
<?php
// 演示夏令时对偏移量的影响
$timezone = new DateTimeZone('America/New_York');
// 测试不同时间的偏移量
$dates = [
'2023-01-15 10:30:45', // 冬季,非夏令时
'2023-07-15 10:30:45', // 夏季,夏令时
'2023-03-12 01:30:45', // 夏令时开始前后
'2023-11-05 01:30:45' // 夏令时结束前后
];
echo "<h4>纽约时区的夏令时影响:</h4>";
foreach ($dates as $date_str) {
$datetime = new DateTime($date_str, $timezone);
$offset = $timezone->getOffset($datetime);
$hours = $offset / 3600;
echo "时间: " . $datetime->format('Y-m-d H:i:s') . "<br>";
echo "偏移量: " . $offset . " 秒 (" . $hours . " 小时)<br>";
echo "是否为夏令时: " . ($datetime->format('I') ? '是' : '否') . "<br>";
echo "时区缩写: " . $datetime->format('T') . "<br>";
echo "<hr>";
}
// 计算夏令时切换的具体时间
$year = 2023;
$transitions = $timezone->getTransitions(
strtotime("$year-01-01"),
strtotime(($year+1) . "-01-01")
);
echo "<h4>2023年夏令时转换:</h4>";
foreach ($transitions as $transition) {
if (isset($transition['isdst'])) {
$time = date('Y-m-d H:i:s', $transition['ts']);
$isdst = $transition['isdst'] ? '是' : '否';
$abbr = $transition['abbr'];
$offset = $transition['offset'];
echo "时间: $time, 夏令时: $isdst, 缩写: $abbr, 偏移: " . ($offset/3600) . "小时<br>";
}
}
// 输出类似:
// 纽约时区的夏令时影响:
// 时间: 2023-01-15 10:30:45
// 偏移量: -18000 秒 (-5 小时)
// 是否为夏令时: 否
// 时区缩写: EST
//
// 时间: 2023-07-15 10:30:45
// 偏移量: -14400 秒 (-4 小时)
// 是否为夏令时: 是
// 时区缩写: EDT
//
// 2023年夏令时转换:
// 时间: 2023-03-12 07:00:00, 夏令时: 是, 缩写: EDT, 偏移: -4小时
// 时间: 2023-11-05 06:00:00, 夏令时: 否, 缩写: EST, 偏移: -5小时
?>
<?php
// 计算两个时区之间的时间差
function getTimezoneDifference($timezone1, $timezone2, $datetime = null) {
if ($datetime === null) {
$datetime = new DateTime('now');
}
$tz1 = new DateTimeZone($timezone1);
$tz2 = new DateTimeZone($timezone2);
$offset1 = $tz1->getOffset($datetime);
$offset2 = $tz2->getOffset($datetime);
$difference = $offset2 - $offset1; // 秒
$difference_hours = $difference / 3600;
return [
'timezone1' => $timezone1,
'timezone2' => $timezone2,
'offset1' => $offset1,
'offset2' => $offset2,
'difference' => $difference,
'difference_hours' => $difference_hours
];
}
// 测试
$datetime = new DateTime('2023-08-15 10:30:45');
$comparisons = [
['America/New_York', 'Asia/Shanghai'],
['Europe/London', 'Australia/Sydney'],
['America/Los_Angeles', 'America/New_York'],
['UTC', 'Asia/Tokyo']
];
echo "<h4>时区时间差比较:</h4>";
foreach ($comparisons as $pair) {
$result = getTimezoneDifference($pair[0], $pair[1], $datetime);
echo "<strong>" . $result['timezone1'] . " 与 " . $result['timezone2'] . ":</strong><br>";
echo "偏移量: " . ($result['offset1']/3600) . "h 与 " . ($result['offset2']/3600) . "h<br>";
echo "时差: " . $result['difference_hours'] . " 小时<br>";
if ($result['difference_hours'] > 0) {
echo $result['timezone2'] . " 比 " . $result['timezone1'] . " 快 " . abs($result['difference_hours']) . " 小时<br>";
} else {
echo $result['timezone2'] . " 比 " . $result['timezone1'] . " 慢 " . abs($result['difference_hours']) . " 小时<br>";
}
echo "<hr>";
}
// 输出类似:
// 时区时间差比较:
// America/New_York 与 Asia/Shanghai:
// 偏移量: -4h 与 8h
// 时差: 12 小时
// Asia/Shanghai 比 America/New_York 快 12 小时
//
// Europe/London 与 Australia/Sydney:
// 偏移量: 1h 与 10h
// 时差: 9 小时
// Australia/Sydney 比 Europe/London 快 9 小时
?>
<?php
// 将时间转换为不同时区
function convertTimeBetweenTimezones($time, $from_timezone, $to_timezone) {
$datetime = new DateTime($time, new DateTimeZone($from_timezone));
$datetime->setTimezone(new DateTimeZone($to_timezone));
return [
'original' => $time,
'from_timezone' => $from_timezone,
'to_timezone' => $to_timezone,
'converted' => $datetime->format('Y-m-d H:i:s'),
'offset_from' => (new DateTimeZone($from_timezone))->getOffset($datetime) / 3600,
'offset_to' => (new DateTimeZone($to_timezone))->getOffset($datetime) / 3600
];
}
// 测试
$time = '2023-08-15 10:30:45';
$conversions = [
['America/New_York', 'Asia/Shanghai'],
['Europe/London', 'America/Los_Angeles'],
['UTC', 'Australia/Sydney']
];
echo "<h4>时区时间转换:</h4>";
foreach ($conversions as $conversion) {
$result = convertTimeBetweenTimezones($time, $conversion[0], $conversion[1]);
echo "<strong>原始时间:</strong> " . $result['original'] . " (" . $result['from_timezone'] . ", UTC" .
($result['offset_from'] >= 0 ? '+' : '') . $result['offset_from'] . ")<br>";
echo "<strong>转换后:</strong> " . $result['converted'] . " (" . $result['to_timezone'] . ", UTC" .
($result['offset_to'] >= 0 ? '+' : '') . $result['offset_to'] . ")<br>";
echo "<hr>";
}
// 输出类似:
// 时区时间转换:
// 原始时间: 2023-08-15 10:30:45 (America/New_York, UTC-4)
// 转换后: 2023-08-15 22:30:45 (Asia/Shanghai, UTC+8)
//
// 原始时间: 2023-08-15 10:30:45 (Europe/London, UTC+1)
// 转换后: 2023-08-15 02:30:45 (America/Los_Angeles, UTC-7)
?>
<?php
// 查看时区偏移量的历史变化
function getTimezoneOffsetHistory($timezone, $start_year, $end_year) {
$tz = new DateTimeZone($timezone);
$history = [];
for ($year = $start_year; $year <= $end_year; $year++) {
// 检查每年的几个关键时间点
$key_dates = [
"$year-01-01 00:00:00", // 年初
"$year-07-01 00:00:00", // 年中
];
foreach ($key_dates as $date) {
$datetime = new DateTime($date, $tz);
$offset = $tz->getOffset($datetime);
$hours = $offset / 3600;
$history[] = [
'date' => $date,
'offset' => $offset,
'hours' => $hours,
'isdst' => $datetime->format('I'),
'abbr' => $datetime->format('T')
];
}
}
return $history;
}
// 获取纽约时区的历史偏移量
$history = getTimezoneOffsetHistory('America/New_York', 2018, 2023);
echo "<h4>纽约时区历史偏移量 (2018-2023):</h4>";
echo "<table border='1'>";
echo "<tr><th>日期</th><th>偏移量(小时)</th><th>夏令时</th><th>缩写</th></tr>";
foreach ($history as $record) {
echo "<tr>";
echo "<td>" . $record['date'] . "</td>";
echo "<td>" . $record['hours'] . "</td>";
echo "<td>" . ($record['isdst'] ? '是' : '否') . "</td>";
echo "<td>" . $record['abbr'] . "</td>";
echo "</tr>";
}
echo "</table>";
// 输出类似:
// 纽约时区历史偏移量 (2018-2023):
// 日期 偏移量(小时) 夏令时 缩写
// 2018-01-01 00:00:00 -5 否 EST
// 2018-07-01 00:00:00 -4 是 EDT
// 2019-01-01 00:00:00 -5 否 EST
// 2019-07-01 00:00:00 -4 是 EDT
// ... 更多
?>
<?php
// 错误处理示例
function safeGetOffset($timezone_name, $datetime_str = 'now') {
try {
$timezone = new DateTimeZone($timezone_name);
$datetime = new DateTime($datetime_str, $timezone);
$offset = $timezone->getOffset($datetime);
$hours = $offset / 3600;
return [
'success' => true,
'timezone' => $timezone_name,
'datetime' => $datetime->format('Y-m-d H:i:s'),
'offset' => $offset,
'hours' => $hours
];
} catch (Exception $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
// 测试
$test_cases = [
['timezone' => 'America/New_York', 'datetime' => '2023-08-15 10:30:45'],
['timezone' => 'Invalid/Timezone', 'datetime' => '2023-08-15 10:30:45'],
['timezone' => 'Asia/Shanghai', 'datetime' => 'invalid datetime'],
['timezone' => 'UTC', 'datetime' => 'now']
];
echo "<h4>错误处理测试:</h4>";
foreach ($test_cases as $case) {
$result = safeGetOffset($case['timezone'], $case['datetime']);
echo "<strong>测试:</strong> " . $case['timezone'] . " at " . $case['datetime'] . "<br>";
if ($result['success']) {
echo "<span style='color: green;'>✓ 成功: 偏移量 = " . $result['hours'] . " 小时</span>";
} else {
echo "<span style='color: red;'>✗ 错误: " . $result['error'] . "</span>";
}
echo "<br><br>";
}
// 输出类似:
// 错误处理测试:
// 测试: America/New_York at 2023-08-15 10:30:45
// ✓ 成功: 偏移量 = -4 小时
//
// 测试: Invalid/Timezone at 2023-08-15 10:30:45
// ✗ 错误: DateTimeZone::__construct(): Unknown or bad timezone (Invalid/Timezone)
//
// 测试: Asia/Shanghai at invalid datetime
// ✗ 错误: DateTime::__construct(): Failed to parse time string (invalid datetime) at position 0 (i): The timezone could not be found in the database
//
// 测试: UTC at now
// ✓ 成功: 偏移量 = 0 小时
?>
| 时区 | 标准时间偏移 (GMT) | 夏令时偏移 (GMT) | 使用夏令时 | 主要地区 |
|---|---|---|---|---|
| America/New_York | -5 | -4 | 是 | 纽约、华盛顿、迈阿密 |
| America/Chicago | -6 | -5 | 是 | 芝加哥、达拉斯、休斯顿 |
| America/Denver | -7 | -6 | 是 | 丹佛、凤凰城、盐湖城 |
| America/Los_Angeles | -8 | -7 | 是 | 洛杉矶、旧金山、西雅图 |
| Europe/London | 0 | +1 | 是 | 伦敦、都柏林、爱丁堡 |
| Europe/Paris | +1 | +2 | 是 | 巴黎、柏林、罗马、马德里 |
| Asia/Shanghai | +8 | +8 | 否 | 北京、上海、广州、深圳 |
| Asia/Tokyo | +9 | +9 | 否 | 东京、大阪、名古屋 |
| Australia/Sydney | +10 | +11 | 是 | 悉尼、墨尔本、布里斯班 |
| UTC | 0 | 0 | 否 | 全球标准 |
getOffset() 返回的是相对于 GMT 的偏移量,不是相对于 UTC(两者在实践中通常相同)| 场景 | 建议 |
|---|---|
| 计算时区偏移 | 总是提供具体的 DateTime 对象,以考虑夏令时 |
| 存储时间戳 | 使用 UTC 时间戳,在显示时转换为本地时区 |
| 比较不同时区时间 | 先转换为同一时区(通常是 UTC)再比较 |
| 处理用户输入 | 记录用户时区,在显示时间时进行转换 |
| 计算时间差 | 考虑时区偏移和夏令时影响 |
| 安排跨时区事件 | 明确指定时区,避免歧义 |