PHP gmdate() 函数

gmdate() 函数与 date() 函数功能相同,但返回的是格林威治标准时间(GMT,即 UTC 时间),而不是本地时间。

注意:此函数用于获取和格式化基于 UTC 时区的日期和时间,不受服务器本地时区设置的影响。

语法

gmdate(string $format, int $timestamp = time()): string

参数

参数 类型 描述
$format string 必需。日期/时间的格式字符串,与 date() 函数使用相同的格式字符
$timestamp int 可选。Unix时间戳,默认为当前时间。注意:gmdate() 会将此时间戳解释为 UTC 时间

返回值

返回格式化后的 UTC 日期时间字符串。如果时间戳参数不是有效的数字,则返回 false

常用格式字符

日期相关
Y4位年份
m2位月份
d2位日期
D星期缩写
时间相关
H24小时制小时
i分钟
s
T时区标识
特殊格式
cISO8601格式
rRFC2822格式
UUnix时间戳
Z时区偏移秒数

示例

示例 1:基本用法 - 与 date() 对比

<?php
// 设置本地时区为亚洲/上海
date_default_timezone_set('Asia/Shanghai');

// 当前时间戳
$timestamp = time();

echo "当前Unix时间戳: " . $timestamp . "\n\n";

echo "本地时间 (date()):\n";
echo "1. 完整时间: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "2. 时区标识: " . date('T', $timestamp) . "\n";
echo "3. 时区偏移: UTC" . date('P', $timestamp) . "\n";

echo "\nUTC时间 (gmdate()):\n";
echo "1. 完整时间: " . gmdate('Y-m-d H:i:s', $timestamp) . "\n";
echo "2. 时区标识: " . gmdate('T', $timestamp) . " (总是返回GMT)\n";
echo "3. 时区偏移: " . gmdate('Z', $timestamp) . " 秒 (总是返回0)\n";

// 显示时差
$localHour = date('H', $timestamp);
$utcHour = gmdate('H', $timestamp);
$hourDiff = $localHour - $utcHour;
if ($hourDiff < 0) $hourDiff += 24;

echo "\n时差分析:\n";
echo "本地时区: " . date_default_timezone_get() . "\n";
echo "本地时间: " . date('H:i', $timestamp) . "\n";
echo "UTC时间: " . gmdate('H:i', $timestamp) . "\n";
echo "时区差异: " . $hourDiff . " 小时\n";
?>
                            

输出:


当前Unix时间戳: 1703500245

本地时间 (date()):
1. 完整时间: 2023-12-25 14:30:45
2. 时区标识: CST
3. 时区偏移: UTC+08:00

UTC时间 (gmdate()):
1. 完整时间: 2023-12-25 06:30:45
2. 时区标识: GMT (总是返回GMT)
3. 时区偏移: 0 秒 (总是返回0)

时差分析:
本地时区: Asia/Shanghai
本地时间: 14:30
UTC时间: 06:30
时区差异: 8 小时
                            
示例 2:国际标准格式

<?php
$timestamp = time();

echo "国际标准时间格式 (UTC):\n\n";

// 1. ISO 8601 格式 (常用于JSON、XML)
echo "ISO 8601 格式:\n";
echo "gmdate('c'): " . gmdate('c', $timestamp) . "\n";
echo "gmdate(DateTime::ATOM): " . gmdate(DATE_ATOM, $timestamp) . "\n";

// 2. RFC 2822 格式 (常用于电子邮件)
echo "\nRFC 2822 格式:\n";
echo "gmdate('r'): " . gmdate('r', $timestamp) . "\n";
echo "gmdate(DateTime::RFC2822): " . gmdate(DATE_RFC2822, $timestamp) . "\n";

// 3. HTTP 日期格式 (常用于HTTP头)
echo "\nHTTP 日期格式:\n";
echo "RFC 822: " . gmdate(DATE_RFC822, $timestamp) . "\n";
echo "RFC 850: " . gmdate(DATE_RFC850, $timestamp) . "\n";
echo "RFC 1036: " . gmdate(DATE_RFC1036, $timestamp) . "\n";
echo "RFC 1123: " . gmdate(DATE_RFC1123, $timestamp) . "\n";

