我们最近切换到一个RDS实例,注意到我们的一堆数据库任务比需要的时间提前了4个小时被触发。经过进一步调查,问题是由RDS实例上的默认时区设置(UTC(引起的。由于此设置无法更改,我们希望在使用此数据库实例的所有应用程序中全局解决代码级别的问题。我试图通过使用将我创建的数据库实例上的时区设置为"美国/东方">
set GLOBAL time_zone = 'US/Eastern'" OR
set time_zone = 'US/Eastern'"
但这会产生一个错误"数据库错误:未知或不正确的时区:"美国/东方">
你认为我在这里做错了什么?有人使用过其他解决方案吗?
不幸的是,无法在RDS DB参数组中设置default_timezone,因此您的尝试已经是正确的方向。
$ rds-describe-db-parameters default | grep "time_zone"
DBPARAMETER default_time_zone engine-default string static false
要通过set global设置全局值,您需要拥有SUPER权限,而该权限不是RDS用户授予的。
设置时区的唯一方法是基于每个连接的
mysql> SET time_zone = timezone;
在我的机器上,我成功地尝试了美国/东方,但我有相当老的一代在运行。
要确定您可用的时区,请登录您的盒子
mysql -h yourboxhost.rds.amazonaws.com -u <youruser> -p
和类型
mysql> SELECT * FROM mysql.time_zone_name;
您应该得到一个已安装的有效时区名称列表,您可以在实例上设置这些名称
+----------------------------------------+--------------+
| Name | Time_zone_id |
+----------------------------------------+--------------+
| Africa/Abidjan | 1 |
| Africa/Accra | 2 |
| Africa/Addis_Ababa | 3 |
| Africa/Algiers | 4 |
| Africa/Asmara | 5 |
| Africa/Asmera | 6 |
| Africa/Bamako | 7 |
| Africa/Bangui | 8 |
| Africa/Banjul | 9 |
| Africa/Bissau | 10 |
| Africa/Blantyre | 11 |
| Africa/Brazzaville | 12 |
| Africa/Bujumbura | 13 |
| Africa/Cairo | 14 |
etc...
每次连接到数据库服务器时,您都必须设置时区
例如,如果您使用php-Mysqli扩展,则可以执行此
$mysqli = mysqli_init();
mysqli_options($mysqli,MYSQLI_INIT_COMMAND,"SET time_zone = 'Africa/Brazzaville'" );
mysqli_real_connect($mysqli,$host, $user, $pass,$dbName) or die ('Unable to connect');
否则,只需在连接到数据库后立即手动执行SET time_zone = '<YOUR_DESIRED_TIMEZONE>'
查询即可。
RDS数据库实例的时区设置现在可以修改:https://aws.amazon.com/de/premiumsupport/knowledge-center/rds-change-time-zone/
我做了以下步骤,这样我就可以更改时区
登录RDS,新建参数组。
编辑新创建的参数组
设置时区Ex:亚洲/加尔各答和保存更改
修改RDS实例,将DB的参数组更改为新建的参数组
保存并重新启动RDS实例
tldr;
创建一个所有用户都有EXECUTE访问权限的"共享"架构,创建一个修改会话时区的SPROC,并修改init_connect MySQL参数以调用它。
正如Ryan Weir在一个重复问题的精彩回答中指出的那样,如果可能的话,这可能应该避免。然而,如果你和我一样,为了方便和理智而想要实现它,那么我采用了Ryan的解决方案,并进行了一些修改。
如果您在MySQL中设置了具有不同权限的多个用户,那么简单地将存储过程放在MySQL模式中可能会出现问题。为了解决这个问题,我创建了一个名为"shared"的新架构,并允许我的所有用户EXECUTE访问该架构。然后我创建了以下存储过程。
DROP PROCEDURE IF EXISTS shared.store_time_zone;
CREATE PROCEDURE shared.`store_time_zone`()
IF NOT (POSITION('rdsadmin@' IN CURRENT_USER()) = 1) THEN
SET SESSION time_zone = 'US/Pacific';
END IF;
我更喜欢设置"US/Pacific"来处理夏令时,但您应该对此进行测试,以确保您的MySQL实例首先识别它。只需执行以下查询SET SESSION time_zone = 'US/Pacific';
即可确保其正常工作。要查找您的时区,请执行SELECT * FROM mysql.time_zone_name;
在这一点上,我建议在修改参数组和潜在的破坏一切之前测试权限。只需连接到DB(最好与具有低级别权限和/或常用权限的用户连接(并执行以下查询。
CALL shared.store_time_zone;
select now();
希望你没有犯任何错误,正确的时间出现了。
接下来,您需要修改RDS实例正在使用的DB参数组中的init_connect参数。您可以通过API或命令行实用程序在RDS web控制台中执行此操作。如果你使用命令行,它会看起来像这样:
$ rds-modify-db-parameter-group PARAMGROUP --parameters "name=init_connect, value='CALL shared.store_time_zone', method=immediate"
如果您通过web控制台执行此操作,那么您只需要更改init_connect的值。
CALL shared.store_time_zone
在web控制台中返回您的RDS实例,并将详细信息窗格向下滚动到DB参数组。它应该说像(应用(或(同步(。一旦它(同步(,就去测试所有东西,以确保没有问题。
如果此时遇到问题,需要回滚,那么我建议将init_connect值设置为无害的值,例如:
SET SESSION time_zone = '-00:00';
将其设置回空白是不可能从web控制台完成的。有关为什么不能恢复DB参数的空值的更多详细信息,请参阅此线程
@Thomas Paine的解决方案对我有效,只是我必须使用user()
而不是current_user()
,因为在init_connect
current_user((的上下文中返回主RDS用户。(我所说的master并不是指rdsadmin,它是真正的根用户,而是用拥有最多权限的DB实例创建的用户。(