关于php:WeBid:夏令时没有正确计算的时区

WeBid: Timezones with daylight savings time not calculated correctly

我当前使用的是开源应用程序:webid(可在此处获得)

问题是:

  • 用户具有存储在数据库中的首选时区
  • 站点具有存储在数据库中的默认时区
  • 所有数据库存储日期存储在"GMT-0"

应用程序没有正确计算DST(夏令时),因为它使用了以下代码:

(包括/函数global.php)

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

GTPotyf解释说:

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.

WebID的最新版本未采用最终更正,请帮助我解决此问题。

来源


为了正确地划分时区,你需要做很多事情。

将服务器设置为UTC,以便php的timedate函数返回一个UTC时间戳。(除相关功能外,如strftime

根据数据库的不同,也可以将其时区设置为UTC。这里是MySQL关于这个主题的文档。

如果存储在那里的日期时间尚未迁移到UTC,则需要将其迁移到UTC。(我不知道你所说的格林尼治标准时间0是什么意思。)

允许用户选择由PHP的datetimezone类支持的格式为"欧洲/伦敦"的时区。

经过一些研究,我把下面的时区数组放在一个下拉框中呈现给用户,因为我不想重复(例如,阿姆斯特丹和布鲁塞尔在同一时区),但我不认为它是完美的。根据用户群的不同,您可能需要更详细地调查某些时区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
$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'
    );

当日期从数据库中出来时,需要将它们从UTC转换为用户的时区。

1
2
3
4
5
6
7
8
9
10
11
12
$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

您需要浏览WebID应用程序并修改适当的部分以正确转换。

因此,使用上面的代码,您将需要一些这样的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}

然后在你的课堂上:

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


BCMCFC答案的替代解决方案(基本上都是这样说的):

从WebID中删除任何时区支持(至少禁用它的任何自定义),并将所有内容保存为UTC(如果还没有)。

使用javascript修改界面以显示日期和时间戳。浏览器将根据浏览器或操作系统的设置正确地转换一个Unix时间戳(不要忘记乘以1000,javascript的date期望毫秒,而不是php中的秒)。

例如,不输出2012-08-18 09:33:43,而是输出document.write(new Date(1345282423*1000).toString());,其中1345282423直接从数据库中获得,或者使用strtotime

您只需要更改显示日期和时间戳的功能,并禁用时区自定义(强制使用UTC/GMT)(不要忘记date_default_timezone_set("UTC");)。

这对我来说似乎微不足道。