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
相关产品推荐
相关产品推荐

