Я читал о лучшем подходе к обработке локализованного времени, когда приложение Laravel используется в нескольких часовых поясах.
Насколько я понимаю, часовой пояс приложения должен оставаться установленным по умолчанию, то есть UTC.
Это означает, что все даты и времени / метки времени записываются в базу данных (в моем случае MySQL) как их значение в формате UTC - другими словами, последовательно.
Чтобы модели Eloquent имели правильные (локализованные) значения даты и времени, необходимо соблюдать часовой пояс пользователя. Именно здесь я не совсем понимаю, как действовать дальше - в частности, с точки зрения:
Редактировать Я должен упомянуть, что мое приложение поддерживает как анонимных, так и аутентифицированных пользователей, поэтому я не хочу заставлять пользователя явно выбирать свой часовой пояс.
Что я делаю, так это то, что часовой пояс в моем проекте / сервере установлен в UTC, и когда я выводю время / дату, я устанавливаю часовой пояс в экземпляре углерода (например, created_at), и у меня есть в профиле пользователя параметр для выбора местного часового пояса.
@thefallen, как вы устанавливаете часовой пояс в экземпляре углерода - вручную? Кроме того, мое приложение поддерживает анонимных и аутентифицированных пользователей, поэтому я не могу явно запросить их часовой пояс.
Вы можете создать глобальное промежуточное ПО и реализовать что-то вроде полезныйангл.com/post/31/…






Мне нравится добавлять вспомогательную функцию только для этого. Я сохраняю приложение в формате UTC, поэтому все даты хранятся одинаково ... а затем я передаю их через помощник либо в контроллере, либо в моем шаблоне лезвия.
public static function date($date, $format = 'n/j/Y g:i a T'){
$timezone = empty(Auth::user()->timezone) ? 'America/New_York' : Auth::user()->timezone;
if ( empty($date) ){
return '--';
}
return Carbon::parse($date)->timezone($timezone)->format($format);
}
При этом используется поле часового пояса, которое было добавлено в модель пользователя, но по умолчанию будет использоваться восточное время, если они являются гостями. (Восточная, потому что это был бизнес, и большинство клиентов находятся здесь.)
В итоге я реализовал это с помощью моей собственной модели, в первую очередь потому, что мне нужно было реализовать это прозрачным образом.
Во-первых, я создал свой собственный метод getAttribute(), чтобы получить сохраненные значения (сохраненные как часовой пояс приложения по умолчанию - вероятно, UTC), а затем применить текущий часовой пояс.
Эта черта также изменяет методы модели create() и update(), чтобы поддерживать поля в свойстве модели dates, сохраняемые в качестве часового пояса приложения, когда они были установлены пользователем в текущем активном часовом поясе.
Статический метод self::getLocale() в трейте в моем случае предоставляется другим трейтом в моем приложении, хотя эту логику можно настроить в соответствии с вашим собственным приложением.
trait LocalTime
{
/**
* Override create() to save user supplied dates as app timezone
*
* @param array $attributes
* @param bool|mixed $allow_empty_translations
*/
public static function create(array $attributes = [], $allow_empty_translations=false)
{
// get empty model so we can access properties (like table name and fillable fields) that really should be static!
// https://github.com/laravel/framework/issues/1436
$emptyModel = new static;
// ensure dates are stored with the app's timezone
foreach ($attributes as $attribute_name => $attribute_value) {
// do we have date value, that isn't Carbon instance? (assumption with Carbon is timezone value will be correct)
if (!empty($attribute_value) && !$attribute_value instanceof Carbon && in_array($attribute_name, $emptyModel->dates)) {
// update attribute to Carbon instance, created with current timezone and converted to app timezone
$attributes[$attribute_name] = Carbon::parse($attribute_value, self::getLocale()->timezone)->setTimezone(config('app.timezone'));
}
}
// https://github.com/laravel/framework/issues/17876#issuecomment-279026028
$model = static::query()->create($attributes);
return $model;
}
/**
* Override update(), to save user supplied dates as app timezone
*
* @param array $attributes
* @param array $options
*/
public function update(array $attributes = [], array $options = [])
{
// ensure dates are stored with the app's timezone
foreach ($attributes as $attribute_name => $attribute_value) {
// do we have date value, that isn't Carbon instance? (assumption with Carbon is timezone value will be correct)
if (!empty($attribute_value) && !$attribute_value instanceof Carbon && in_array($attribute_name, $this->dates)) {
// update attribute to Carbon instance, created with current timezone and converted to app timezone
$attributes[$attribute_name] = Carbon::parse($attribute_value, self::getLocale()->timezone)->setTimezone(config('app.timezone'));
}
}
// update model
return parent::update($attributes, $options);
}
/**
* Override getAttribute() to get times in local time
*
* @param mixed $key
*/
public function getAttribute($key)
{
$attribute = parent::getAttribute($key);
// we apply current timezone to any timestamp / datetime columns (these are Carbon objects)
if ($attribute instanceof Carbon) {
$attribute->tz(self::getLocale()->timezone);
}
return $attribute;
}
}
Мне было бы интересно узнать отзывы о вышеупомянутом подходе.
Это выглядит нормально, но требует, чтобы вы добавили черту ко всем моделям. Я думаю, что это могло бы быть альтернативным решением - прослушивать общее событие eloquent.saving и перебирать свойство $dates затронутой модели и работать над этими атрибутами. Конечно, это требует, чтобы у вас было правильно используемое свойство $dates. Примечание. Если вы используете пользовательские события в своей модели (массив $dispatchesEvents) и одно из них возвращает результат, общее событие не будет запущено.
Вы можете попробовать эти ответы stackoverflow.com/questions/36147824/…