Localizing your web app for per-client date/time display
by Andrew Kandels
Many frameworks do this for you; but, if you're writing a small application or updating an older one, you might need to take a more manual approach to dealing with localization and date/time values. Ill go over the common settings, how to store them, and lists of possible values.
Everyone in the world can read a date as either 12/31/2010 or 31/12/2010 (alternate slashes and two digit years can be substituted). You dont need to allow customizing the display beyond these two formats - its just cosmetic after that. If you hard coded column sizes on grids and forms, you can store this setting as boolean called
date_dmy or similar. Or, you can take the WordPress/phpBB approach and store it as a string with php's date() formatter strings.
Daylight Saving Time (DST)
Most of North America, Europe, southern South America, New Zealand and southern Australia observe daylight saving time (notice daylight is singular, not plural) which changes their time zone offset. First, youll need an
is_dst boolean configuration parameter to store whether or not the client observes DST.
The dates each country observes DST varies. The first piece of information youll need when generating times is a true/false value reflecting whether or not the client is in DST as of a date (warning, this can change a date if its midnight and were adding hours!).
There are three ways to check if the client is in DST:
- Lazy Method: Most of the time in the northern hemisphere, it starts in March and ends in November. Rely on the servers date(‘I) invocation to determine whether the server local time is DST or not (this only works if your server time is DST).
- Accurate Method: Install the tz database (other formats). Determine their DST start and end dates by querying the tz database with their 2-letter country code and the date (so you need to capture the country code for each client).
- Proper/Framework Method: Collect and store the clients locale as a PHP timezone string. Use date_default_timezone_set() to change the script to their local zone. Check date(‘I) to check if theyre in DST time (or just display their time/date at this point after converting server time to GMT and let PHP handle conversion).
When storing a time zone, make sure to use a signed float. There are half-hour time zones! Generally, time zones are stored in relation to GMT. Possible time zones are:
-12, -11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 8, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14.
For reasons like database timestamp auto-creation and administrative reporting, all times in databases are usually stored in server local time. You should write a script that converts server time into GMT or use gmdate(). Filtering into the client time zone can then be done from GMT which is generally easier to read in source code.
Everyone in the world can read a time either as 23:45 or 11:45pm. You can easily store this configuration as a "is_24hr" boolean value. If you want to allow greater customization, you can allow clients to use PHP date() format strings (like WordPress/phpBB does).
Separate and Consolidate Date and Time Display Functions
Run all your date/time logic through three functions. This allows you to easily test for failure and reduces work.
I usually recommend writing three date/time display functions. One to display date, one to display time, and one that concatenates the two. Several applications have a single display which returns both, but there are many cases where its helpful to display one or the other and it really doesnt hurt to separate the two.
Lazy Date Problem
Many people get lazy when displaying dates and simply return them in server time. You wont notice problems if you're primarily in the US with a maximum of a 3 hour difference between time zones; but, If you're server is in EST and your client is in London, 8pm server time on the 11th of December is the 12th of December for the client. Remember to do the same time zone and DST logic when calculating dates as you do when calculating times.
Lazy Range Problem
A client enters a date range search in your application from January 4th, 2010 to January 7th, 2010 and you store the date as a timestamp or datetime value. First, make sure you follow the last paragraph (lazy date problem) and convert the dates the client enters from his time to server time (backwards conversion). Second, add times to the dates:
WHERE created_date BETWEEN "2010-01-04 00:00:00" AND "2010-01-07 23:59:59"
Its important to include the times or youll lose up to a days worth of results. Clients will expect this behavior.
PHP versus Database
As tempting as it is to store database records in client local time, it should be avoided. If a client updates their time zone, you have to update every records time and date accordingly. Its also more confusing when querying the data directly from an administrators point of view, or when importing into other systems.