// 4. 数据库格式
echo "\n数据库格式:\n";
echo "MySQL DATETIME: " . gmdate('Y-m-d H:i:s', $timestamp) . "\n";
echo "MySQL TIMESTAMP: " . $timestamp . "\n";
echo "SQLite: " . gmdate('Y-m-d\TH:i:s', $timestamp) . "\n";

// 5. 特殊用途格式
echo "\n特殊用途格式:\n";
echo "文件名安全: " . gmdate('Y-m-d_His', $timestamp) . "\n";
echo "日志格式: " . gmdate('[d/M/Y:H:i:s +0000]', $timestamp) . "\n";
echo "API时间戳: " . gmdate('Y-m-d\TH:i:s\Z', $timestamp) . "\n";

// 6. 演示时区独立性
echo "\n时区独立性演示:\n";
date_default_timezone_set('America/New_York');
echo "纽约时间: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "UTC时间: " . gmdate('Y-m-d H:i:s', $timestamp) . " (保持不变)\n";

date_default_timezone_set('Europe/London');
echo "伦敦时间: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "UTC时间: " . gmdate('Y-m-d H:i:s', $timestamp) . " (保持不变)\n";
?>
                            

输出:


国际标准时间格式 (UTC):

ISO 8601 格式:
gmdate('c'): 2023-12-25T06:30:45+00:00
gmdate(DateTime::ATOM): 2023-12-25T06:30:45+00:00

RFC 2822 格式:
gmdate('r'): Mon, 25 Dec 2023 06:30:45 +0000
gmdate(DateTime::RFC2822): Mon, 25 Dec 2023 06:30:45 +0000

HTTP 日期格式:
RFC 822: Mon, 25 Dec 23 06:30:45 +0000
RFC 850: Monday, 25-Dec-23 06:30:45 GMT
RFC 1036: Mon, 25 Dec 23 06:30:45 +0000
RFC 1123: Mon, 25 Dec 2023 06:30:45 +0000

数据库格式:
MySQL DATETIME: 2023-12-25 06:30:45
MySQL TIMESTAMP: 1703500245
SQLite: 2023-12-25T06:30:45

特殊用途格式:
文件名安全: 2023-12-25_063045
日志格式: [25/Dec/2023:06:30:45 +0000]
API时间戳: 2023-12-25T06:30:45Z

时区独立性演示:
纽约时间: 2023-12-25 01:30:45
UTC时间: 2023-12-25 06:30:45 (保持不变)
伦敦时间: 2023-12-25 06:30:45
UTC时间: 2023-12-25 06:30:45 (保持不变)
                            
示例 3:实际应用 - API服务和国际日志系统

<?php
/**
 * REST API响应类 - 使用UTC时间
 */
class RestApiResponse {

    /**
     * 生成API响应
     */
    public static function jsonResponse($data, $statusCode = 200, $message = 'success'): string {
        $response = [
            'status' => $statusCode,
            'message' => $message,
            'data' => $data,
            'timestamp' => gmdate('Y-m-d\TH:i:s\Z'), // 使用UTC时间戳
            'server_time' => time()
        ];

        header('Content-Type: application/json');
        header('Date: ' . gmdate(DATE_RFC1123));
        http_response_code($statusCode);

        return json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    }

    /**
     * 生成缓存控制头
     */
    public static function cacheHeaders($maxAge = 3600): void {
        $expires = gmdate(DATE_RFC1123, time() + $maxAge);
        header('Cache-Control: public, max-age=' . $maxAge);
        header('Expires: ' . $expires);
        header('Last-Modified: ' . gmdate(DATE_RFC1123));
    }
}

/**
 * 国际日志系统 - 使用UTC时间记录
 */
class InternationalLogger {
    private $logFile;

    public function __construct($logFile) {
        $this->logFile = $logFile;
    }

