Dav*_* Xu 5 php datetime laravel php-carbon
我想知道这是否可行,所以让我说我有一个这样的模型:
MyModel
SomeDate - Carbon
Run Code Online (Sandbox Code Playgroud)
现在,我也有一个当前用户的时区,如下所示:
User
MyTimezone
Run Code Online (Sandbox Code Playgroud)
存储在数据库中的时区始终以UTC格式存储(以确保一切都一致),并且输出日期应始终格式化为特定时区(但每个用户的时区不同),例如America1/Chicago for User1和America /用户2的丹佛.
有没有办法在输出之前自动将每个Carbon实例的时区格式化为给定的一个,或者我是否必须遍历集合并相应地设置每个实例?
设置app.timezone不起作用,因为它还导致Carbon实例在app.timezone时区中保存到数据库,而数据库中的所有日期都应该是UTC,因此我失去了一致性.
我目前app.timezone在App配置中设置为UTC,但我还被迫在输出之前将所有Carbon实例转换为正确的时区.有没有更好的方法,可能是在将Carbon变成字符串并在那里进行之前捕获执行?
编辑:
我试过的事情:
覆盖setAttribute和getAttribute:
public function setAttribute($property, $value) {
if ($value instanceof Carbon) {
$value->timezone = 'UTC';
}
parent::setAttribute($property, $value);
}
public function getAttribute($key) {
$stuff = parent::getAttribute($key);
if ($stuff instanceof Carbon) {
$stuff->timezone = Helper::fetchUserTimezone();
}
return $stuff;
}
Run Code Online (Sandbox Code Playgroud)
覆盖asDateTime:
protected function asDateTime($value)
{
// If this value is an integer, we will assume it is a UNIX timestamp's value
// and format a Carbon object from this timestamp. This allows flexibility
// when defining your date fields as they might be UNIX timestamps here.
$timezone = Helper::fetchUserTimezone();
if (is_numeric($value))
{
return Carbon::createFromTimestamp($value, $timezone);
}
// If the value is in simply year, month, day format, we will instantiate the
// Carbon instances from that format. Again, this provides for simple date
// fields on the database, while still supporting Carbonized conversion.
elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value))
{
return Carbon::createFromFormat('Y-m-d', $value, $timezone)->startOfDay();
}
// Finally, we will just assume this date is in the format used by default on
// the database connection and use that format to create the Carbon object
// that is returned back out to the developers after we convert it here.
elseif ( ! $value instanceof DateTime)
{
$format = $this->getDateFormat();
return Carbon::createFromFormat($format, $value, $timezone);
}
return Carbon::instance($value);
}
Run Code Online (Sandbox Code Playgroud)
对于我的应用程序遇到同样的问题,其中远程网站将以UTC格式存储日期,并且我必须根据登录用户显示实际日期,我想出了覆盖Laravel Eloquent模型.
只需扩展Illuminate\Database\Eloquent\Model,如下:
<?php namespace Vendor\Package;
use Illuminate\Database\Eloquent\Model as EloquentModel;
class Model extends EloquentModel
{
/**
* Return a timestamp as a localized DateTime object.
*
* @param mixed $value
* @return \Carbon\Carbon
*/
protected function asDateTime($value)
{
$carbon = parent::asDateTime($value);
// only make localized if timezone is known
if(Auth::check() && Auth::user()->timezone)
{
$timezone = new DateTimeZone(Auth::user()->timezone);
// mutates the carbon object immediately
$carbon->setTimezone($timezone);
}
return $carbon;
}
/**
* Convert a localized DateTime to a normalized storable string.
*
* @param \DateTime|int $value
* @return string
*/
public function fromDateTime($value)
{
$save = parent::fromDateTime($value);
// only make localized if timezone is known
if(Auth::check() && Auth::user()->timezone)
{
// the format the value is saved to
$format = $this->getDateFormat();
// user timezone
$timezone = new DateTimeZone(Auth::user()->timezone);
$carbon = Carbon::createFromFormat($format, $value, $timezone);
// mutates the carbon object immediately
$carbon->setTimezone(Config::get('app.timezone'));
// now save to format
$save = $carbon->format($format);
}
return $save;
}
}
Run Code Online (Sandbox Code Playgroud)
也许这对其他绊倒这个问题的人有用.
作为参考
小智 1
如果我理解正确,您想要实现的是将时区从 A 格式转换为 B 格式并将其发送给用户,其中 A 格式存储在数据库中,从数据库检索记录后转换为 B 格式。
这是一个巧妙的方法来做到这一点。
User在、 等模型中MyModel需要转换的地方,在 model 中添加一个函数:
public function getConversionAttribute()
{
$conversion = Convert($this->SomeDate);
//Convert is the customized function to convert data format
//SomeDate is the original column name of dates stored in your database
return $conversion;
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您使用 查询 User 模型或 MyModel $user = User::find(1),您现在可以通过使用 访问转换属性来获取转换后的日期$user->conversion。
干杯!
但是,以这种方式添加的属性不会包含在转换后的数组中。您需要在模型中添加另一个函数。
public function toArray()
{
$array = parent::toArray();
//if you want to override the original attribute
$array['SomeDate'] = $this->conversion;
//if you want to keep both the original format and the current format
//use this: $array['Conversion'] = $this->conversion;
return $array;
}
Run Code Online (Sandbox Code Playgroud)
通用版本:
public function toArray() {
$array = parent::toArray();
//if you want to override the original attribute
$dates = $this->getDates();
foreach ($dates as $date) {
$local = $this->{$date}->copy();
$local->timezone = ...
$array[$date] = (string)$local;
}
//if you want to keep both the original format and the current format
//use this: $array['Conversion'] = $this->conversion;
return $array;
}
Run Code Online (Sandbox Code Playgroud)