PHP timezone_transitions_get()函数

timezone_transitions_get() 函数返回时区的所有转换信息,包括夏令时的开始和结束时间、偏移量变化等。这个函数是 DateTimeZone 类的方法。

注意:这不是一个独立的函数,而是 DateTimeZone 对象的实例方法,需要通过 DateTimeZone 对象调用。

语法

DateTimeZone::getTransitions([int $timestampBegin [, int $timestampEnd]]) : array|false

参数说明

参数 默认值 描述
timestampBegin null

可选。 开始时间戳。从该时间戳开始获取时区转换信息。

如果未提供,则返回所有可用转换信息。

timestampEnd null

可选。 结束时间戳。获取到该时间戳为止的转换信息。

如果只提供开始时间戳,则返回从开始时间戳到未来的转换信息。

返回值

返回一个索引数组,每个元素是一个关联数组,包含转换信息。如果失败则返回 false

返回数组的结构

键名 描述 示例
ts 转换发生的时间戳(Unix 时间戳) 1678838400
time ISO 8601 格式的日期时间字符串 2023-03-12T07:00:00+00:00
offset 与 UTC 的偏移量(秒) -14400, 3600
isdst 是否启用夏令时(1=是,0=否) 1, 0
abbr 时区缩写 EDT, EST, BST

示例

示例 1:基本用法 - 获取所有转换

<?php
// 创建 DateTimeZone 对象
$timezone = new DateTimeZone('America/New_York');

// 获取所有时区转换信息
$transitions = $timezone->getTransitions();

echo "<h4>纽约时区转换信息(前5个):</h4>";
echo "<pre>";
$count = 0;
foreach ($transitions as $transition) {
    if ($count++ >= 5) break; // 只显示前5个
    print_r($transition);
    echo "\n";
}
echo "</pre>";
echo "总转换数: " . count($transitions);

// 输出类似:
// 纽约时区转换信息(前5个):
// Array
// (
//     [ts] => -9223372036854775808
//     [time] => -292277022657-01-27T08:29:52+00:00
//     [offset] => -17762
//     [isdst] => 0
//     [abbr] => LMT
// )
// Array
// (
//     [ts] => -2717650800
//     [time] => 1883-11-18T12:03:00+00:00
//     [offset] => -18000
//     [isdst] => 0
//     [abbr] => EST
// )
// ... 更多
// 总转换数: 241
?>

示例 2:获取指定时间范围的转换

<?php
// 获取指定时间范围的转换
$timezone = new DateTimeZone('America/New_York');

// 获取2023年的转换
$start_2023 = strtotime('2023-01-01');
$end_2023 = strtotime('2023-12-31 23:59:59');

$transitions_2023 = $timezone->getTransitions($start_2023, $end_2023);

echo "<h4>纽约时区2023年转换信息:</h4>";
if (!empty($transitions_2023)) {
    echo "<table border='1'>";
    echo "<tr><th>时间</th><th>偏移量(小时)</th><th>夏令时</th><th>缩写</th></tr>";

    foreach ($transitions_2023 as $transition) {
        $time = date('Y-m-d H:i:s', $transition['ts']);
        $offset_hours = $transition['offset'] / 3600;
        $isdst = $transition['isdst'] ? '是' : '否';

        echo "<tr>";
        echo "<td>" . $time . "</td>";
        echo "<td>UTC" . ($offset_hours >= 0 ? '+' : '') . $offset_hours . "</td>";
        echo "<td>" . $isdst . "</td>";
        echo "<td>" . $transition['abbr'] . "</td>";
        echo "</tr>";
    }
    echo "</table>";
} else {
    echo "在指定时间范围内没有转换";
}

// 输出类似:
// 纽约时区2023年转换信息:
// 时间                    偏移量(小时)  夏令时  缩写
// 2023-03-12 07:00:00     UTC-4        是      EDT
// 2023-11-05 06:00:00     UTC-5        否      EST
?>

示例 3:分析时区转换模式

