Guide through Magento’s timezones

Featured Image

I’ll guide you through Magento’s timezone behavior, as I’ve noticed that people tend to get confused in cases when they have 2 or more websites with different timezones. If this is what you are searching for, read on!

First of all, let’s start with the Web server – Magento relation, and their times.

Web server – Magento relation

Let’s look at the following scenario. You want an online store – ok, you’ll need a web hosting for it (on some web hosting providers server). With classic low-level PHP development people tend to overlook server’s settings, and each server has it’s own time and timezone set. If you overlook that, each time your script executes any of time functions, it will take server time as actual one. So first thing you need to look at, is server location, and its time zone.

In case of Magento, the situation is a bit different. Let’s take a look at index.php (first executed PHP file on server):

Mage::run($mageRunCode, $mageRunType);

And that line starts Magento initialization.

Now, let’s move forward, to app/Mage.php file. In there, you’ll find this:

self::$_app->run(array(
                'scope_code' => $code,
                'scope_type' => $type,
                'options'    => $options,
            ));

After we trace it a bit more, we’ll come across this method:

//File: "app/code/core/Mage/Core/Model/App.php"
     /**
     * Initialize PHP environment
     *
     * @return Mage_Core_Model_App
     */
    protected function _initEnvironment()
    {
        $this->setErrorHandler(self::DEFAULT_ERROR_HANDLER);
        //Sets the default timezone used by all date/time functions in a script
        //Mage_Core_Model_Locale::DEFAULT_TIMEZONE = 'UTC' by default
        date_default_timezone_set(Mage_Core_Model_Locale::DEFAULT_TIMEZONE);
        return $this;
    }

Oh look, Magento sets script’s time relative to server time, converted to UTC. So each Magento store (database-wise) is synced to UTC.

Someone might ask why should we do this, and why wouldn’t we just set it to timezone that suits our needs. Well, it’s a good question – but the answer is better:

If you have your Magento installation on cloud for example, or even on come cluster, it will help with cross-server synchronization as “UTC stands for Coordinated Universal Time” and pretty much each configuration of each server considers that as a default, if not set otherwise.

Now, this explains how Magento gets / calculates timezone.

Moving on to

Magento Per Store Timezone Settings

If you navigate to “System->Configuration->General->Locale Options->Timezone” in Admin area of Magento, you’ll see that you can change Timezone for each Website you have. This way you get a way to have stores for each part of the world set with correct timezone.

Here’s a method used to fetch current time per store (Zend_Date instance):

    //File: "app/code/core/Mage/Core/Model/Locale.php"
    /**
     * Create Zend_Date object with date converted to store timezone and store Locale
     *
     * @param   mixed $store Information about store
     * @param   string|integer|Zend_Date|array|null $date date in UTC
     * @param   boolean $includeTime flag for including time to date
     * @return  Zend_Date
     */
    public function storeDate($store=null, $date=null, $includeTime=false)
    {
        $timezone = Mage::app()->getStore($store)->getConfig(self::XML_PATH_DEFAULT_TIMEZONE);
        $date = new Zend_Date($date, null, $this->getLocale());
        $date->setTimezone($timezone);
        if (!$includeTime) {
            $date->setHour(0)
                ->setMinute(0)
                ->setSecond(0);
        }
        return $date;
    }

Or if you need string representation, just use this:

    /**
    * Date and time format codes
    */
 
    /*
    const FORMAT_TYPE_FULL  = 'full';
    const FORMAT_TYPE_LONG  = 'long';
    const FORMAT_TYPE_MEDIUM= 'medium';
    const FORMAT_TYPE_SHORT = 'short';
    */
 
    Mage::helper('core')->formatTime($time=null, $format='short', $showDate=false);
 
    //Or "$this->helper('core')->formatTime($time=null, $format='short', $showDate=false);"

Front-end and Back-end views

On back-end you’ll always see times shown as configured on “System->Configuration->General->Locale Options->Timezone” for “Default” scope (usually set to Admin’s timezone). Example where you can see tis is on order views page.

And each time shown on front-end will be shown as configured on same place, but on website scope. Although there aren’t may places on front-end where exact time is shown, it’s important for dates (if you have limited time offers for example), or for Cron tasks set for specific stores (newsletter sending etc.).

Conclusion

As I’ve mentioned at the very beginning of this article. This all applies to single-store setup as well, but it is of a HUGE importance if you have multi-store setup. If it’s set incorrectly it might lead to some “ghost bugs”, and it’s quite hard to trace – especially if you (developer) don’t understand how exactly it works.

I hope I’ve cleared few things here. And thanks for reading!


P.S.
If you notice some strange behavior of time related stuff, please submit it here to comments!

Interested in hiring us?

Have a chat with us. You would be surprised how small changes can make your business even more successful.


4 comments

  1. I am having the same issue with my custom dashboard. Why would they not at least store the local timezone date in the DB. Please help us Inchoo this is taking away from my sleep :).

  2. Hi there.
    I’ve added a new datetime column at sales_flat_order, but everytime a new registry is inserted, it is shown 3 hours less than the real time.
    So, when seeing my sales order grid the time appears wrong, but when see it on the sales order view on html, getting the value from db, it looks good.
    =/
    My timezone at the config is ok, and also at php.ini.
    Do you know what it could be wrong?

    Thanks

    1. I guess this is because Magento messes up its own timezone behaviour. I am currently fighting against the Log Module. Sometimes the now() $this->setData('last_visit_at', now()); method is used and sometime the GMT $data = new Varien_Object(array(
      'quote_id' => (int) $visitor->getQuoteId(),
      'visitor_id' => (int) $visitor->getId(),
      'created_at' => Mage::getSingleton('core/date')->gmtDate()
      ));
      is used. And overall Magento stores everthing as TIMESTAMP without checking the mysql timezone settings. So we have a UTC time that goes to a timestamp (thats internally is UTC) that will be treated as local time by mysql. Why could not simply use sql NOW() for that? MySQL stores as UTC and everthing would be fine. If Magento needs UTC it can load via SQL: CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime`.

      I am really pissed of because a lot of statistics is simply garbarge.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.