You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多时区适配:时间选择器如何显示用户本地正确时间

解决步骤

1. 为Mailing模型添加send_at字段的访问器和修改器

你之前添加的访问器仅针对created_at字段生效,send_at不会自动转换时区,所以需要新增对应访问器,同时添加修改器统一处理存储时的时区转换:

// 在Mailing模型顶部引入Carbon
use Carbon\Carbon;

// 新增send_at访问器,读取时自动转用户时区
public function getSendAtAttribute($value)
{
    $timezone = optional(auth()->user())->timezone ?? config('app.timezone');
    return Carbon::parse($value)->timezone($timezone);
}

// 新增send_at修改器,存储时自动转系统配置的欧洲时区
public function setSendAtAttribute($value)
{
    $timezone = optional(auth()->user())->timezone ?? config('app.timezone');
    $this->attributes['send_at'] = Carbon::parse($value, $timezone)->timezone(config('app.timezone'));
}

同时需要把send_at加入模型的$dates属性,让Laravel自动解析为Carbon实例:

protected $dates = [
    'send_at',
    'created_at',
    'updated_at'
];

2. 修正Blade视图的时间显示逻辑

原有代码使用原生date()函数不会应用用户时区,替换为Carbon处理,同时动态显示当前用户时区缩写:

<div class="form-group">
    <div class="col-md-5">
        <label for="" class="form-label">Start Sending:</label>
        <br>
        <input type="radio" name="send_at" @if(old('send_at') != "now") checked @endif value="now" id="send-now">
        <label for="send-now">Now</label><br>
        <input type="radio" @if($mailing && strtotime($mailing->send_at) > time()) checked @endif name="send_at" value="latter" id="send-latter">
        <label for="send-latter">Later</label><br>
        
        @php
            $userTimezone = optional(auth()->user())->timezone ?? config('app.timezone');
            $defaultTime = Carbon::now($userTimezone);
            if($mailing && !old('send_date')) {
                $defaultTime = $mailing->send_at; // 访问器已自动转为用户时区
            } elseif(old('send_date') && old('send_time')) {
                $defaultTime = Carbon::parse(old('send_date') .' '. old('send_time'), $userTimezone);
            }
        @endphp
        
        <div class="row">
            <div class="col-md-6 pb-20">
                <input class="datepicker form-control" type="text" name="send_date" value="{{ $defaultTime->format("m/d/Y") }}">
            </div>
            <div class="col-md-6">
                <div class="input-group bootstrap-timepicker timepicker">
                    <input type="text"  name="send_time"  value="{{ $defaultTime->format("h:i A") }}" id="timepicker" class="form-control input-small">
                    <span class="input-group-addon"><i class="glyphicon glyphicon-time"></i></span>
                    <span class="input-group-addon">{{ $defaultTime->format('T') }}</span>
                </div>
            </div>
        </div>
    </div> 
</div>

3. 修正saveMailing方法的send_at赋值逻辑

原有代码直接把前端传的send_at(值为now/latter)赋值给字段,需要先判断选项处理实际时间:

public function saveMailing(User $user, $data)
{
    $subscribers = isset($data['subscribers']) && $data['subscribers'] ? $data['subscribers'] : null;
    $subscribersIds = array();
    
    if($subscribers) {
        $subscribersArr = explode(",", $subscribers);
        if(count($subscribersArr) > 0) {
            foreach ($subscribersArr as $sid) {
                if($sid > 0) {
                    $subscribersIds[$sid] = $sid;
                }
            }
        }
    }
    $this->user_id = $user->id;
    $this->promo_id = $data['promo_id'];
    $this->mailinglist_id = $data['mailinglist_id'] > 0 ? $data['mailinglist_id'] : null;
    $this->subject = $data['subject'];
    $this->body = $data['body'];
    // 新增send_at处理逻辑
    if ($data['send_at'] == 'now') {
        $this->send_at = Carbon::now();
    } else {
        // 拼接用户选择的日期时间,修改器会自动转成系统时区存储
        $this->send_at = $data['send_date'] . ' ' . $data['send_time'];
    }
    $this->type = isset($data['type']) && $data['type'] == 'reminder' ? 'reminder' : 'notification';
    $this->subscribers = count($subscribersIds) > 0 ? implode(",", $subscribersIds) : null;
    
    $this->save();
}

内容的提问来源于stack exchange,提问作者Sinisa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 23:18:02