• 288阅读
  • 3回复

关于global.php时区设置和date()函数、gmdate()函数 [复制链接] [手机版]

上一主题 下一主题
在线zhangjingyu

只看楼主 正序阅读 使用道具 红 蓝 绿 紫 粉 黑 楼主  发表于: 2026-08-09 19:31:49 星期日
有时候,在格式化时间的时候发现,显示的并不是北京时间,而是0区的格林威治时间。这时候,通常要加一行指定时区的代码:date_default_timezone_set('Asia/Shanghai');但这行代码放的位置有讲究:如果有调用global.php文件的代码,一定要放在它的后面。

global.php文件:
  1. function_exists('date_default_timezone_set') && date_default_timezone_set('Etc/GMT+0');

加了8个小时后可以了。那为什么之前直接加这一行就可以:date_default_timezone_set('Asia/Shanghai');今天这个文件不对呢
好问题!关键在于 global.php 里面可能已经设置了时区,而且设置的是 UTC 或者 Europe/London 等,date_default_timezone_set('Asia/Shanghai') 被 global.php 里的设置覆盖了!

原因分析:
PHP 中 date_default_timezone_set() 的行为是:
后调用的覆盖先调用的
如果在代码后面又调用了 date_default_timezone_set(),会重新设置时区

所以,建议:
在 require_once('../global.php') 之后,立即添加:
date_default_timezone_set('Asia/Shanghai');
这样就能确保最终使用的是北京时间,不会被 global.php 覆盖。
你的文件执行流程:
1. date_default_timezone_set('Asia/Shanghai');  // 设置北京时间
2. require_once('../global.php');              // 引入 global.php
   └─ global.php 内部:date_default_timezone_set('UTC'); // 覆盖为 UTC
3. 显示时间时用的是 UTC,差8小时 ❌

修正后:
1. require_once('../global.php');              // 引入 global.php
   └─ global.php 内部:date_default_timezone_set('UTC');
2. date_default_timezone_set('Asia/Shanghai'); // 重新设置北京时间,覆盖 UTC
3. 显示时间时用的是北京时间 ✅
尊重每位祺师,做有价值的祺文化社区!欢迎光临,并感谢您的支持与陪伴!
我希望能通过这个论坛让更多的朋友更多的关爱自己的家人和朋友,不要等到有一天失去后才知道没有好好的珍惜,才知道
拥有的珍贵!亲爱的们,如果你懂得,请把这份关爱传递,让更多的人加入到爱心接力当中,让每个人的心中都洋溢着爱的温馨!

我们应该知道:岁月如梭!其实生命,是很短暂,也是很脆弱的东西…… 设置自己的帖子签名请点这里!
在线zhangjingyu

只看该作者 地板  发表于: 2026-08-09 21:37:11 星期日  点亮(0)
gmdate() 的本质
gmdate() 不是"绝对的日期/时间",而是 "始终按 UTC 时区格式化"。
正确理解
// gmdate() = date() 但强制使用 UTC 时区
gmdate('Y-m-d H:i:s', $timestamp);
// 等价于:
date_default_timezone_set('UTC');
echo date('Y-m-d H:i:s', $timestamp);

关键区别
函数行为是否受时区影响
date()按当前 PHP 时区格式化✅ 是
gmdate()按 UTC 时区格式化(忽略当前设置)❌ 否(固定 UTC)
$timestamp = 1785851856;  // 2026-08-04 13:57:36 UTC

// 场景1:PHP 时区 = Asia/Shanghai
date_default_timezone_set('Asia/Shanghai');
echo date('Y-m-d H:i:s', $timestamp);   // 2026-08-04 21:57:36 (北京时间)
echo gmdate('Y-m-d H:i:s', $timestamp); // 2026-08-04 13:57:36 (UTC) ← 不受影响

