WeBid: Timezones with daylight savings time not calculated correctly

I'm currently using an open source application: WeBid (available here)

Here is the issue:

  • The user has a preferred timezone stored in DB
  • The site has a default timezone stored in DB
  • All db stored dates are stored at "GMT-0"
  • The application doesn't calculate the DST (Daylight Savings Time) correctly as it uses the following code:

    (includes/functions_global.php)

    $this->ctime = time() + (($this->SETTINGS['timecorrection'] + gmdate('I')) * 3600);
    $this->tdiff = ($this->SETTINGS['timecorrection'] + gmdate('I')) * 3600;
    

    gtpotyf explains:

    gmdate('I') -> Returns 1 if DST is active, 0 if not active. However since gmdate always uses GMT(+0) and that timezone has no DST it will always return 0.

    using date('I') instead of gmdate('I') would work better, but would still not be correct since it uses the timezone from the server and still not the users timezone.

    No final correction was adopted by WeBid's latest version, please help me resolve this issue.

    Source


    In order to sort out timezones properly you'll need to do a number of things.

    Set your server to UTC, so that PHP's time and date functions return a UTC timestamp. (In addition to associated functions such as strftime .

    Depending on your database, you can set its timezone to UTC as well. MySQL's documentation on the subject is here.

    You'll need to migrate the datetimes stored in there to UTC if they aren't already. (I'm not sure what you mean by GMT-0.)

    Let users choose a timezone in the format 'Europe/London' as supported by PHP's DateTimeZone class.

    Following some research, I put together the following array of timezones to present to users in a drop down box, as I didn't want duplicates (Amsterdam and Brussels are in the same timezone, for example.) I wouldn't claim it to be perfect though. Depending on your user base you may want to investigate certain timezones in more detail.

    $timezones = array(
            'Pacific/Midway' => '(UTC-11:00) Midway Island, Samoa',
            'Pacific/Honolulu' => '(UTC-10:00) Hawaii-Aleutian',
            'Pacific/Marquesas' => '(UTC-09:30) Marquesas Islands',
            'Pacific/Gambier' => '(UTC-09:00) Gambier Islands',
            'America/Anchorage' => '(UTC-09:00) Alaska',
            'America/Ensenada' => '(UTC-08:00) Tijuana, Baja California',
            'Etc/GMT+8' => '(UTC-08:00) Pitcairn Islands',
            'America/Los_Angeles' => '(UTC-08:00) Pacific Time (US & Canada)',
            'America/Denver' => '(UTC-07:00) Mountain Time (US & Canada)',
            'America/Chihuahua' => '(UTC-07:00) Chihuahua, La Paz, Mazatlan',
            'America/Dawson_Creek' => '(UTC-07:00) Arizona',
            'America/Belize' => '(UTC-06:00) Saskatchewan, Central America',
            'America/Cancun' => '(UTC-06:00) Guadalajara, Mexico City, Monterrey',
            'Chile/EasterIsland' => '(UTC-06:00) Easter Island',
            'America/Chicago' => '(UTC-06:00) Central Time (US & Canada)',
            'America/New_York' => '(UTC-05:00) Eastern Time (US & Canada)',
            'America/Havana' => '(UTC-05:00) Cuba',
            'America/Bogota' => '(UTC-05:00) Bogota, Lima, Quito, Rio Branco',
            'America/Caracas' => '(UTC-04:30) Caracas',
            'America/Santiago' => '(UTC-04:00) Santiago',
            'America/La_Paz' => '(UTC-04:00) La Paz',
            'Atlantic/Stanley' => '(UTC-04:00) Falkland Islands',
            'America/Campo_Grande' => '(UTC-04:00) Brazil',
            'America/Goose_Bay' => '(UTC-04:00) Atlantic Time (Goose Bay)',
            'America/Glace_Bay' => '(UTC-04:00) Atlantic Time (Canada)',
            'America/St_Johns' => '(UTC-03:30) Newfoundland',
            'America/Araguaina' => '(UTC-03:00) UTC-3',
            'America/Montevideo' => '(UTC-03:00) Montevideo',
            'America/Miquelon' => '(UTC-03:00) Miquelon, St. Pierre',
            'America/Godthab' => '(UTC-03:00) Greenland',
            'America/Argentina/Buenos_Aires' => '(UTC-03:00) Buenos Aires',
            'America/Sao_Paulo' => '(UTC-03:00) Brasilia',
            'America/Noronha' => '(UTC-02:00) Mid-Atlantic',
            'Atlantic/Cape_Verde' => '(UTC-01:00) Cape Verde Is.',
            'Atlantic/Azores' => '(UTC-01:00) Azores',
            'Europe/Dublin' => '(UTC) Irish Standard Time : Dublin',
            'Europe/Lisbon' => '(UTC) Western European Time : Lisbon',
            'Europe/London' => '(GMT) Greenwich Mean Time : London, Belfast',
            'Africa/Abidjan' => '(GMT) Monrovia, Reykjavik',
            'Europe/Amsterdam' => '(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna',
            'Europe/Belgrade' => '(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague',
            'Europe/Brussels' => '(UTC+01:00) Brussels, Copenhagen, Madrid, Paris',
            'Africa/Algiers' => '(UTC+01:00) West Central Africa',
            'Africa/Windhoek' => '(UTC+01:00) Windhoek',
            'Asia/Beirut' => '(UTC+02:00) Beirut',
            'Africa/Cairo' => '(UTC+02:00) Cairo',
            'Asia/Gaza' => '(UTC+02:00) Gaza',
            'Africa/Johannesburg' => '(UTC+02:00) Johannesburg, Harare, Pretoria',
            'Asia/Jerusalem' => '(UTC+02:00) Jerusalem',
            'Europe/Athens' => '(UTC+02:00) Athens',
            'Europe/Minsk' => '(UTC+02:00) Minsk',
            'Asia/Damascus' => '(UTC+02:00) Syria',
            'Europe/Moscow' => '(UTC+03:00) Moscow, St. Petersburg, Volgograd',
            'Africa/Addis_Ababa' => '(UTC+03:00) Nairobi',
            'Asia/Tehran' => '(UTC+03:30) Tehran',
            'Asia/Dubai' => '(UTC+04:00) Abu Dhabi, Muscat',
            'Asia/Yerevan' => '(UTC+04:00) Yerevan',
            'Asia/Kabul' => '(UTC+04:30) Kabul',
            'Asia/Yekaterinburg' => '(UTC+05:00) Ekaterinburg',
            'Asia/Tashkent' => '(UTC+05:00) Tashkent',
            'Asia/Kolkata' => '(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi',
            'Asia/Katmandu' => '(UTC+05:45) Kathmandu',
            'Asia/Dhaka' => '(UTC+06:00) Astana, Dhaka',
            'Asia/Novosibirsk' => '(UTC+06:00) Novosibirsk',
            'Asia/Rangoon' => '(UTC+06:30) Yangon (Rangoon)',
            'Asia/Bangkok' => '(UTC+07:00) Bangkok, Hanoi, Jakarta',
            'Asia/Krasnoyarsk' => '(UTC+07:00) Krasnoyarsk',
            'Asia/Hong_Kong' => '(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi',
            'Asia/Irkutsk' => '(UTC+08:00) Irkutsk, Ulaan Bataar',
            'Australia/Perth' => '(UTC+08:00) Perth',
            'Australia/Eucla' => '(UTC+08:45) Eucla',
            'Asia/Tokyo' => '(UTC+09:00) Osaka, Sapporo, Tokyo',
            'Asia/Seoul' => '(UTC+09:00) Seoul',
            'Asia/Yakutsk' => '(UTC+09:00) Yakutsk',
            'Australia/Adelaide' => '(UTC+09:30) Adelaide',
            'Australia/Darwin' => '(UTC+09:30) Darwin',
            'Australia/Sydney' => '(UTC+10:00) Sydney, Canberra, Brisbane',
            'Australia/Hobart' => '(UTC+10:00) Hobart',
            'Asia/Vladivostok' => '(UTC+10:00) Vladivostok',
            'Australia/Lord_Howe' => '(UTC+10:30) Lord Howe Island',
            'Etc/GMT-11' => '(UTC+11:00) Solomon Is., New Caledonia',
            'Asia/Magadan' => '(UTC+11:00) Magadan',
            'Pacific/Norfolk' => '(UTC+11:30) Norfolk Island',
            'Asia/Anadyr' => '(UTC+12:00) Anadyr, Kamchatka',
            'Pacific/Auckland' => '(UTC+12:00) Auckland, Wellington',
            'Etc/GMT-12' => '(UTC+12:00) Fiji, Kamchatka, Marshall Is.',
            'Pacific/Chatham' => '(UTC+12:45) Chatham Islands',
            'Pacific/Tongatapu' => '(UTC+13:00) Nuku Alofa',
            'Pacific/Kiritimati' => '(UTC+14:00) Kiritimati'
        );
    

    When dates come out of your database, they'll need to be converted from UTC into the user's timezone.

    $timestamp = time(); // or a timestamp from your DB
    
    # create server and user timezone objects
    $fromZone = new DateTimeZone('UTC'); // UTC
    $toZone = new DateTimeZone($userTimezone); // Europe/London, or whatever it happens to be
    
    $time = date('Y-m-d H:i:s', $timestamp);
    $dt = new DateTime($time, $fromZone);
    echo $dt->format('Y-m-d H:i:s'); // Still UTC
    
    $dt->setTimezone($toZone);
    echo $dt->format('Y-m-d H:i:s'); // Converted
    

    You'll need to go through the WeBid application and modify the appropriate parts to convert properly.


    So, using the above code, you'll need a couple of functions that do something like this:

    function getConvertedDateTimeObject($timestamp, $userTimezone){
        # create server and user timezone objects
        $fromZone = new DateTimeZone('UTC'); // UTC
        $toZone = new DateTimeZone($userTimezone); // Europe/London, or whatever it happens to be
    
        $time = date('Y-m-d H:i:s', $timestamp);
        $dt = new DateTime($time, $fromZone);
        $dt->setTimezone($toZone);
        return $dt;
    }
    
    function getUserTimestamp($timestamp, $userTimezone){
        $dt = getConvertedDateTimeObject($timestamp, $userTimezone);
        return $dt->getTimestamp();
    }
    
    function getUserOffset($timestamp, $userTimezone){
        $dt = getConvertedDateTimeObject($timestamp, $userTimezone);
        return $dt->getOffset();
    }
    

    Then in your class:

    $this->ctime = getUserTimestamp(time(), $userTimezone); // I assume you have access to the user's timezone?
    $this->tdiff = getUserOffset(time(), $userTimezone);
    

    Alternative solution to bcmcfc's answer (which pretty much says it all):

    Remove any timezone support from WeBid (at least disable any customization for it) and save everything as UTC (if it isn't already).

    Modify the interface to display dates and timestamps using Javascript. The browser will correctly transform a unix timestamp (don't forget to multiply by 1000, Javascript's Date expects milliseconds, instead of seconds as in PHP) based on the settings of the browser or operating system.

    For example, instead of outputting 2012-08-18 09:33:43, you would output <script>document.write(new Date(1345282423*1000).toString());</script> , where 1345282423 was obtained directly from the database, or using strtotime .

    You only need to alter the function which displays dates and timestamps, and disable timezone customization (forcing UTC/GMT) (don't forget date_default_timezone_set("UTC"); ).

    This seems trivial enough to me.

    链接地址: http://www.djcxy.com/p/29364.html

    上一篇: 如何获得其他时区的夏令时状态

    下一篇: WeBid:夏时制时区计算不正确