<?php
// 分析时区转换模式
function analyzeTimezoneTransitions($timezone_name, $year) {
    $timezone = new DateTimeZone($timezone_name);

    $start = strtotime("$year-01-01");
    $end = strtotime(($year+1) . "-01-01") - 1;

    $transitions = $timezone->getTransitions($start, $end);

    $analysis = [
        'timezone' => $timezone_name,
        'year' => $year,
        'transition_count' => count($transitions),
        'transitions' => [],
        'has_dst' => false,
        'dst_periods' => []
    ];

    foreach ($transitions as $transition) {
        $analysis['transitions'][] = [
            'timestamp' => $transition['ts'],
            'time' => date('Y-m-d H:i:s', $transition['ts']),
            'offset' => $transition['offset'],
            'offset_hours' => $transition['offset'] / 3600,
            'isdst' => $transition['isdst'],
            'abbr' => $transition['abbr']
        ];

        if ($transition['isdst']) {
            $analysis['has_dst'] = true;
        }
    }

    return $analysis;
}

// 分析几个时区
$timezones = ['America/New_York', 'Europe/London', 'Australia/Sydney', 'Asia/Shanghai'];

echo "<h4>2023年时区转换分析:</h4>";
foreach ($timezones as $tz) {
    $analysis = analyzeTimezoneTransitions($tz, 2023);

    echo "<h5>" . $tz . "</h5>";
    echo "转换次数: " . $analysis['transition_count'] . "<br>";
    echo "有夏令时: " . ($analysis['has_dst'] ? '是' : '否') . "<br>";

    if (!empty($analysis['transitions'])) {
        echo "<small>转换详情:</small><br>";
        foreach ($analysis['transitions'] as $t) {
            echo "  - " . $t['time'] . " (" . $t['abbr'] . ", UTC" .
                 ($t['offset_hours'] >= 0 ? '+' : '') . $t['offset_hours'] . ")" . "<br>";
        }
    }
    echo "<hr>";
}

// 输出类似:
// 2023年时区转换分析:
// America/New_York
// 转换次数: 2
// 有夏令时: 是
// 转换详情:
//   - 2023-03-12 07:00:00 (EDT, UTC-4)
//   - 2023-11-05 06:00:00 (EST, UTC-5)
//
// Europe/London
// 转换次数: 2
// 有夏令时: 是
// 转换详情:
//   - 2023-03-26 01:00:00 (BST, UTC+1)
//   - 2023-10-29 01:00:00 (GMT, UTC+0)
//
// Australia/Sydney
// 转换次数: 2
// 有夏令时: 是
// 转换详情:
//   - 2023-10-01 16:00:00 (AEDT, UTC+11)
//   - 2023-04-02 16:00:00 (AEST, UTC+10)
//
// Asia/Shanghai
// 转换次数: 0
// 有夏令时: 否
?>

示例 4:查找特定时间的时区信息

<?php
// 查找特定时间的时区信息
function getTimezoneInfoAtTime($timezone_name, $timestamp) {
    $timezone = new DateTimeZone($timezone_name);

    // 获取包含该时间戳的转换
    $transitions = $timezone->getTransitions($timestamp, $timestamp);

    if (empty($transitions)) {
        // 如果没有转换,获取前一个转换
        $all_transitions = $timezone->getTransitions($timestamp - 86400 * 365, $timestamp);
        if (empty($all_transitions)) {
            return "无法获取时区信息";
        }
        $transition = end($all_transitions);
    } else {
        $transition = $transitions[0];
    }

    return [
        'timestamp' => $timestamp,
        'time' => date('Y-m-d H:i:s', $timestamp),
        'offset' => $transition['offset'],
        'offset_hours' => $transition['offset'] / 3600,
        'isdst' => $transition['isdst'],
        'abbr' => $transition['abbr']
    ];
}

