fewagency / carbonator
Datetime helpers for timezone handling
Installs: 8 864
Dependents: 2
Suggesters: 0
Security: 0
Stars: 3
Watchers: 3
Forks: 0
Open Issues: 1
Requires
- php: >=7.3
- nesbot/carbon: ^1.21||^2.0
Requires (Dev)
- phpunit/phpunit: ^9.3
This package is auto-updated.
Last update: 2024-10-11 21:57:55 UTC
README
A collection of datetime helpers built on Carbon.
They help you easily parse or convert string
s or DateTime
s between timezones (and format them) with one single call.
A good pattern is to always keep your app working with times in the UTC timezone internally and to store any time data in that default timezone. If you're temped to or already use another timezone as default, please read the following article: Always Use UTC Dates And Times.
This is how Carbonator
can help you juggle those timezones:
- Actively convert any times to UTC when user data enters the application.
This is the perfect job for
Carbonator::parseToDefaultTz($input, $tz_parse = null)
. - If needed, convert to the user's timezone just before display or when populating inputs.
parseToDatetimeLocal($input, $tz_target = null, $tz_parse = null)
is one of the methods that can be used to directly format a string for display.
Examples
// Create DateTime in any timezone and get it in your app's default timezone: $in_sweden = Carbon::parse('2016-08-07 13:37', 'Europe/Stockholm'); // Stockholm is 2 hours ahead of UTC during daylight savings time $in_utc = Carbonator::parseToDefaultTz($in_sweden); echo $in_utc->toCookieString(); // Sunday, 07-Aug-2016 11:37:00 UTC // Parse directly from a string in a timezone and get it in your app's default timezone: $in_utc = Carbonator::parseToDefaultTz('2016-08-07 13:37', '-05:00'); echo $in_utc->toCookieString(); // Sunday, 07-Aug-2016 18:37:00 UTC // Format a time for a user in Namibia $in_utc = Carbon::parse('2016-08-07 13:37'); // Windhoek is 1 hour ahead of UTC when not on daylight savings time (WAT: West Africa Time) echo Carbonator::formatInTz($in_utc, 'D, M j, Y H:i T', 'Africa/Windhoek'); // Sun, Aug 7, 2016 14:37 WAT // Populate a HTML5 datetime-local input for a user in Japan: $in_utc = Carbon::parse('2016-08-07 13:37'); echo Carbonator::parseToDatetimeLocal($in_utc, 'Asia/Tokyo'); // 2016-08-07 22:37 // Populate a HTML5 datetime attribute $in_india = Carbon::parse('2016-08-07 13:37', 'Asia/Kolkata'); echo Carbonator::parseToDatetime($in_india); // 2016-08-07T13:37:00+05:30
Installation & Configuration
composer require fewagency/carbonator
Background
The Carbon package is excellent,
but it doesn't support parsing other DateTime
instances while keeping their timezone.
That's just the behaviour of the PHP DateTime
constructor
and not much to do about.
Also, Carbon
throws exceptions on errors.
To be able to parse any user input without having to filter or validate it first,
I wanted wrappers that just returns null
when input can't be parsed.
I think it makes sense putting these opinionated parsing and display methods into a separate
helper package instead of having Carbon
do even more work.
Usage
The first parameter - $input
All of Carbonator
's methods take a string
or
PHP DateTime
instance as the first $input
parameter.
This $input
will be turned into a Carbon
instance to process.
Remember that Carbon
extends DateTime
and can always be used safely as input.
Any empty $input
or any errors in parsing will make methods return null
.
The last parameter - $tz_parse
All of Carbonator
's methods also take the $tz_parse
timezone as the last parameter.
The $tz_parse
timezone will be used as context when parsing an $input
string,
but will be ignored when parsing DateTime
instances, as they already have a timezone.
As per default DateTime
behaviour, $tz_parse
will also be ignored whenever there is timezone
information supplied within the string.
Timezone parameters
Timezones can be supplied in string
format (e.g. 'Europe/Stockholm'
or '+01:00'
) or as a
PHP DateTimeZone
instance.
Remember, named timezones like Europe/Stockholm
takes daylight savings time (summer time)
into account, whereas offset timezones like +01:00
does not.
Use named timezones if you can, your users will appreciate it.
If a timezone parameter is left out or null
when calling a method,
the PHP default timezone from
date_default_timezone_get()
will be used.
Hopefully your default timezone will be UTC
.
Some frameworks, like Laravel, set the timezone explicitly using a config value
and you should keep that as UTC
unless you really know what you're trying to achieve with
another setting.
Read more below in Check your setup.
Methods
Carbonator::parse($input, $tz_parse = null)
Returns a Carbon
instance.
Note that the timezone of the output doesn't always match the supplied context timezone
from the 2nd parameter. The output is just guaranteed to be Carbon
or null
.
Carbonator::parseToTz($input, $tz_target = null, $tz_parse = null)
Returns a Carbon
instance, guaranteed to be in the $tz_target
timezone.
Carbonator::parseToDefaultTz($input, $tz_parse = null)
Returns a Carbon
instance, guaranteed to be in the PHP default timezone.
Carbonator::formatInTz($input, $format, $tz_target = null, $tz_parse = null)
Returns a string formatted according to the $format
- see docs for PHP's date()
.
The string is guaranteed to be in the $tz_target
timezone.
Carbonator::parseToDatetimeLocal($input, $tz_target = null, $tz_parse = null)
Returns a string formatted for a
HTML5 datetime-local
<input/> element
in the 'Y-m-d H:i'
format (e.g. '2016-08-07 13:37'
), with no timezone information.
Be kind to your users and display the timezone next to your input, perhaps in the <label>
or in an element referenced through the input's aria-describedby
attribute.
Carbonator::parseToDatetime($input, $tz_target = null, $tz_parse = null)
Returns a string formatted in the
"W3C" format
'Y-m-d\TH:i:sP'
(e.g. '2016-08-07T13:37:00+00:00'
), suitable for a
HTML5 <time/>
element's datetime
attribute.
Figuring out users' timezones
There's no way to know a user's timezone for sure, without asking them.
If you want to help your users select a timezone,
PHP's timezone_identifiers_list()
is a nice tool to find relevant timezones by country or continent.
The list is quite long though, so you could do IP-location on the server side to suggest a timezone to the user. For Laravel there's a package called Laravel Geoip doing just that by connecting to different services.
In the browser you could run some javascript, for example jstimezonedetect to guess the named timezone of your user from the timezone offset reported by their operating system. Or you could use the browser's Geolocation API, but that could be seen as a bit intrusive by the user, with permissions and everything.
In Laravel, there's a handy validation rule for timezone identifiers.
Check your setup
This console command will check your Linux system timezone:
date +%Z
Hopefully it's UTC
.
This query can be run by MySQL to check which timezones your database is using:
SELECT @@global.time_zone, @@session.time_zone
Hopefully both display as SYSTEM
or UTC
.
From within PHP you can use
date_default_timezone_get()
to check what default timezone is used.
If it's not UTC
, find out where it's set by either:
In Laravel
If you're using Laravel, you set your app's default timezone in your app's config/app.php
.
You can easily check a database-connection's timezone using the artisan tinker
command from the terminal:
php artisan tinker
Then run:
DB::select('SELECT @@global.time_zone, @@session.time_zone');
Again, hopefully both are reported as SYSTEM
or UTC
.
If the session timezone is wrong, an optional 'timezone'
parameter can be set on MySQL connections
in your app's config/databases.php
.
Don’t set it manually unless you need to, in which case it should be the same as the
Laravel config, i.e 'UTC'
.
Actually, pulling in config('app.timezone')
in the database config file works too!
Other methods
Here's a good read on Getting MySQL To Do It when it comes to timezones and PHP.
Authors
I, Björn Nilsved, created this package while working at FEW.