Multiple times in Laravel / Carbon

I was wondering if this is possible, so let me say that I have such a model:

MyModel
   SomeDate - Carbon

Now I also have a time zone for the current user:

User
   MyTimezone

the time slots stored in the database are always stored in UTC (to ensure that everything is consistent), and the output dates should always be formatted in a specific time zone (but the time zone is different for each user), for example America / Chicago for User1 and America / Denver for User2.

Is there a way to automatically format the time intervals per Carbon instance to the specified one before the output, or will I need to scroll through the collection and set each of them accordingly?

The setup app.timezonedoes not work, as it also causes Carbon instances to be stored in the database in the time zone app.timezone, while all dates in the database must be in UTC, so I lose consistency.

I currently app.timezonehave UTC set in the application configuration, but I also have to convert all Carbon instances to the correct time zone before output. Is there a better way, maybe capturing a penalty, before Carbon turns into a string and does it there?

EDIT:

Things I tried:

Replace setAttribute and 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;
}

override asDateTime:

protected function asDateTime($value)
{
    // If this value is an integer, we will assume it is a UNIX timestamp 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);
}
+4
source share
2 answers

, , , - A B , A B .

.

, User MyModel, , :

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;
}

, 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;
}

:

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;
}
+1

, - 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;
    }
}

, , .

  • laravel 5 (2015-03-18): Illuminate\Database\Eloquent\Model: 2809-2889
  • laravel 4.2 (2015-03-18): Illuminate\Database\Eloquent\Model: 2583-2662
+2

Source: https://habr.com/ru/post/1570115/


All Articles