    /**
     * 记录UTC时间日志
     */
    public function log($level, $message, $context = []) {
        $logEntry = [
            'time' => gmdate('Y-m-d H:i:s'),  // UTC时间
            'timestamp' => time(),
            'level' => strtoupper($level),
            'message' => $message,
            'context' => $context,
            'timezone' => 'UTC'
        ];

        $logLine = json_encode($logEntry, JSON_UNESCAPED_UNICODE) . PHP_EOL;
        file_put_contents($this->logFile, $logLine, FILE_APPEND);
    }

    /**
     * 读取并分析日志(按UTC时间)
     */
    public function analyzeLogs($startTime = null, $endTime = null) {
        $logs = file($this->logFile, FILE_IGNORE_NEW_LINES);
        $analysis = [
            'total' => 0,
            'by_level' => [],
            'by_hour' => [],
            'errors' => []
        ];

        foreach ($logs as $log) {
            $entry = json_decode($log, true);
            $analysis['total']++;

            // 按日志级别统计
            $level = $entry['level'];
            $analysis['by_level'][$level] = ($analysis['by_level'][$level] ?? 0) + 1;

            // 按UTC小时统计
            $hour = substr($entry['time'], 11, 2);
            $analysis['by_hour'][$hour] = ($analysis['by_hour'][$hour] ?? 0) + 1;

            // 收集错误
            if ($level === 'ERROR') {
                $analysis['errors'][] = $entry;
            }
        }

        return $analysis;
    }
}

/**
 * 时间转换工具
 */
class TimeConverter {

    /**
     * 本地时间转UTC
     */
    public static function localToUTC($localTime, $timezone) {
        $date = new DateTime($localTime, new DateTimeZone($timezone));
        $date->setTimezone(new DateTimeZone('UTC'));
        return $date->format('Y-m-d H:i:s');
    }

    /**
     * UTC转本地时间
     */
    public static function utcToLocal($utcTime, $timezone) {
        $date = new DateTime($utcTime, new DateTimeZone('UTC'));
        $date->setTimezone(new DateTimeZone($timezone));
        return $date->format('Y-m-d H:i:s');
    }

    /**
     * 计算时区偏移
     */
    public static function getTimezoneOffset($timezone) {
        $date = new DateTime('now', new DateTimeZone($timezone));
        return $date->getOffset() / 3600; // 返回小时数
    }
}

// 使用示例
echo "API服务和国际日志系统演示\n\n";

// 1. API响应演示
echo "1. API响应示例:\n";
$apiData = [
    'user' => [
        'id' => 123,
        'name' => '张三',
        'email' => 'zhangsan@example.com'
    ],
    'permissions' => ['read', 'write']
];

echo RestApiResponse::jsonResponse($apiData, 200);
echo "\n\n";

// 2. 日志系统演示
echo "2. 日志系统演示:\n";
$logger = new InternationalLogger('app.log');

// 记录一些日志
$logger->log('INFO', '用户登录', ['user_id' => 123, 'ip' => '192.168.1.1']);
$logger->log('WARNING', 'API调用频繁', ['api' => '/users', 'count' => 150]);
$logger->log('ERROR', '数据库连接失败', ['error_code' => 1001, 'retry' => 3]);

// 分析日志
$analysis = $logger->analyzeLogs();
echo "日志分析结果:\n";
echo "总日志数: " . $analysis['total'] . "\n";
echo "按级别统计: " . json_encode($analysis['by_level'], JSON_UNESCAPED_UNICODE) . "\n";
echo "按小时统计(UTC): " . json_encode($analysis['by_hour'], JSON_UNESCAPED_UNICODE) . "\n\n";

// 3. 时间转换演示
echo "3. 时间转换演示:\n";
$localTime = '2023-12-25 14:30:45';

echo "原始时间: " . $localTime . "\n";
echo "北京到UTC: " . TimeConverter::localToUTC($localTime, 'Asia/Shanghai') . "\n";
echo "纽约到UTC: " . TimeConverter::localToUTC($localTime, 'America/New_York') . "\n";
echo "伦敦到UTC: " . TimeConverter::localToUTC($localTime, 'Europe/London') . "\n\n";