// 测试不同时间
$timezone = 'America/New_York';
$test_times = [
    '2023-01-15 10:30:45',  // 冬季,非夏令时
    '2023-07-15 10:30:45',  // 夏季,夏令时
    '2023-03-12 01:30:45',  // 夏令时开始前
    '2023-03-12 08:30:45',  // 夏令时开始后
    '2023-11-05 00:30:45',  // 夏令时结束前
    '2023-11-05 08:30:45'   // 夏令时结束后
];

echo "<h4>纽约时区在不同时间的偏移量:</h4>";
foreach ($test_times as $time_str) {
    $timestamp = strtotime($time_str);
    $info = getTimezoneInfoAtTime($timezone, $timestamp);

    if (is_array($info)) {
        echo "<strong>" . $time_str . ":</strong><br>";
        echo "时区缩写: " . $info['abbr'] . "<br>";
        echo "偏移量: UTC" . ($info['offset_hours'] >= 0 ? '+' : '') . $info['offset_hours'] . "<br>";
        echo "夏令时: " . ($info['isdst'] ? '是' : '否') . "<br>";
        echo "<hr>";
    } else {
        echo "<strong>" . $time_str . ":</strong> " . $info . "<br>";
    }
}

// 输出类似:
// 纽约时区在不同时间的偏移量:
// 2023-01-15 10:30:45:
// 时区缩写: EST
// 偏移量: UTC-5
// 夏令时: 否
//
// 2023-07-15 10:30:45:
// 时区缩写: EDT
// 偏移量: UTC-4
// 夏令时: 是
//
// 2023-03-12 01:30:45:
// 时区缩写: EST
// 偏移量: UTC-5
// 夏令时: 否
//
// 2023-03-12 08:30:45:
// 时区缩写: EDT
// 偏移量: UTC-4
// 夏令时: 是
?>

示例 5:比较不同时区的转换

<?php
// 比较不同时区的转换
function compareTimezoneTransitions($timezone1, $timezone2, $year) {
    $tz1 = new DateTimeZone($timezone1);
    $tz2 = new DateTimeZone($timezone2);

    $start = strtotime("$year-01-01");
    $end = strtotime(($year+1) . "-01-01") - 1;

    $transitions1 = $tz1->getTransitions($start, $end);
    $transitions2 = $tz2->getTransitions($start, $end);

    $comparison = [
        'year' => $year,
        'timezone1' => $timezone1,
        'timezone2' => $timezone2,
        'transitions1' => count($transitions1),
        'transitions2' => count($transitions2),
        'details' => []
    ];

    // 合并并排序所有转换
    $all_transitions = [];
    foreach ($transitions1 as $t) {
        $t['timezone'] = $timezone1;
        $all_transitions[] = $t;
    }
    foreach ($transitions2 as $t) {
        $t['timezone'] = $timezone2;
        $all_transitions[] = $t;
    }

    // 按时间戳排序
    usort($all_transitions, function($a, $b) {
        return $a['ts'] - $b['ts'];
    });

    $comparison['all_transitions'] = $all_transitions;
    return $comparison;
}

// 比较纽约和伦敦的转换
$comparison = compareTimezoneTransitions('America/New_York', 'Europe/London', 2023);

echo "<h4>2023年纽约 vs 伦敦时区转换比较:</h4>";
echo "纽约转换次数: " . $comparison['transitions1'] . "<br>";
echo "伦敦转换次数: " . $comparison['transitions2'] . "<br><br>";

echo "<table border='1'>";
echo "<tr><th>时间</th><th>时区</th><th>缩写</th><th>偏移量</th><th>夏令时</th></tr>";

foreach ($comparison['all_transitions'] as $transition) {
    $time = date('Y-m-d H:i:s', $transition['ts']);
    $offset_hours = $transition['offset'] / 3600;
    $isdst = $transition['isdst'] ? '是' : '否';

    echo "<tr>";
    echo "<td>" . $time . "</td>";
    echo "<td>" . $transition['timezone'] . "</td>";
    echo "<td>" . $transition['abbr'] . "</td>";
    echo "<td>UTC" . ($offset_hours >= 0 ? '+' : '') . $offset_hours . "</td>";
    echo "<td>" . $isdst . "</td>";
    echo "</tr>";
}
echo "</table>";

