【问题标题】:Laravel Carbon how to change timezone without changing the hourLaravel Carbon 如何在不更改小时的情况下更改时区
【发布时间】:2023-03-17 04:03:01
【问题描述】:

我正在尝试找到一种解决方法,以解决如何将存储在我的数据库中的日期时间转换为“yyyy-mm-dd HH-mm-ss”并为其指定时区“America/Los_Angeles”。

如果我更改时区,Carbon 会自动从时间中减去 7 小时,这就是将时间从 UTC 更改为 PST 时发生的情况,但我的数据库中的时间设置为 PST 时间。例如,我希望时间是今天上午 10 点,但如果我更改时区,Carbon 会将其转换为今天上午 3 点。

如何将时区更改为 PST 但仍将时间保持在上午 10 点?我需要 API 调用的时区,这就是我需要弄清楚这一点的原因。

【问题讨论】:

  • 真是一团糟。这就是为什么所有服务器和日期都应始终配置/存储为 UTC。
  • 我的服务器设置为 UTC,但我将日期存储为 PST,因为我以前从未需要使用时区。
  • 如果您的日期时间字符串本身不包含时区,您应该能够简单地更改config/app.php 中的'timezone' => 'UTC' 声明。默认情况下,这将指示 Carbon / DateTime 解释该特定时区中的任何日期时间字符串,因此您不必每次都在所有 Carbon 实例上转换时区(这将更改日期和/或时间)。
  • 世界标准时间!

标签: php laravel datetime laravel-5


【解决方案1】:

好的,我想出了一个愚蠢但实用的方法来做我想做的事情,并且它有效。

这是我的代码:

      $dt = Carbon::parse($request->ShootDateTime)->timezone('America/Los_Angeles');
      $toDay = $dt->format('d');
      $toMonth = $dt->format('m');
      $toYear = $dt->format('Y');
      $dateUTC = Carbon::createFromDate($toYear, $toMonth, $toDay, 'UTC');
      $datePST = Carbon::createFromDate($toYear, $toMonth, $toDay, 'America/Los_Angeles');
      $difference = $dateUTC->diffInHours($datePST);
      $date = $dt->addHours($difference);

我得到了我想转换为时区的时间并对其进行解析并更改时区。然后我得到日、月和年,并创建 2 个不同的日期,两者都会及时读取为 00:00:00,但因为在这种情况下它们相隔 7 小时,所以它们只能是 00:00:如果它们相差 7 小时,则为 00,这就是我接下来要捕捉的内容。最后,我采用初始日期时间并将差异添加到其中,从而在适当的时区为我提供适当的时间。

它很丑,但它有效。

