出于几个原因,您会犯这个错误。首先,可能的时区列表是有限的,所以去掉文本字段,只使用下拉菜单。
其次,您可以根据需要删除\重命名下拉列表中的项目,但请记住,由于您保存的是偏移量而不是 tz 名称,因此您永远无法返回(我的示例将向您展示如果您使用它的确切原因)。通常,最好存储名称而不是偏移量,以便您可以正确管理夏令时。你会注意到,要让这个系统正常工作,我需要调用 date('I') 来确定它是否是夏令时,这真的很糟糕(仅仅因为我的服务器 TZ 是夏令时并不意味着它在用户 TZ)。如果您保存了 TZ 名称,则可以将该逻辑推迟到 PHP 并使用它当前的任何偏移量。在这个简单的示例中,这似乎并不重要,但是如果您曾经尝试使用它存储该偏移量或计算未来\过去时间,那么您
另一件小事是将函数定义放在“if”语句中很奇怪。在 PHP 中,所有函数定义都是全局的,因此无论“if”条件是否为真,它都将可用。这样做的问题是你现在已经模糊了你的逻辑而没有收获。把它放在别处更容易、更清楚。
我已经重写了你的代码,让它变得更好一点,并在你使用它时实际工作,但我遗漏了一些细节(比如给 TZ 名称加上别名 [你似乎掌握了如何做] 和切换使用 TZ 名称而不是偏移量 [因为这可能会破坏您拥有的其他代码]),但我鼓励您也修复这些问题。
<?php
$tz_offset=0;
function get_offset_time($offset=0) {
$original=new DateTime("now");
$timezoneName=timezone_name_from_abbr("", $offset, date('I'));
if(!$timezoneName) die('ERROR: Unknown timezone \''.($offset/3600).'\'');
$oTZ=new DateTimezone($timezoneName);
$modified = $original->setTimezone($oTZ);
return $modified->format('Y-m-d H:i:s');
}
function get_timezone_offset($tz_name=null) {
if(!$tz_name) return 0; // If we have invalid data then return before we error
$tz=new DateTimeZone($tz_name);
$dt=new DateTime("now", $tz);
return $tz->getOffset($dt);
}
function enumerate_tz($tz_select=null) {
global $tz_offset;
$tz_ident=DateTimeZone::listIdentifiers();
foreach($tz_ident as $val) {
$tmp_offset=get_timezone_offset($val);
if($val=='UTC'||$tmp_offset)
echo '<option value="'.$val.'" '. ($tmp_offset==$tz_offset?' selected':''). '>'.
$val. ' [ '.($tmp_offset/3600).' ]'. // If you'd like to customize the viewable names for each TZ you may do so here
'</option>';
}
}
if(isset($_POST['tz_input']) && $_POST['tz_input']) {
$tz_input=htmlentities($_POST['tz_input']);
$tz_offset=get_timezone_offset($tz_input);
}
echo '<html><title>Timezone Select</title><body>'.
'<p>The current timezone offset is: '. ($tz_offset? ($tz_offset/3600): '0'). '</p>';
echo '<p>The current time is: '. get_offset_time($tz_offset). '</p>';
echo '<form method=post><select name=tz_input>';
enumerate_tz($tz_offset); // You'll notice that this list duplicates many of the timezones so that after selecting one the next
// time through it'll often select a different one. If you want to fix that you'll need to save the actually offset name instead of an offset.
echo '</select><input type=submit value=Search />'.
'</form></body>';
?>
编辑:要注意的另一件事是 PHP 的 timezone_name_from_abbr() 函数不完整。某些时区偏移不会返回 TimeZone 名称。你也必须考虑到这一点。例如,即使 PHP 理解“太平洋/中途”时区,它在进行反向查找时也无法找到它。我已经更新了代码,这样就不会再导致硬错误了。
EDIT2:我可以看到,除非有人向您展示如何使粪便发光,否则您不会快乐。干得好:
function getOptionDX($val, $option_array) {
if(!isset($option_array)||!is_array($option_array)||!count($option_array)>0||!$val) return null;
$val=htmlentities($val);
if(isset($option_array[$val])) return $val;
$new_val=array_search($val, $option_array);
return $new_val!==FALSE?$new_val: null;
}
将此添加到您的代码中,并将对 htmlentities 的调用替换为对此的调用:
$timezone2 = getOptionDX($_POST['timezone2'], $options);
最后,更改这一行:
if($timezone2) $offset = get_timezone_offset($timezone2);
如果用户手动输入 TZ 并且正确,则跳过 page2.php。如果您不想更改任何内容,这与可以给出的答案一样接近。事实是,您的逻辑首先是有缺陷的(这并不意味着是刺戳,但这是真的)。
EDIT3: IDK 出了什么问题,但这是我的完整代码清单,其中包含您要求的修复:
<?php
$offset=0; $timezone2='';
$options = array();
$options["Africa/Addis_Ababa"] = "Addis Ababa";
$options["Europe/London"] = "London";
$options["America/Chicago"] = "The Windy City";
function getOptionDX($val, $option_array) {
if(!isset($option_array)||!is_array($option_array)||!count($option_array)>0||!$val) return null;
$val=htmlentities(ucwords(strtolower($val)));
if(isset($option_array[$val])) return $val;
$new_val=array_search($val, $option_array);
return $new_val!==FALSE?$new_val: null;
}
function get_timezone_offset( $remote_tz ) {
$timezone2=new DateTimeZone($remote_tz);
$datetime2=new DateTime("now", $timezone2);
$offset=$timezone2->getOffset($datetime2);
return $offset;
}
if(isset($_POST['location'])) {
$addLoc=getOptionDX($_POST['location'], $options);
if(isset($addLoc)) $options[$addLoc]=$_POST['location'];
else header('Location: '. $_SERVER['SCRIPT_NAME']);
}
if(isset($_POST['timezone2'])) {
$timezone2=htmlentities($_POST['timezone2']);
$offset=get_timezone_offset($timezone2);
}
if(isset($_GET['page2'])) {
?>
<form method=post action=?page2>
<select name=timezone2>
<?php foreach($options as $key=>$value) echo "\t".'<option value="'. $key .'"'.(get_timezone_offset($key)==$offset?' selected':'').'>'.$value.'</option>'."\n"; ?>
</select>
<input type=hidden name=location type="text" value="<?php echo $_POST['location']; ?>"/>
</div>
<input type=submit value=Search>
</form>
<p>Current Offset: <?php echo $offset/3600; ?></p>
<p>Current Time: <?php echo gmdate('Y-m-d H:i:s'); ?> UTC</p>
<p>Current Time: <?php echo gmdate('Y-m-d H:i:s', time()+$offset).' '. $timezone2; ?> </p>
<?php
} else {
?>
<form method=post action=?page2>
<input name=location type=text value=""/>
<button type=submit>Search</button>
</form>
<?php
}
?>
我已经对此进行了测试并且知道它有效,如果这还不足以回答您的问题,那么我放弃了。我开始认为您真的想要一种方法来发明不存在的新时区。那是不可能的。您可以像我在这里所做的那样对已经存在的那些进行别名,这与您将得到的一样接近。从逻辑上讲,时区的范围只能从 -12:00 到 +12:00,并且几乎每个已知的时区都已经被考虑在内,所以如果这还不够,你真的别无选择,只能重新考虑你的设计。