// 输出类似:
// 2023年纽约 vs 伦敦时区转换比较:
// 纽约转换次数: 2
// 伦敦转换次数: 2
//
// 时间                    时区               缩写  偏移量  夏令时
// 2023-03-12 07:00:00    America/New_York   EDT  UTC-4   是
// 2023-03-26 01:00:00    Europe/London      BST  UTC+1   是
// 2023-10-29 01:00:00    Europe/London      GMT  UTC+0   否
// 2023-11-05 06:00:00    America/New_York   EST  UTC-5   否
?>

示例 6:错误处理

<?php
// 错误处理示例
function safeGetTransitions($timezone_name, $start = null, $end = null) {
    try {
        $timezone = new DateTimeZone($timezone_name);

        if ($start === null && $end === null) {
            $transitions = $timezone->getTransitions();
        } else if ($end === null) {
            $transitions = $timezone->getTransitions($start);
        } else {
            $transitions = $timezone->getTransitions($start, $end);
        }

        if ($transitions === false) {
            return ['error' => '获取转换信息失败'];
        }

        return ['success' => true, 'transitions' => $transitions];
    } catch (Exception $e) {
        return ['error' => $e->getMessage()];
    }
}

// 测试
$test_cases = [
    ['timezone' => 'America/New_York', 'start' => strtotime('2023-01-01'), 'end' => strtotime('2023-12-31')],
    ['timezone' => 'Invalid/Timezone', 'start' => null, 'end' => null],
    ['timezone' => 'UTC', 'start' => strtotime('2023-01-01'), 'end' => strtotime('2023-12-31')],
    ['timezone' => 'Asia/Shanghai', 'start' => null, 'end' => null]
];

echo "<h4>时区转换获取测试:</h4>";
foreach ($test_cases as $case) {
    $result = safeGetTransitions($case['timezone'], $case['start'], $case['end']);

    echo "<strong>测试:</strong> " . $case['timezone'];
    if ($case['start'] !== null) {
        echo " (" . date('Y-m-d', $case['start']) . " 到 " . date('Y-m-d', $case['end']) . ")";
    }
    echo "<br>";

    if (isset($result['success'])) {
        echo "<span style='color: green;'>✓ 成功: 找到 " . count($result['transitions']) . " 个转换</span>";
    } else {
        echo "<span style='color: red;'>✗ 错误: " . $result['error'] . "</span>";
    }
    echo "<br><br>";
}

// 输出类似:
// 时区转换获取测试:
// 测试: America/New_York (2023-01-01 到 2023-12-31)
// ✓ 成功: 找到 2 个转换
//
// 测试: Invalid/Timezone
// ✗ 错误: DateTimeZone::__construct(): Unknown or bad timezone (Invalid/Timezone)
//
// 测试: UTC (2023-01-01 到 2023-12-31)
// ✓ 成功: 找到 0 个转换
//
// 测试: Asia/Shanghai
// ✓ 成功: 找到 241 个转换
?>

示例 7:创建时区转换可视化

