PHP中如何将JSON格式的Datetime转换为带正确时区的DateTime对象
解决JSON存储的DateTime数组转带时区DateTime对象的问题
首先,你当前代码里的核心错误是把timezone_type直接拼到日期字符串里——这个字段只是用来标识时区的类型,并不是时区偏移量或缩写,这么做会完全打乱DateTime的时区解析逻辑,导致你看到的时间完全不符合预期。
我们先对应你提到的3种时区类型,逐个处理JSON解码后的数组:
正确的转换逻辑
你的数据里timezone_type=3,对应时区标识符类型(比如UTC、Europe/London),这时候应该用DateTime构造函数的第二个参数传入DateTimeZone对象,而不是修改日期字符串。
如果要兼容所有3种时区类型,可以用switch分支处理:
/** * @return array|null * @throws JsonException * @throws Exception */ public function getContext(): ?array { $context = json_decode($this->context, true, 512, JSON_THROW_ON_ERROR); foreach ($context as $key => $value){ // 判断是否是JSON存储的DateTime数组 if(is_array($value) && isset($value['date'], $value['timezone_type'], $value['timezone'])){ $dateTime = null; switch ($value['timezone_type']) { case 1: // 类型1:UTC偏移量(比如时区值是+0300),直接拼到日期字符串后 $dateTime = new DateTime(sprintf('%s %s', $value['date'], $value['timezone'])); break; case 2: // 类型2:时区缩写(比如GMT),同样拼到日期字符串后 $dateTime = new DateTime(sprintf('%s %s', $value['date'], $value['timezone'])); break; case 3: // 类型3:时区标识符(比如UTC),用DateTimeZone作为构造参数 $timeZone = new DateTimeZone($value['timezone']); $dateTime = new DateTime($value['date'], $timeZone); break; default: throw new Exception(sprintf("不支持的时区类型:%d", $value['timezone_type'])); } // 如果你期望显示18h00(比如目标时区是UTC+1,比如Europe/Paris) // 可以在这里转换到目标时区 // $dateTime->setTimeZone(new DateTimeZone('Europe/Paris')); $context[$key] = $dateTime; } } // 注意:array_unique对DateTime对象不生效(对象比较是引用级别的) // 如果需要去重,建议自己实现逻辑,或者去掉这个调用 return $context; }
为什么你之前的结果不符合预期?
- 不设置时区时显示17h00:这是因为默认用了服务器的时区,而你的原始日期是UTC的17:00,如果服务器时区也是UTC,就会显示17h00。
- 设置错误时区后显示20h00:你之前的代码把
timezone_type=3拼到日期后变成2021-05-20 17:00:00.000000-3,这会被解析为UTC-3时区的17:00,转换为UTC时间就是20:00,所以显示错误。
实现你期望的18h00显示
如果你的目标时区是UTC+1(比如欧洲中部时间),只需要在构造完DateTime对象后,调用setTimeZone切换时区,再用format输出:
// 转换到目标时区 $dateTime->setTimeZone(new DateTimeZone('Europe/Paris')); // 输出18h00 echo $dateTime->format('H\hi');
内容的提问来源于stack exchange,提问作者Florent Cardot
相关产品推荐
相关产品推荐