【讨论】:

    【解决方案2】:

    更好更简单的方法是:

    $carbon = new Carbon('YYYY-MM-DD HH:II:SS', 'America/Los_Angeles');
    

    注意:不要忘记添加依赖use \Carbon\Carbon;。

    【讨论】:

      【解决方案3】:

      我认为您正在寻找的是:

      Carbon::createFromFormat('Y-m-d H:i:s', $some_date, 'UTC')
          ->setTimezone('America/Los_Angeles')
      

      首先,您设置您最初拥有的时区,因此如果您将数据库中的日期存储为 UTC,然后将默认时区设置为 UTC,然后使用 ->setTimeZone('Valid/Timezone') 将您所拥有的更改为新时区。

      【讨论】:

        【解决方案4】:
        /**
         * Return the formated date based on timezone selected from sidebar nav | Front-end user | Saved in Cookie | Sent $to
         *
         * @param Carbon $date
         * @param null $type (long | short)
         * @return Carbon date
         */
        public static function formatDateTimeZone($date, $type = 'long', $from = null, $to = null)
        {
            if (!$from)
                $from = 'UTC';
        
            if (!$to)
                $to = Cookie::get('timezone_user');
        
            $dateUTC = Carbon::now();
            $datePST = Carbon::now();
            $datePST->setTimezone($to);
        
            $start  = new Carbon($dateUTC);
            $end    = new Carbon($datePST);
            $difference = $start->diffInHours($end, false); // set false to see the negative difference
        
            $carbon = Carbon::createFromFormat('Y-m-d H:i:s', $date, $from); // specify UTC otherwise defaults to locale time zone as per ini setting
            $carbon->addHours($difference);
        
            if ($type == 'short')
            {
                $carbon = Carbon::parse($carbon)->format('Y-m-d');
            }
        
            return $carbon;
        }
        

        致电:$date = Date::formatDateTimeZone(Carbon::parse('2019-11-01 06:00:00'), 'long', 'UTC', 'America/Los_Angeles');

        我创建了这个函数来将保存在数据库中的日期格式化为 UTC 并将其正确显示到图表中。

        它会产生实际时区小时数的差异,并对旧日期应用相同的逻辑。 (例如 2019-11-04 时差为 -7h)

        Laravel 5.8

        【讨论】:

          【解决方案5】:

          Carbon::parse 第二个参数是您要解析的字符串的时区设置器,这使您能够将日期字符串解析到所需的时区并保持小时/秒不变。

          这里是link到parse方法的源代码,供参考。

          【讨论】:

            【解决方案6】:

            使用shiftTimezone() 方法代替setTimezone()。

            如果您在现有的 Carbon 实例上调用 setTimezone(), 它会将日期/时间更改为新时区,例如:

            $datetime = Carbon::createFromFormat('Y-m-d H:i:s', '2020-09-15 23:45:00');
            echo $datetime->toAtomString() . "\n";
            // 2020-09-15T23:45:00+00:00
            
            $datetime->setTimezone('America/Los_Angeles');
            echo $datetime . "\n";
            // 2020-09-15T16:45:00-07:00
            

            但是,调用 shiftTimezone() 会设置 时区而不更改时间。让我们从头再来一次:

            $datetime = Carbon::createFromFormat('Y-m-d H:i:s', '2020-09-15 23:45:00');
            echo $datetime->toAtomString() . "\n";
            // 2020-09-15T23:45:00+00:00
            
            $datetime->shiftTimezone('America/Los_Angeles');
            echo $datetime->toAtomString() . "\n";
            // 2020-09-15T23:45:00-07:00
            

            当然,您也可以将这些方法链接在一起:

            $datetime = Carbon::createFromFormat('Y-m-d H:i:s', '2020-09-15 23:45:00')
                ->shiftTimezone('America/Los_Angeles');
            echo $datetime->toAtomString() . "\n";
            // 2020-09-15T23:45:00-07:00
            
            

            您还可以通过将时区作为 settings数组:

            $datetime = Carbon::createFromFormat('Y-m-d H:i:s', '2020-09-15 23:45:00')
                ->settings(['timezone' => 'America/Los_Angeles']);
            echo $datetime->toAtomString() . "\n";
            // 2020-09-15T23:45:00-07:00
            

            【讨论】:

            • 谢谢,多纳泰罗。应该是正确的答案。
            【解决方案7】:

            我对这个问题的回答会有所不同。对于我的情况,我有一个日期字符串需要解析,就好像它是给定日期的第 0 小时(午夜)在自定义时区 - 但我数据库中的所有日期都是 在 UTC 中跟踪,所以我真正需要做的是将日期保持在 UTC 时区,但给它一种预期时区的“反向偏移”。

            情况:我得到一个日期字符串“2020-09-02”,我将使用它来查看 X 记录是否有一个在同一日期或之后的字段;但是,我在美国/芝加哥时区,目前距离 UTC 为 -05:00,因此我需要将此日期字符串的 UTC 版本调整为 2020-09-02 05:00 以准确计算我时区的午夜.

            为此,我需要将日期字符串解析为美国/芝加哥时区,然后将时区更改为 UTC:

            $value = "2020-09-02"
            Carbon::parse($value . '  America/Chicago')->tz('UTC')
            

            【讨论】:

              猜你喜欢
              • 2018-07-24
              • 1970-01-01
              • 2013-09-10
              • 2015-10-26
              • 1970-01-01
              • 1970-01-01
              • 2019-11-01
              • 2021-01-31
              • 2023-03-09
              相关资源
              最近更新 更多