Eloquent Carbon игнорирует часовой пояс при обработке дат?

У меня есть следующий ресурс: <br/> <pre><code class="php">class TestResource extends JsonResource
{
  public function toArray(Request $request): array
  {
    return [
      'start' =&gt; $this-&gt;start-&gt;timezone('Europe/Moscow')-&gt;toDateTimeLocalString(),
    ];
  }
}</code></pre> <br/> <br/> А также имеется тестовый случай: <br/> <pre><code class="php">$d = "2024-09-01T16:00:00.000Z";
    $a = new Test(['start' =&gt; $d]);
    dump(
      $d,
      (new TestResource($a))-&gt;toArray($request),
      Carbon::parse($d)-&gt;timezone('Europe/Moscow')-&gt;toDateTimeLocalString()
    );</code></pre> <br/> <br/> Если я оставлю часовой пояс приложения по умолчанию, UTC, то все будет работать так, как и ожидалось. Какое влияние на тестирование окажет изменение часового пояса приложения?
  • 1 сентября 2024 г. 11:34
Ответы на вопрос 2
В вашем случае вы используете Eloquent и Carbon для работы с датами и временем. Давайте разобьем вашу проблему на несколько частей, чтобы понять, как изменение часового пояса повлияет на тестирование.

1. **Постановка вопроса**:
   Вы используете `toArray` в `TestResource`, чтобы вернуть время начала (`start`) в виде строки с указанием часового пояса "Europe/Moscow". При этом вы передаете время в формате UTC ("2024-09-01T16:00:00.000Z"). Вы используете `timezone()` из библиотеки Carbon для преобразования времени.

2. **Часовой пояс приложения**:
   Когда вы меняете часовой пояс приложения, это будет влиять на то, как Eloquent/Carbon будет обрабатывать даты и время по умолчанию. Например, если ваш часовой пояс установлен на UTC, то Carbon будет считывать и интерпретировать время как UTC (то есть с учетом часового пояса уже в 16:00 по UTC).

3. **Сравнение с UTC**:
   Если приложение на UTC:
   - `Carbon::parse($d)` вернет объект Carbon с учетом вашего входного времени как 16:00 по UTC.
   - Применяя `->timezone('Europe/Moscow')`, вы получите 19:00 (что верно, так как разница между UTC и Europe/Moscow — 3 часа).

4. **При изменении часового пояса**:
   Если вы измените часовой пояс приложения, например, на Europe/Moscow:
   - `Carbon::parse($d)` теперь будет интерпретировать входное время `2024-09-01T16:00:00.000Z` как 16:00 по времени Москвы, что является некорректным для митинга о UTC (это приведет к путанице).
   - Это означает, что, когда вы примените `->timezone('Europe/Moscow')`, вам может потребоваться больше, чем просто преобразовать с использованием `timezone()`, чтобы понимать, как именно обращаться с источником данных, особенно если источником данных использовалось другое времени.

5. **Рекомендации**:
   - При использовании времени с учетом часового пояса важно иметь чёткое понимание, в каком формате и в каком часовом поясе находится ваше исходное время.
   - Для тестов стоит придерживаться одного и того же часового пояса, чтобы избежать путаницы, и, если возможно, работать с UTC на уровне моделей, а затем использовать часовой пояс только на этапе вывода (например, форматирования для пользователя). 

Использование тестов с разными часовыми поясами для вашего приложения может выявить кучу нюансов, поэтому важно понимать, как ведет себя ваша логика обработки времени в зависимости от настроек часового пояса.
$d = Carbon::now(); // использует config('app.timezone')
debug(['NOW',(string)$d->timezone ,$d->toDateTimeLocalString()]);

// использует config('app.timezone') потому что в parse не передана таймзона
$d=Carbon::parse('2024-09-01T16:00:00.000'); 
debug(['parsed no TZ', (string)$d->timezone,$d->toDateTimeLocalString()]);
$d->timezone('Europe/Moscow');
debug(['set MSK', (string)$d->timezone,$d->toDateTimeLocalString()]);

// TZ указано в строке. НЕ ИСПОЛЬЗУЕТ config('app.timezone')
$d=Carbon::parse('2024-09-01T16:00:00.000Z'); 
debug(['parsed UTC', (string)$d->timezone,$d->toDateTimeLocalString()]);
$d->timezone('Europe/Moscow');
debug(['set MSK', (string)$d->timezone,$d->toDateTimeLocalString()]);

/**
array:3 [▼
  0 => "NOW"
  1 => "Europe/Moscow"
  2 => "2024-09-02T10:37:14"
]
array:3 [▼
  0 => "parsed no TZ"
  1 => "Europe/Moscow"
  2 => "2024-09-01T16:00:00"
]
array:3 [▼
  0 => "set MSK"
  1 => "Europe/Moscow"
  2 => "2024-09-01T16:00:00"
]
array:3 [▼
  0 => "parsed UTC"
  1 => "Z"
  2 => "2024-09-01T16:00:00"
]
debug
array:3 [▼
  0 => "set MSK"
  1 => "Europe/Moscow"
  2 => "2024-09-01T19:00:00"
]
*/
Похожие вопросы