// 场景2:PHP 时区 = UTC
date_default_timezone_set('UTC');
echo date('Y-m-d H:i:s', $timestamp);   // 2026-08-04 13:57:36 (UTC)
echo gmdate('Y-m-d H:i:s', $timestamp); // 2026-08-04 13:57:36 (UTC) ← 一样
更准确的说法:
gmdate() 是 "固定使用 UTC 时区的 date()"
它不是"绝对的",而是"固定在 UTC"的
尊重每位祺师,做有价值的祺文化社区!欢迎光临,并感谢您的支持与陪伴!
我希望能通过这个论坛让更多的朋友更多的关爱自己的家人和朋友,不要等到有一天失去后才知道没有好好的珍惜,才知道
拥有的珍贵!亲爱的们,如果你懂得,请把这份关爱传递,让更多的人加入到爱心接力当中,让每个人的心中都洋溢着爱的温馨!

我们应该知道:岁月如梭!其实生命,是很短暂,也是很脆弱的东西…… 设置自己的帖子签名请点这里!
在线zhangjingyu

只看该作者 板凳  发表于: 2026-08-09 21:13:53 星期日  点亮(0)
前几天,我们讨论过时区和date()格式化日期的问题,结论是:
date('Y-m-d H:i:s', $row['timestamp']) 始终受 PHP 当前时区的影响。
现在已知服务器的时区设置是utc,所以在我们自定义函数function getipguishu($onlineip) {格式化时间时,所得到的日期是utc日期(而我们通常要显示为北京时间)。从后台模板文件中,查看得知,论坛中有保存时区设置的数据,是pw_config表中的db_timedf,值为8。那我们是不是可以不具体或者说不特定指定时区:date_default_timezone_set('Asia/Shanghai');而是使用后台的设置,自动转换到对应的日期。就是添加一句:global $db_timedf
你的思路很好!确实可以利用论坛后台的时区设置来实现灵活的时区转换。不过需要注意的是,pw_config 表中的 db_timedf 存储的是时区偏移值(小时数),而不是时区名称。

解决方案
方案一:根据后台设置动态计算(推荐)
  1. function getipguishu($onlineip) {
  2.     global $db_timedf;  // 从后台获取时区偏移值(如 8)    
  3.     // ... 获取归属地的代码 ...    
  4.     // 格式化时间时,根据后台时区设置调整
  5.     $timestamp = time();  // 或其他时间戳
  6.     $formatted_time = gmdate('Y-m-d H:i:s', $timestamp + $db_timedf * 3600);    
  7.     return $formatted_time;
  8. }
方案二:使用 date() + 动态设置时区
  1. function getipguishu($onlineip) {
  2.     global $db_timedf;    
  3.     // 根据偏移值设置时区
  4.     $timezone = sprintf('%+d', $db_timedf);  // 如 "+8" 或 "-5"
  5.     date_default_timezone_set('Etc/GMT' . $timezone);    
  6.     // 或者用更精确的方式
  7.     // $timezone = new DateTimeZone(sprintf('Etc/GMT%+d', $db_timedf));    
  8.     // ... 获取归属地的代码 ...    
  9.     $formatted_time = date('Y-m-d H:i:s', time());
  10.     return $formatted_time;
  11. }
方案三:根据后台设置偏移时间戳(最稳定)
  1. function getipguishu($onlineip) {
  2.     global $db_timedf;    
  3.     // 如果 $db_timedf 不存在或为空,默认使用 8(北京时间)
  4.     if (empty($db_timedf)) {
  5.         $db_timedf = 8;    }    
  6.     // ... 获取归属地的代码 ...    
  7.     // 获取当前 UTC 时间戳,加上时区偏移
  8.     $timestamp = time();  // 当前 UTC 时间戳
  9.     $local_timestamp = $timestamp + $db_timedf * 3600;
  10.     $formatted_time = gmdate('Y-m-d H:i:s', $local_timestamp);    
  11.     return $formatted_time;
  12. }
重要说明
1. $db_timedf 的值含义
// pw_config 表中的 db_timedf
$db_timedf = 8;   // UTC+8(北京时间)
$db_timedf = 0;   // UTC
$db_timedf = -5;  // UTC-5(美国东部时间)
2. 不同方法的对比
方法    代码    优点    缺点
固定时区    date_default_timezone_set('Asia/Shanghai')    简单直接    不灵活
动态偏移    gmdate('Y-m-d H:i:s', $timestamp + $db_timedf*3600)    灵活,可后台调整    需要理解原理
动态时区    date_default_timezone_set('Etc/GMT+8')    使用标准时区    可能有夏令时问题
完整示例代码
  1. function getipguishu($onlineip) {
  2.     global $db_timedf;
  3.     
  4.     // 默认值(防止未定义)
  5.     if (!isset($db_timedf) || $db_timedf === '') {
  6.         $db_timedf = 8;  // 默认北京时间
  7.     }
  8.     $db_timedf = intval($db_timedf);
  9.     
  10.     // ... 这里是你原有的获取归属地逻辑 ...
  11.     // 例如:
  12.     $ipdata = file_get_contents("http://ip-api.com/json/{$onlineip}");
  13.     $result = json_decode($ipdata, true);
  14.     $location = $result['country'] . $result['regionName'] . $result['city'];    
  15.     // 格式化时间(使用后台时区设置)
  16.     $current_time = time();  // UTC 时间戳
  17.     $local_time = $current_time + $db_timedf * 3600;
  18.     $formatted_time = gmdate('Y-m-d H:i:s', $local_time);    
  19.     return array(
  20.         'location' => $location,
  21.         'time' => $formatted_time
  22.     );
  23. }
注意事项
$db_timedf 可能是字符串,需要转换为整数($db_timedf = intval($db_timedf);)
需要 global $db_timedf; 才能获取到全局变量
要确保 pw_config 表已经被加载(通常在 global.php 中)
时区偏移值有正负,注意计算方向

关于 date_default_timezone_set() 的说明
  1. // 如果使用 date_default_timezone_set(),不需要提前设置
  2. // 但需要根据 $db_timedf 构建时区字符串
  3. function getipguishu($onlineip) {
  4.     global $db_timedf;    
  5.     // 构建时区
  6.     $offset = intval($db_timedf);
  7.     $timezone = ($offset >= 0) ? "Etc/GMT-{$offset}" : "Etc/GMT+{abs($offset)}";
  8.     // 注意:Etc/GMT 的符号是反的!+8 要写成 Etc/GMT-8    
  9.     date_default_timezone_set($timezone);    
  10.     // ... 其他代码 ...
  11.     $formatted_time = date('Y-m-d H:i:s', time());
  12. }
推荐使用方案三(gmdate + 手动偏移),因为它:
✅ 不受服务器时区影响
✅ 不受 date_default_timezone_set() 影响
✅ 计算结果明确可控
✅ 性能更好(不需要设置时区)
尊重每位祺师,做有价值的祺文化社区!欢迎光临,并感谢您的支持与陪伴!
我希望能通过这个论坛让更多的朋友更多的关爱自己的家人和朋友,不要等到有一天失去后才知道没有好好的珍惜,才知道
拥有的珍贵!亲爱的们,如果你懂得,请把这份关爱传递,让更多的人加入到爱心接力当中,让每个人的心中都洋溢着爱的温馨!

我们应该知道:岁月如梭!其实生命,是很短暂,也是很脆弱的东西…… 设置自己的帖子签名请点这里!
在线zhangjingyu

只看该作者 沙发  发表于: 2026-08-09 19:50:20 星期日  点亮(0)
时区小知识:
时区说明
Etc/GMT+0UTC+0(格林威治标准时间)
Asia/Shanghai北京时间(UTC+8)
Etc/GMT-8也是北京时间(注意正负号相反)

注意: Etc/GMT+0 中的 +0 表示东0区,而 Etc/GMT-8 才是东8区(北京时间)。这个命名很反人类,所以建议直接用 Asia/Shanghai。
尊重每位祺师,做有价值的祺文化社区!欢迎光临,并感谢您的支持与陪伴!
我希望能通过这个论坛让更多的朋友更多的关爱自己的家人和朋友,不要等到有一天失去后才知道没有好好的珍惜,才知道
拥有的珍贵!亲爱的们,如果你懂得,请把这份关爱传递,让更多的人加入到爱心接力当中,让每个人的心中都洋溢着爱的温馨!

我们应该知道:岁月如梭!其实生命,是很短暂,也是很脆弱的东西…… 设置自己的帖子签名请点这里!