首页 > 其他 > 详细

时区问题

时间:2018-12-14 00:07:36      阅读:164      评论:0      收藏:0      [点我收藏+]

CST时区名为CST的时区是一个很混乱的时区,有四种含义:

-美国中部时间CentralStandardTime(USA)UTC-06:00

-澳大利亚中部时间CentralStandardTime(Australia)UTC+09:30

-中国标准时ChinaStandardTimeUTC+08:00

-古巴标准时CubaStandar

 

可能存在mysql读取TimeStamp字段时区和java时区相差13小时的现象

其原因为:

public void configureTimezone() { 
String configuredTimeZoneOnServer = getServerVariable("time_zone"); 
if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) { 
configuredTimeZoneOnServer = getServerVariable("system_time_zone"); 

String canonicalTimezone = getPropertySet().getStringReadableProperty(PropertyDefinitions.PNAME_serverTimezone).getValue(); 
if (configuredTimeZoneOnServer != null) { 
// user can override this with driver properties, so don‘t detect if that‘s the case 
if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) { 
try { 
canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor()); 
} catch (IllegalArgumentException iae) { 
throw ExceptionFactory.createException(WrongArgumentException.class, iae.getMessage(), getExceptionInterceptor()); 



if (canonicalTimezone != null &;&; canonicalTimezone.length() > 0) { 
this.serverTimezoneTZ = TimeZone.getTimeZone(canonicalTimezone); 
// The Calendar class has the behavior of mapping unknown timezones to ‘GMT‘ instead of throwing an exception, so we must check for this... 
if (!canonicalTimezone.equalsIgnoreCase("GMT") 
&;&; this.serverTimezoneTZ.getID().equals("GMT")) { 
throw ... 


this.defaultTimeZone = this.serverTimezoneTZ; 

mysql> show variables like ‘%time_zone%‘; 
+------------------+--------+ 
| Variable_name| Value| 
+------------------+--------+ 
| system_time_zone | CST| 
| time_zone | SYSTEM | 
+------------------+--------+ 

当 JDBC 与 MySQL 开始建立连接时,会调用 `com.mysql.cj.jdbc.ConnectionImpl.initializePropsFromServer()` 获取服务器参数

代码中可见当 MySQL 的 `time_zone` 值为 `SYSTEM` 时,会取 `system_time_zone` 值作为协调时区。

若 `String configuredTimeZoneOnServer` 得到的是 `CST` 那么 Java 会误以为这是 `CST -0500`,

当服务器的时区为`CST +0800`时误认为java误认为时区为 `CST -0500`,导致java获取结果相差13小时。

`com.mysql.cj.jdbc.PreparedStatement.setTimestamp()`。 
```java 
public void setTimestamp(int parameterIndex, Timestamp x) throws java.sql.SQLException { 
synchronized (checkClosed().getConnectionMutex()) { 
setTimestampInternal(parameterIndex, x, this.session.getDefaultTimeZone()); 

这里的this.session.getDefaultTimeZone()是java默认得到的`CST -0500`,

private void setTimestampInternal(int parameterIndex, Timestamp x, TimeZone tz) throws SQLException {
    if (x == null) {
        setNull(parameterIndex, MysqlType.TIMESTAMP);
    } else {
        if (!this.sendFractionalSeconds.getValue()) {
            x = TimeUtil.truncateFractionalSeconds(x);
        }

        this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = MysqlType.TIMESTAMP;

        if (this.tsdf == null) {
            this.tsdf = new SimpleDateFormat("‘‘yyyy-MM-dd HH:mm:ss", Locale.US);
        }

        this.tsdf.setTimeZone(tz);

        StringBuffer buf = new StringBuffer();
        buf.append(this.tsdf.format(x));
        if (this.session.serverSupportsFracSecs()) {
            buf.append(‘.‘);
            buf.append(TimeUtil.formatNanos(x.getNanos(), true));
        }
        buf.append(‘\‘‘);

        setInternal(parameterIndex, buf.toString());
    }
}

此处 Timestamp 被转换为会话时区的时间字符串了

在此时jdbc误认为会话时区在 CST-5 

JBDC 把 Timestamp+0 转为 CST-5 的 String-5 

MySQL 认为会话时区在 CST+8,将 String-5 转为 Timestamp-13 

最终结果相差 13 个小时!如果处在冬令时还会相差 14 个小时! 

解决办法也很简单,明确指定 MySQL 数据库的时区,不使用引发误解的 `CST`: 

mysql> set global time_zone = ‘+08:00‘; 
Query OK, 0 rows affected (0.00 sec) 
mysql> set time_zone = ‘+08:00‘; 
Query OK, 0 rows affected (0.00 sec) 

或者修改 `my.cnf` 文件,在 `[mysqld]` 节下增加 `default-time-zone = ‘+08:00‘`。 
修改时区操作影响深远,需要重启 MySQL 服务器,建议在维护时间进行。

时区问题

原文:https://www.cnblogs.com/yizw/p/10117168.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!