SitePoint Sponsor

User Tag List

Results 1 to 5 of 5
  1. #1
    SitePoint Evangelist AlienDev's Avatar
    Join Date
    Feb 2007
    Location
    UK
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Displaying time as local to a user

    At sign-up, I collect the user's country and set the nearest timezone (they can change this if it is incorrect).

    I want to display time local to a user. Every is stored in the database as UTC (in the code below, 'Zulu' = UTC), and that zone is set at the start of every run.

    Some Googling didn't really help (e.g. Dan Grossman's question a few years ago had the same problem).

    What I have: (you can re-use this if you want)

    Code php:
     
    class TimezoneTable extends Singleton
    {
        private $zones;
     
     
        protected function __construct()
        {
            $dir = sfConfig::get('sf_data_dir');
            $dataFile = $dir.'/timezones';
            $timerFile = $dir.'/timezones-timer';
            $logFile = $dir.'/timezones-log';
     
     
            // See if the cache is less than a day old.
            if (is_file($timerFile))
            {
                $lastTime = (integer) file_get_contents($timerFile);
                if ($lastTime > (time() - 89000))
                {
                    // Cache is fresh.
                    $this->zones = unserialize(file_get_contents($dataFile));
                    return;
                }
            }
     
     
            $vals = json_decode(file_get_contents('http://api.coronatus.com/clock/read'), true);
            $zones = array();
            foreach ($vals as $val)
            {
                $zones[$val['timezone']] = $val['utc_offset'];
            }
     
            file_put_contents($dataFile, serialize($zones));
            file_put_contents($timerFile, time());
            file_put_contents($logFile, '['.date('Y-m-d H:i:i')."] Refreshed\n", FILE_APPEND);
     
            $this->zones = $zones;
        }
     
     
        public function getAllNames()
        {
            return array_keys($this->zones);
        }
     
     
        /**
         * Return the number of hours $timezone is off of UTC.
         *
         * @param string $timezone
         * @return integer  Number of hours.
         */
        public function getOffsetInHours($timezone)
        {
            if (!isset($this->zones[$timezone]))
            {
                throw new InvalidArgumentException('Timezone not known: '.$timezone);
            }
     
            return $this->zones[$timezone];
        }
    }
     
     
     
     
    /**
     * Try to change any string/unix-timestamp/DateTime-object to a unix timestamp.
     *
     * Timezones are ignored.
     *
     * @param mixed $time Any type of date-time, in Zulu
     * @return string Seconds since Epoch, in Zulu
     */
    function convert_to_seconds($time)
    {
        if ($time instanceof DateTime)
        {
            $seconds = $time->format('U');
        }
        // Already in seconds.
        elseif (ctype_digit($time) && (10 === strlen($time)))
        {
            $seconds = $time;
        }
        // YYYY-MM-DD HH:MM:SS
        elseif (1 === preg_match('/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/', $time))
        {
            $seconds = strtotime($time);
        }
        else
        {
            throw new InvalidArgumentException(
                'Time couldn\'t be interpreted: '.Coronatus_Util::getArgDescription($time)
            );
        }
     
        return $seconds;
    }
     
     
    /**
     * Describe the difference in time between $then and now.
     *
     * Timezones are irrelevant to this function.
     *
     * @param mixed $then A zulu time.
     * @return string
     */
    function how_long_ago($then)
    {
        $diff = time() - convert_to_seconds($then);
     
        if ($diff < 0)
        {
            throw new InvalidArgumentException('Time is in the future: '.$then);
        }
     
        return Coronatus_UtilDateTime::timespan($diff).' ago';
    }
     
     
    /**
     * Use this function for every date/time displayed.
     *
     * It alters the time to be in the actor's timezone.
     *
     * @param string $format How to format the output.
     * @param mixed $time The Zulu time to convert.
     * @return string
     */
    function display_time($format, $time)
    {
        switch (strtolower($format))
        {
            case 'mysql':
                $format = 'Y-m-d H:i:s';
                break;
            case 'date':
                $format = 'jS F Y';
                break;
            case 'datetime':
                $format = 'jS F Y, H:i';
                break;
        }
     
        if (!isset($userOffset))
        {
            static $userOffset;
            $userOffset = sfContext::getInstance()->getUser()->getTzSecondOffset();
        }
     
        return date($format, convert_to_seconds($time) + $userOffset);
    }

    display_time() does the showing.

    Is there a better way to do this, that doesn't involve changing PHP's TZ multiple times?

    Thanks
    Me on StackOverflow | Blog & personal website.

    I mostly use: PHP, Java, JavaScript, Android.

  2. #2
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    PHP 5.3 added new date and time zone classes that weren't available when I asked that question in 2007. If you have access to PHP 5.3, you can do timezone conversion by name without doing any of the computations yourself, or changing the timezone setting for the whole interpreter.

    Look at the first comment here for an example:
    http://www.php.net/manual/en/datetime.settimezone.php

    I did end up doing some ugly stuff with date_default_timezone_set() all over the place back then, but don't have to anymore.

  3. #3
    SitePoint Evangelist AlienDev's Avatar
    Join Date
    Feb 2007
    Location
    UK
    Posts
    591
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dan Grossman View Post
    PHP 5.3 added new date and time zone classes that weren't available when I asked that question in 2007. If you have access to PHP 5.3, you can do timezone conversion by name without doing any of the computations yourself, or changing the timezone setting for the whole interpreter.

    Look at the first comment here for an example:
    http://www.php.net/manual/en/datetime.settimezone.php
    I like that! Sadly I don't have PHP5.3 in production, only development... I guess it's that time again to email my host and ask to move server ^^
    Me on StackOverflow | Blog & personal website.

    I mostly use: PHP, Java, JavaScript, Android.

  4. #4
    rajug.replace('Raju Gautam'); bronze trophy Raju Gautam's Avatar
    Join Date
    Oct 2006
    Location
    Kathmandu, Nepal
    Posts
    4,013
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Dan Grossman View Post
    I did end up doing some ugly stuff with date_default_timezone_set() all over the place back then, but don't have to anymore.
    It cannot be said as 'ugly' way Dan because those stuffs are the only ways to do with prior to PHP 5.3. I have also done in that way for several projects like;
    - let user to select their timezone while registering/signing up.
    - save that in the database
    - set that timezone string with put_env or date_default_timezone_set() at the top of the page/script after the user logs in

    Thank you PHP team for adding new feature to achieve the goal. Hope all the hosting servers will upgrade PHP version to 5.3 very soon.
    Mistakes are proof that you are trying.....
    ------------------------------------------------------------------------
    PSD to HTML - SlicingArt.com | Personal Blog | ZCE - PHP 5

  5. #5
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Unless I missed something, I believe you should be using gmdate() and manually adjusting for dst. date() will adjust for php's timezone offset and dst flag. If php's timezone is gmt, you get lucky and it "works anyway" because there's no dst. Then you can put that is_dst flag to use from your json data.


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •