whitecube / laravel-timezones
在数据库中存储UTC日期,并在应用程序中使用自定义时区。
Requires
- php: >=8.1
- laravel/framework: ^9|^10|^11
- nesbot/carbon: ^2.64|^3.0
Requires (Dev)
- mockery/mockery: ^1.6
- pestphp/pest: ^2.34
README
处理时区可能会令人沮丧。这里是一个让您的日子变得明亮的一些尝试。
问题:人们普遍认为日期应以UTC
日期时间存储在数据库中,这通常意味着它们还需要在处理或显示之前进行本地时区的适配。Laravel提供了app.timezone
配置,使得处理时区成为可能。然而,更改该配置将影响存储和处理日期的时区。这个包试图通过提供一个时区转换机制来解决这个问题,该机制应该能够自动执行大多数重复的时区配置。
// Model: protected $casts = [ 'occurred_at' => TimezonedDatetime::class, ]; // Set a custom timezone Timezone::set('Europe/Brussels'); // Display dates stored as UTC in the app's timezone: // (database value: 2022-12-13 09:00:00) echo $model->occurred_at->format('d.m.Y H:i'); // Output: 13.12.2022 10:00 // Store dates using automatic UTC conversion: $model->occurred_at = '2022-12-13 20:00:00'; $model->save(); // Database value: 2022-12-13 19:00:00
安装
composer require whitecube/laravel-timezones
入门
app.timezone
配置设置必须设置为在数据库中保存日期时应使用的时区。我们强烈建议将其设置为UTC
,因为它是日期存储的全球标准。
对于应用程序内的日期处理和显示,人们期望有更多的灵活性。这就是为什么可以通过更新timezone
单例实例来动态设置应用程序的时区。根据应用程序的上下文,请选择最适合您情况的选项
1. 使用中间件
当应用程序的时区应该由用户的设置设置时很有用。
namespace App\Http\Middleware; use Closure; use Whitecube\LaravelTimezones\Facades\Timezone; class DefineApplicationTimezone { public function handle($request, Closure $next) { Timezone::set($request->user()->timezone ?? 'Europe/Brussels'); return $next($request); } }
2. 使用服务提供者
当应用程序的时区应该由应用程序本身设置时很有用。例如,在App\Providers\AppServiceProvider
namespace App\Providers; use Illuminate\Support\ServiceProvider; use Whitecube\LaravelTimezones\Facades\Timezone; class AppServiceProvider extends ServiceProvider { public function boot() { Timezone::set('America/Toronto'); } }
用法
一切设置完毕后,处理配置为应用程序当前时区的日期的最简单方法是使用模型上的TimezonedDatetime
或ImmutableTimezonedDatetime
类型。
use Whitecube\LaravelTimezones\Casts\TimezonedDatetime; use Whitecube\LaravelTimezones\Casts\ImmutableTimezonedDatetime; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'published_at' => TimezonedDatetime::class, 'birthday' => ImmutableTimezonedDatetime::class . ':Y-m-d', ];
在其他场景中,请随时直接使用Timezone
外观来获得更多便利。
use Carbon\Carbon; use Whitecube\LaravelTimezones\Facades\Timezone; // Get the current date configured with the current timezone: $now = Timezone::now(); // Create a date using the current timezone: $date = Timezone::date('2023-01-01 00:00:00'); // Alternatively, set the timezone manually on a Carbon instance: $date = new Carbon('2023-01-01 00:00:00', Timezone::current()); // Convert a date to the current timezone: $date = Timezone::date(new Carbon('2023-01-01 00:00:00', 'UTC')); // Alternatively, set the application timezone yourself: $date = (new Carbon('2023-01-01 00:00:00', 'UTC'))->setTimezone(Timezone::current()); // Convert a date to the storage timezone: $date = Timezone::store(new Carbon('2023-01-01 00:00:00', 'Europe/Brussels')); // Alternatively, set the storage timezone yourself: $date = (new Carbon('2023-01-01 00:00:00', 'Europe/Brussels'))->setTimezone(Timezone::storage());
分配值到转换属性
许多开发者习惯于将Carbon实例分配给日期属性
$model->published_at = Carbon::create($request->published_at);
这可能会导致意外的行为,因为分配的Carbon实例将默认为UTC
时区,而提供的值可能是指另一个时区。日期时间字符串将原样存储,而不会相应地调整其时区。
为了防止这种情况,建议让转换完成大部分工作
$model->published_at = $request->published_at;
包现在将使用正确的时区(例如,Europe/Brussels
)处理提供的日期时间字符串,并将正确的UTC值存储在数据库中。
一个更详细的(但也是正确的)方法是通过Timezone
外观创建Carbon实例
$model->published_at = Carbon::create($request->published_at, Timezone::current()); // Or, shorthand: $model->published_at = Timezone::date($request->published_at);
这不是一个错误,这是预期行为,因为应该在分配之前完全了解Carbon实例的时区。
边缘情况
如果您需要在默认时间戳列(created_at
和/或updated_at
)上使用TimezonedDatetime
或ImmutableTimezonedDatetime
转换,并且您期望处理除UTC或您使用Timezone::set()
定义的时区之外的时区,则需要在您的模型上应用Whitecube\LaravelTimezones\Concerns\HasTimezonedTimestamps
特质。
这是必要的,以防止Laravel对这些属性进行转换,这将导致丢失时区信息,阻止我们的转换正常工作。
这是一个需要使用特质的示例
Timezone::set('Europe/Brussels'); $model->created_at = new Carbon('2022-12-15 09:00:00', 'Asia/Taipei');
🔥 赞助
如果您在生产应用程序中依赖于此包,请考虑赞助我们!这是帮助我们继续做我们热爱的事情:制作优秀的开源软件的最好方式。
贡献
请随意提出更改建议,请求新功能或自行修复错误。我们相信还有很多可以改进的地方,我们非常愿意合并有用的拉取请求。谢谢!
用❤️为开源制作
在Whitecube(https://www.whitecube.be)我们使用许多开源软件作为我们日常工作的部分。所以当我们有机会回馈的时候,我们非常兴奋!
希望您会喜欢我们从我们这里的小贡献,如果您在项目中发现它有用,我们非常乐意听到您的反馈。关注我们的Twitter获取更多更新!