$utcTime = '2023-12-25 06:30:45';
echo "UTC时间: " . $utcTime . "\n";
echo "UTC到北京: " . TimeConverter::utcToLocal($utcTime, 'Asia/Shanghai') . "\n";
echo "UTC到纽约: " . TimeConverter::utcToLocal($utcTime, 'America/New_York') . "\n";
echo "UTC到伦敦: " . TimeConverter::utcToLocal($utcTime, 'Europe/London') . "\n\n";

// 4. HTTP头生成示例
echo "4. HTTP头生成:\n";
echo "Date头: " . gmdate(DATE_RFC1123) . "\n";
echo "Expires头 (1小时后): " . gmdate(DATE_RFC1123, time() + 3600) . "\n";
echo "Last-Modified头: " . gmdate(DATE_RFC1123, filemtime(__FILE__)) . "\n";

// 5. 文件命名示例
echo "\n5. 文件命名示例:\n";
$filename = 'backup_' . gmdate('Ymd_His') . '.sql';
echo "备份文件名: " . $filename . "\n";
?>
                            

输出:


API服务和国际日志系统演示

1. API响应示例:
{
    "status": 200,
    "message": "success",
    "data": {
        "user": {
            "id": 123,
            "name": "张三",
            "email": "zhangsan@example.com"
        },
        "permissions": ["read", "write"]
    },
    "timestamp": "2023-12-25T06:30:45Z",
    "server_time": 1703500245
}

2. 日志系统演示:
日志分析结果:
总日志数: 3
按级别统计: {"INFO":1,"WARNING":1,"ERROR":1}
按小时统计(UTC): {"06":3}

3. 时间转换演示:
原始时间: 2023-12-25 14:30:45
北京到UTC: 2023-12-25 06:30:45
纽约到UTC: 2023-12-25 19:30:45
伦敦到UTC: 2023-12-25 14:30:45

UTC时间: 2023-12-25 06:30:45
UTC到北京: 2023-12-25 14:30:45
UTC到纽约: 2023-12-25 01:30:45
UTC到伦敦: 2023-12-25 06:30:45

4. HTTP头生成:
Date头: Mon, 25 Dec 2023 06:30:45 GMT
Expires头 (1小时后): Mon, 25 Dec 2023 07:30:45 GMT
Last-Modified头: Mon, 25 Dec 2023 06:30:45 GMT

5. 文件命名示例:
备份文件名: backup_20231225_063045.sql
                            
gmdate() 与 date() 详细对比
特性 gmdate() date()
时区基准 格林威治标准时间 (UTC/GMT) 服务器本地时区
时区影响 不受 date_default_timezone_set() 影响 date_default_timezone_set() 影响
返回值 'T' 总是返回 "GMT" 返回本地时区缩写
返回值 'Z' 总是返回 0 返回本地时区偏移秒数
时间戳解释 将时间戳解释为 UTC 时间 将时间戳解释为本地时间
适用场景 国际应用、API、日志、科学计算 本地化应用、用户界面显示
HTTP头 适合生成 HTTP 日期头 不适合 HTTP 头(除非服务器在 UTC)
重要:对于同一时间戳,gmdate()date() 返回的小时数会相差本地时区与 UTC 的时差。

<?php
// 示例:显示时差如何影响输出
date_default_timezone_set('Asia/Shanghai');
$timestamp = 1703500245; // 2023-12-25 06:30:45 UTC

echo "时间戳: " . $timestamp . "\n";
echo "UTC时间: " . gmdate('Y-m-d H:i:s', $timestamp) . "\n";
echo "北京时间: " . date('Y-m-d H:i:s', $timestamp) . "\n";

// 时差计算
$utcHour = gmdate('H', $timestamp);
$localHour = date('H', $timestamp);
echo "\n小时对比: UTC {$utcHour}:00 vs 北京时间 {$localHour}:00\n";
echo "时差: " . ($localHour - $utcHour) . " 小时\n";
?>
                            