<?php
// 创建时区转换可视化
function visualizeTimezoneTransitions($timezone_name, $year) {
    $timezone = new DateTimeZone($timezone_name);
    $start = strtotime("$year-01-01");
    $end = strtotime(($year+1) . "-01-01") - 1;

    $transitions = $timezone->getTransitions($start, $end);

    if (empty($transitions)) {
        return "<div class='no-transitions'>{$timezone_name} 在 {$year} 年没有时区转换</div>";
    }

    $html = "<div class='timezone-visualization'>";
    $html .= "<h4>{$timezone_name} - {$year} 年时区转换</h4>";
    $html .= "<div class='timeline'>";

    // 创建时间线
    $months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
    foreach ($months as $month) {
        $html .= "<div class='month'>{$month}</div>";
    }

    $html .= "</div>";

    // 添加转换标记
    foreach ($transitions as $transition) {
        $date = date('n', $transition['ts']); // 月份 (1-12)
        $day = date('j', $transition['ts']);  // 日
        $offset_hours = $transition['offset'] / 3600;
        $isdst = $transition['isdst'];
        $abbr = $transition['abbr'];

        $left = (($date - 1) * 8.33) + (($day - 1) * 0.28); // 简化计算

        $html .= "<div class='transition-marker' style='left: {$left}%;'>";
        $html .= "<div class='marker-dot'></div>";
        $html .= "<div class='marker-info'>";
        $html .= date('Y-m-d H:i', $transition['ts']) . "<br>";
        $html .= "{$abbr} (UTC" . ($offset_hours >= 0 ? '+' : '') . "{$offset_hours})<br>";
        $html .= "夏令时: " . ($isdst ? '是' : '否');
        $html .= "</div>";
        $html .= "</div>";
    }

    $html .= "</div>";

    return $html;
}

// 添加CSS样式
echo "<style>
.timezone-visualization {
    position: relative;
    margin: 20px 0;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 5px;
    background: #f9f9f9;
}
.timeline {
    display: flex;
    justify-content: space-between;
    margin-bottom: 40px;
    padding: 10px;
    background: #fff;
    border: 1px solid #ddd;
}
.month {
    flex: 1;
    text-align: center;
    font-size: 12px;
    color: #666;
}
.transition-marker {
    position: absolute;
    top: 60px;
    width: 5px;
}
.marker-dot {
    width: 10px;
    height: 10px;
    background: #e74c3c;
    border-radius: 50%;
    margin: 0 auto 5px;
}
.marker-info {
    position: absolute;
    top: 15px;
    left: 50%;
    transform: translateX(-50%);
    width: 150px;
    padding: 5px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 3px;
    font-size: 11px;
    text-align: center;
    display: none;
}
.transition-marker:hover .marker-info {
    display: block;
}
.no-transitions {
    padding: 20px;
    text-align: center;
    color: #666;
    font-style: italic;
}
</style>";

// 可视化几个时区
$timezones_to_visualize = ['America/New_York', 'Europe/London', 'Australia/Sydney'];

echo "<h4>时区转换可视化 (2023年):</h4>";
foreach ($timezones_to_visualize as $tz) {
    echo visualizeTimezoneTransitions($tz, 2023);
    echo "<br>";
}

// 输出HTML可视化
?>

常见时区转换模式

时区 转换次数/年 转换月份 标准时间偏移 夏令时偏移
America/New_York 2 3月, 11月 UTC-5 UTC-4
Europe/London 2 3月, 10月 UTC+0 UTC+1
Australia/Sydney 2 4月, 10月 UTC+10 UTC+11
Asia/Shanghai 0 - UTC+8 -
America/Phoenix 0 - UTC-7 -
Europe/Moscow 0 - UTC+3 -

注意事项

  • getTransitions() 返回的转换信息可能非常多,特别是对于有历史时区变化的地区
  • 某些时区(如 UTC、Asia/Shanghai)没有转换,函数可能返回空数组或只包含初始转换
  • 转换时间戳是基于 UTC 的,可能需要转换为本地时间显示
  • 时区转换规则可能随时间变化,历史数据可能不完整
  • 处理大量转换数据时要注意性能,考虑使用时间范围限制
  • 时区缩写(abbr)可能因历史时期而异

最佳实践

场景 建议
获取当前转换 使用 getTransitions(time(), time()) 获取当前转换信息
处理大量数据 总是使用时间范围参数限制返回的数据量
显示给用户 将时间戳转换为用户本地时间,使用友好的日期格式
缓存转换数据 时区转换不常变化,可以缓存结果提高性能
处理历史日期 注意时区规则的历史变化,特别是夏令时规则的改变
比较不同时区 将时间统一转换为 UTC 后再进行比较

相关函数和类