当在多个时区使用Laravel应用程序时,我一直在学习处理本地化时间的最佳方法。
我的理解是,应用程序时区应保持默认设置,即UTC。
这意味着所有日期时间/时间戳均以其UTC值记录在数据库中(在我的情况下为MySQL),换句话说,始终如一。
要使雄辩的模型具有正确的(本地化)日期/时间值,必须遵守用户的时区。在这一点上,我对如何进行尚不十分清楚-具体而言,在以下方面:
修改 我应该提到我的应用程序同时支持匿名用户和经过身份验证的用户,所以我不想强迫用户明确选择其时区。
答案 0 :(得分:0)
我喜欢为此添加辅助功能。我将应用程序保留在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);
}
这使用已添加到用户模型中的时区字段-但如果他们是来宾,则默认为东部时间。 (之所以如此东部,是因为这是生意,而且大多数客户都在这里。)
答案 1 :(得分:0)
我最终用自己的模型特征实现了这一目标,主要是因为我需要以透明的方式实现这一目标。
首先,我创建了自己的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;
}
}
我对上述方法的反馈很感兴趣。