I wrote about localising dates (and other data) in a recent blog post,
but unfortunately there were some shortcomings where time zones were concerned.
As I alluded to in that post there is a way around this via the Intl
extension
that exposes a simple API to format DateTime
instances.
Thankfully this follow up post will be quite short as the setup is very simple for those of you on Ubuntu/Debian you can use the repositories.
sudo apt-get install php5-intl
For other distributions you can use PECL to install Intl
after building the
dependencies - icu (on Redhat this is as simple as
yum install libicu libicu-devel.x86_64
).
pecl install intl
echo "extension=intl.so" >> /etc/php.ini
Don’t forget to restart your webserver (eg. Apache) to make the new extension available to PHP.
Now it is installed you can use the extension to format dates in code.
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::FULL,
IntlDateFormatter::FULL
);
echo $IntlDateFormatter->format($DateTime);
// martes, 21 de julio de 2015, 14:11:11 (Hora de verano británica)
In this example I am telling the IntlDateFormatter
that I want to use the
Spanish locale (es_ES
) to print out the full date and time. By changing the
constants you can alter the format of the date that will be printed.
So if you just want the time you could create a formatter in the following manner.
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::NONE,
IntlDateFormatter::FULL
);
echo $IntlDateFormatter->format($DateTime);
// 14:15:04 (Hora de verano británica)
There are a few constants that can be passed into both the second (date) and
third (time) parameters of the IntlDateFormatter
constructor to change output
format.
IntlDateFormatter::NONE
- exclude this element from displayIntlDateFormatter::SHORT
- shortest format (22/07/2007)IntlDateFormatter::MEDIUM
- abbreviated format (Jul 22, 2007)IntlDateFormatter::LONG
- unabbreviated format (July 22, 2007)IntlDateFormatter::FULL
- full date information
Another example using the long format with the Spanish locale:
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::LONG,
IntlDateFormatter::LONG
);
echo $IntlDateFormatter->format($DateTime);
// 21 de julio de 2015, 14:25:41 GMT+1
So now you have seen how to change the format of the date we can look at the
timezone aspect of the equation. Normally it uses the default PHP timezone, but
this can be specified as the fourth parameter of the IntlDateFormatter
constructor.
You can pass in an instance of DateTimeZone
or IntlTimeZone
or a timezone
string such as Europe/London
or GMT+10
.
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::FULL,
IntlDateFormatter::FULL,
'Australia/Yancowinna'
);
echo $IntlDateFormatter->format($DateTime);
// martes, 21 de julio de 2015, 23:03:30 (Hora estándar de Australia central)
Incidentally, you can also pass other values into the format()
method too and not
just an instance of DateTime
. You can also pass an IntlCalendar
instance, the
number of seconds since the Unix epoch (01/01/1970 00:00:00) or a an array compatible
with localtime()
.
By default Intl
uses the Gregorian calendar but it can also make use
of other calendars by specifying a fifth parameter in the calls to IntlDateFormatter
constructor. So by default the previous example would include a calendar specification
like the following.
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES',
IntlDateFormatter::FULL,
IntlDateFormatter::FULL,
'Australia/Yancowinna',
IntlDateFormatter::GREGORIAN
);
echo $IntlDateFormatter->format($DateTime);
// martes, 21 de julio de 2015, 23:12:43 (Hora estándar de Australia central)
Should you wish to use another calendar it can be specified as part of the locale. In the following example I have decided to use the Buddhist calendar.
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES@calendar=buddhist',
IntlDateFormatter::FULL,
IntlDateFormatter::FULL,
'Australia/Yancowinna',
IntlDateFormatter::TRADITIONAL
);
echo $IntlDateFormatter->format($DateTime);
// martes, 21 de julio de 2558 BE, 23:16:08 (Hora estándar de Australia central)
Notice that I have changed the code for the locale (first parameter) to
es_ES@calendar=buddhist
and the calendar (fifth parameter) to
IntlDateFormatter::TRADITIONAL
. You could also use the Islamic calendar
with:
$DateTime = new DateTime();
$IntlDateFormatter = new IntlDateFormatter(
'es_ES@calendar=islamic',
IntlDateFormatter::FULL,
IntlDateFormatter::FULL,
'Australia/Yancowinna',
IntlDateFormatter::TRADITIONAL
);
echo $IntlDateFormatter->format($DateTime);
// martes, 5 de Shawwal de 1436 AH, 23:23:10 (Hora estándar de Australia central)
The calendars ICU allows you to play with include:
- Japanese (
@calendar=japanese
) - Buddhist (
@calendar=buddhist
) - Chinese (
@calendar=chinese
) - Persian (
@calendar=persian
) - Indian (
@calendar=indian
) - Islamic (
@calendar=islamic
) - Hebrew (
@calendar=hebrew
) - Coptic (
@calendar=coptic
) - Ethiopic (
@calendar=ethiopic
)
So there you have it; localised time zone aware dates with PHP on multiple calendar types. If the provided formats suit your application then this is a simple way to ensure your date and time information is readable in various locations and languages.