时区和时间标准
重要时间标准
  • UTC (协调世界时): 国际时间标准,基于原子钟
  • GMT (格林威治标准时间): 基于地球自转,与UTC基本一致
  • Unix时间戳: 从1970-01-01 00:00:00 UTC开始的秒数
常见时区
  • UTC+8: 中国标准时间 (CST)
  • UTC+0: 格林威治时间 (GMT)
  • UTC-5: 美国东部时间 (EST)
  • UTC+9: 日本标准时间 (JST)
最佳实践:在数据库、API、日志中存储和使用 UTC 时间,只在用户界面显示时转换为本地时间。
常见错误和注意事项
1. 混淆gmdate()和date()

<?php
// 错误:期望本地时间却用了gmdate
date_default_timezone_set('Asia/Shanghai');
echo "现在时间: " . gmdate('Y-m-d H:i:s') . " (错误!这是UTC时间)\n";

// 正确:明确知道自己在获取UTC时间
echo "UTC时间: " . gmdate('Y-m-d H:i:s') . "\n";
echo "北京时间: " . date('Y-m-d H:i:s') . "\n";

// 正确:在需要UTC时间的地方使用gmdate
echo "HTTP Date头: " . gmdate(DATE_RFC1123) . "\n";
?>
                            
2. 时间戳的双重解释

<?php
// 错误:对同一时间戳使用不同函数期望相同时间
$timestamp = strtotime('2023-12-25 14:30:45'); // 本地时间的时间戳

echo "错误理解:\n";
echo "date()输出: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "gmdate()输出: " . gmdate('Y-m-d H:i:s', $timestamp) . "\n";
echo "(注意:这两个输出表示不同的时间点)\n\n";

// 正确:理解时间戳的本质
echo "正确理解:\n";
echo "时间戳 " . $timestamp . " 表示:\n";
echo "- 在本地时区中: " . date('Y-m-d H:i:s', $timestamp) . "\n";
echo "- 在UTC时区中: " . gmdate('Y-m-d H:i:s', $timestamp) . "\n";
?>
                            
3. 数据库时间处理

<?php
// 错误:将本地时间存入数据库
$localTime = date('Y-m-d H:i:s');
// INSERT INTO logs (time) VALUES ('$localTime'); // 不好,包含时区信息

// 正确:存储UTC时间
$utcTime = gmdate('Y-m-d H:i:s');
// INSERT INTO logs (time) VALUES ('$utcTime'); // 好,时区明确

// 正确:使用UNIX时间戳
$timestamp = time();
// INSERT INTO logs (timestamp) VALUES ($timestamp); // 最好,时区无关

echo "存储时间的最佳实践:\n";
echo "1. UNIX时间戳: " . $timestamp . "\n";
echo "2. UTC时间字符串: " . $utcTime . "\n";
echo "3. 带时区的时间: " . date('c') . "\n";
?>
                            

注意事项

  • 时区一致性:在分布式系统中,始终使用 UTC 时间可以避免时区混淆问题。
  • 夏令时:gmdate() 不受夏令时影响,而 date() 可能会受影响。
  • HTTP标准:HTTP协议要求 Date 头使用 RFC 1123 格式的 GMT 时间。
  • 数据库存储:推荐在数据库中存储 UNIX 时间戳或 UTC 时间字符串。
  • API设计:REST API 应返回 ISO 8601 格式的 UTC 时间(带 'Z' 后缀)。
  • 日志记录:多服务器环境中的日志应使用 UTC 时间以便统一分析。
  • 时间戳参数:传递给 gmdate() 的时间戳被解释为 UTC 时间,这与 date() 不同。
  • 性能考虑:gmdate()date() 的性能差异通常可以忽略不计。

相关函数

date()

格式化本地时间/日期

time()

返回当前的Unix时间戳

strtotime()

将英文文本日期时间解析为Unix时间戳

gmmktime()

取得 GMT 日期的 UNIX 时间戳

DateTime()

面向对象的日期时间处理

date_default_timezone_set()

设置脚本中所有日期/时间函数使用的默认时区