Laravel.io
use Carbon\Carbon;

trait Timezone {

    protected $defaultTimezone = null;

    public function getDefaultTimezone()
    {
        if( is_null($this->defaultTimezone) ) {
            $this->defaultTimezone = \Auth::check() ? \Auth::user()->timezone : \Config::get('app.timezone');
        }

        return $this->defaultTimezone;
    }

    public function setCreatedAtAttribute($value)
    {
        $dt = Carbon::createFromFormat('Y-m-d H:i:s',$value, $this->getDefaultTimezone());
        $dt->setTimezone('UTC');
        $this->attributes['created_at'] = $dt->format('Y-m-d H:i:s');
    }

    public function setTimezoneForDates()
    {
        if(empty($this->dates)) {
            return;
        }

        foreach( $this->dates as $column ) {
            $dt = Carbon::createFromFormat('Y-m-d H:i:s',$this->attributes($column), $this->getDefaultTimezone());
            $dt->setTimezone('UTC');
            $this->attributes[$column] = $dt->format('Y-m-d H:i:s');
        }
    }

    /**
     * Convert a DateTime to a storable string.
     *
     * STOLEN from Illuminate\Database\Eloquent\Model to override.
     * @param  \DateTime|int  $value
     * @return string
     */
    public function fromDateTime($value)
    {
        $format = $this->getDateFormat();

        // If the value is already a DateTime instance, we will just skip the rest of
        // these checks since they will be a waste of time, and hinder performance
        // when checking the field. We will just return the DateTime right away.
        if ($value instanceof DateTime)
        {
            //
        }

        // If the value is totally numeric, we will assume it is a UNIX timestamp and
        // format the date as such. Once we have the date in DateTime form we will
        // format it according to the proper format for the database connection.
        elseif (is_numeric($value))
        {
            $value = Carbon::createFromTimestamp($value, $this->getDefaultTimezone());
        }

        // If the value is in simple year, month, day format, we will format it using
        // that setup. This is for simple "date" fields which do not have hours on
        // the field. This conveniently picks up those dates and format correct.
        elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value))
        {
            $value = Carbon::createFromFormat('Y-m-d', $value, $this->getDefaultTimezone())->startOfDay();
        }

        // If this value is some other type of string, we'll create the DateTime with
        // the format used by the database connection. Once we get the instance we
        // can return back the finally formatted DateTime instances to the devs.
        else
        {
            $value = Carbon::createFromFormat($format, $value, $this->getDefaultTimezone());
        }

        $value->setTimezone('UTC');
        return $value->format($format);
    }

    /**
     * Return a timestamp as DateTime object.
     *
     * STOLEN from Illuminate\Database\Eloquent\Model to override.
     *
     * @param  mixed  $value
     * @return \Carbon\Carbon
     */
    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.
        if (is_numeric($value))
        {
            $dt = Carbon::createFromTimestamp($value, "UTC");
            $dt->setTimezone($this->getDefaultTimezone());
            return $dt;
        }

        // 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))
        {
            $dt =  Carbon::createFromFormat('Y-m-d', $value, "UTC")->startOfDay();
            $dt->setTimezone($this->getDefaultTimezone());
            return $dt;
        }

        // 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();

            $dt =  Carbon::createFromFormat($format, $value, 'UTC');
            $dt->setTimezone($this->getDefaultTimezone());
            return $dt;
        }

        return Carbon::instance($value);
    }

    /**
     * Convert the model's attributes to an array.
     *
     * @return array
     */
    public function attributesToArray()
    {
        $attributes = $this->getArrayableAttributes();

        // If an attribute is a date, we will cast it to a string after converting it
        // to a DateTime / Carbon instance. This is so we will get some consistent
        // formatting while accessing attributes vs. arraying / JSONing a model.
        foreach ($this->getDates() as $key)
        {
            if ( ! isset($attributes[$key])) continue;

            $attributes[$key] = (string) $this->asDateTime($attributes[$key]);
        }

        $mutatedAttributes = $this->getMutatedAttributes();

        // We want to spin through all the mutated attributes for this model and call
        // the mutator for the attribute. We cache off every mutated attributes so
        // we don't have to constantly check on attributes that actually change.
        foreach ($mutatedAttributes as $key)
        {
            if ( ! array_key_exists($key, $attributes)) continue;

            $attributes[$key] = $this->mutateAttributeForArray(
                $key, $attributes[$key]
            );
        }

        // Next we will handle any casts that have been setup for this model and cast
        // the values to their appropriate type. If the attribute has a mutator we
        // will not perform the cast on those attributes to avoid any confusion.
        foreach ($this->casts as $key => $value)
        {
            if ( ! array_key_exists($key, $attributes) ||
                in_array($key, $mutatedAttributes)) continue;

            $attributes[$key] = $this->castAttribute(
                $key, $attributes[$key]
            );
        }

        // Here we will grab all of the appended, calculated attributes to this model
        // as these attributes are not really in the attributes array, but are run
        // when we need to array or JSON the model for convenience to the coder.
        foreach ($this->getArrayableAppends() as $key)
        {
            $attributes[$key] = $this->mutateAttributeForArray($key, null);
        }

        return $attributes;
    }

}

Please note that all pasted data is publicly available.