How to use JDate

Few days ago I decided to help Yves with a datetime bug in Matukio (dating back to its "Seminar" roots). Everything seemed to be straight forward. I've worked with JDate in the past and had some experience with timezones. So I took the challenge thinking that I'll spend 2h and everything would be fine. Well, as it often happens a 2h job turned to be a one and a half day job... (this could make a very good blog post about estimates, but I'll do that another time...)

Let us examine the problem at hand. User A fills out a form, which has a field that stores a date. The best thing to do when you store the date in the db is to convert it to UTC. Why to UTC? Well this way you can have always a starting point and when you present the output to the user you can add different timezones depending on the users position. The trick here is to convert the date back to UTC. Fortunately JDate can help us with that. If you look at the JDate class in libraries/joomla/utilities/date.php you will see that the constructor actually expects 2 parameters -> the date and the timezone. So when you save a date you would generally want to do something like this:

$date = new JDate($myDate, $myTimezone);

Now the question is -> how do you properly calculate a timezone? Well, joomla helps us with that as well. You could write a small utility function that would look like this:

 /**
     * Returns the userTime zone if the user has set one, or the global config one
     * @return mixed
     */
    public static function getTimeZone() {
        $userTz = JFactory::getUser()->getParam('timezone');
        $timeZone = JFactory::getConfig()->getValue('offset');
        if($userTz) {
            $timeZone = $userTz;
        }
        return new DateTimeZone($timeZone);
    }

In the first line we try to get the user timezone, in the second we get the global config timezone. If the user has set a timezone in his configuration, then we pass the value of it to the DateTimeZone object. If the user on the other hand has not set a timezone, then we use the global one. Now that we have the correct time zone we can format the date to the MySQL format and store it in the database.

$myTimezone = myHelperClass:getTimezone();
$date = new JDate($myDate, $myTimezone)->format('Y-m-d H:i:s', false, false);

The first parameter to the format function is 'Y-m-d H:i:s' - this is the format we want our date to be saved in the db. The second parameter tells the function that we want to have the GMT/UTC time and the third parameter tells the format function that we don't want to translate the date.

Now you can save a correct UTC date in your database. Once you have that you will obviously want to show the date to the user again. This is also fairly straight forward provided you don't make the same mistake as I did. When I was trying to show the date I stored in the DB I was thinking - hm, the second parameter that I pass to JDate is the timezone, so obviously I need to pass the timezone I want my date to be presented in. So I used my utility function and passed the timezone as a second parameter. After that I just used the format function to output the date, but to my astonishment instead of showing the correct date and time I expected my date was actually 2h off. I wanted to have a date in the Berlin timezone, which is +1 (and +1 for DST), but I somehow ended with a date that was -2... I couldn't understand what was going on. So eventually I ended up purchasing a book that deals with the Date and Time subject in depth: Date and Time programming - a very good book on the subject and a good read for every PHP developer. After few hours reading I learned a lot of things that I didn't know , but unfortunately I still couldn't understand why my date was -2h off...

Eventually it struck me like a lightning! The second parameter was there to help JDate convert the date to UTC, I was not supposed to pass a timezone parameter if my date was in the UTC timezone. Here is what I had to do:

$date = new JDate($myDate);
$date->setTimezone($myTimezone);
echo $date->format(...);

Easy isn't it? There are also few things that could be useful to know:

  1. JHtml::_('date', $myDate) will output an UTC date in the user's timezone automatically -> so there is not need to calculate the timezone yourself.
  2. JHtml::_('calender', myDate ...) won't convert the date to the user's timezone so you have to make sure that you provide the date with the correct timezone
  3. If you use JForm calender time you can provide a filter: SERVER_UTC or USER_UTC that will handle the timezone calculations for you. 

I hope that this post will save you some time and that you learned something :) If you have any questions or remarks use the comment section below!

Rate this blog entry:
6
Working with Javascript in Joomla - Part 1
Some awesome CSS 3 tips and tricks for your site -...