-
Notifications
You must be signed in to change notification settings - Fork 74
The MySQL plugin compare server and client timezone #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thank you for the PR! Though |
@hito4t. Thank you for replying. It seems
I tried MySQL Server version: 5.0.95. It
|
I'm sorry, I've mistaken. In my environment (Windows 7 and MySQL 5.6), the string value returned by I could get right value by the following code. ResultSet rs = statement.executeQuery("SELECT @@system_time_zone"); if (rs.next()) { byte[] b = rs.getBytes(1); String tz = new String(b, "MS932"); } The result value was "東京 (標準時)" (Japanese). The value of |
OMG, we can't use I'm investigating an alternative idea. How about this? (need implement
I want to output "GMT-07:00".
|
Can you try the following SQL? select IF(timediff(now(),utc_timestamp())=0,'UTC',
IF(timediff(now(),utc_timestamp())>0,
CONCAT('GMT+',TIME_FORMAT(timediff(now(),utc_timestamp()),'%h:%m')),
CONCAT('GMT',TIME_FORMAT(timediff( now(), utc_timestamp()),'%h:%m')))) as offset; OR set @timediff = timediff(now(),utc_timestamp());
select IF(@timediff=0,'UTC',
IF(@timediff>0,
CONCAT('GMT+',TIME_FORMAT(@timediff,'%h:%m')),
CONCAT('GMT',TIME_FORMAT(@timediff,'%h:%m')))) as offset;
|
Please take a look again. I calculate GMT offset.
|
Both worked fine! I think SQL should return timezone offset as number and Java should convert it to timezone string because the timezone strings is interpreted in Java. |
@hito4t Thank you for your comment. How do you think this query?
Implementation Idea
Memo
|
@hito4t Please take a look again. I think I should seperate TimeZone getter (builder?) class like the following. public TimeZone MySQLTimeZoneBuilder.fromSystemConfig(Connection connection) throws SQLException;
public TimeZone MySQLTimeZoneBuilder.fromUTCOffsetSeconds(int offset); This is the sample output.
|
@hito4t, Please take a look again. You can change timezone like the following quickly.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hiroyuki-sato
Thank you!
Please see review comments.
// | ||
String query = "select TIME_TO_SEC(timediff(now(),utc_timestamp()));"; | ||
Statement stmt = connection.createStatement(); | ||
ResultSet rs = stmt.executeQuery(query); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Statement
and ResultSet
are not closed.
They should be closed in finally
clause.
Statement stmt = ... try { ... } finally { stmt.close(); }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add stmt.close
exception handling is still TODO.
ResultSet rs = stmt.executeQuery(query); | ||
|
||
if (rs.next()) { | ||
int offset_seconds = rs.getInt(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class names, method names and variable names (except for constant names) should be CamelCased in Java.
For example, offset_seconds
should be offsetSeconds
.
http://www.oracle.com/technetwork/java/codeconventions-135099.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable names use camel case like offsetSeconds
.
} | ||
} | ||
|
||
public static TimeZone fromGMTOffsetSeconds(int offset_seconds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change to private
.
int tz_min = abs_offset_sec % ONE_HOUR_SEC / ONE_MIN_SEC; | ||
String tz_name = String.format(Locale.ENGLISH, "GMT%s%02d:%02d", sign, tz_hour, tz_min); | ||
return TimeZone.getTimeZone(tz_name); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work for summer time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed on the Twitter, I used getDSTSavings
method like the below.
If this code is better,
I'll change this.
TimeZone clientTimeZone = TimeZone.getDefault();
Date today = new Date();
int clientOffset = clientTimeZone.getRawOffset();
if( clientTimeZone.inDaylightTime(today) ){
clientOffset += clientTimeZone.getDSTSavings();
}
TimeZone svr_tz = MySQLTimeZoneBuilder.fromSystemTimeZone(connection); | ||
|
||
String usr_tz_name = System.getProperty("user.timezone"); | ||
TimeZone usr_tz = TimeZone.getTimeZone(usr_tz_name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can get same value by TimeZone.getDefaultValue()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to TimeZone.getDefaultValue
.
// | ||
if( svr_tz.getRawOffset() != usr_tz.getRawOffset() ) { | ||
logger.warn(String.format(Locale.ENGLISH, | ||
"The server timezone offset(%s) and client timezone(%s) has different timezone offset. The plugin will fetch wrong datetime values.",svr_tz.getID(),usr_tz_name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about following message?
The client timezone(%s) is different from the server timezone(%s). ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to The client timezone(%s) is different from the server timezone(%s).
@@ -426,6 +426,8 @@ public TaskReport run(TaskSource taskSource, | |||
LastRecordStore lastRecordStore = null; | |||
|
|||
try (JdbcInputConnection con = newConnection(task)) { | |||
con.before_load(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newConnection
is called by AbstractJdbcInputPlugin#transaction
first, then called by AbstractJdbcInputPlugin#run
.
So we should check timezone in the transaction
method.
@Override public ConfigDiff transaction(ConfigSource config, InputPlugin.Control control) { ... Schema schema; try (JdbcInputConnection con = newConnection(task)) { // TODO incremental_columns is not set => get primary key schema = setupTask(con, task); } catch (SQLException ex) { throw Throwables.propagate(ex); } return buildNextConfigDiff(task, control.run(task.dump(), schema, 1)); }
Now setupTask
method is private
, but I think the method is appropriate to check timezone if it is changed to protected
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed setupTask to protect
and Override setupTask
like the below.
@Override
protected Schema setupTask(JdbcInputConnection con, PluginTask task) throws SQLException
{
MySQLInputConnection mySQLCon = (MySQLInputConnection)con;
mySQLCon.compareTimeZone();
return super.setupTask(con,task);
}
@hito4t Thank you for your comment. I wrote two implementations. |
@hiroyuki-sato |
Please take a look again. I implemented
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hiroyuki-sato
Thank you.
I have a few comments.
Please check them.
serverTimeZone = getServerTimeZone(); | ||
} | ||
catch (SQLException ex) { | ||
logger.error(String.format(Locale.ENGLISH, "SQLException raised %s", ex.toString())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be logger.warn
because it is not fatal even if timezone checking fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change logger.warn
.
return fromGMTOffsetSeconds(offsetSeconds); | ||
} | ||
else { | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If throwing SQLException
instead of returning null, the caller doesn't have to check null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw SQLException if timezone comparison query fail. Simplified codes.
@hito4t Thank you for reviewing. |
@hiroyuki-sato |
@hito4t Thank you for reviewing. |
@hiroyuki-sato |
@hito4t |
Thank you! |
@muga @hito4t
Reference implementation This comment.
The embulk-input-mysql to compare server and client timezone.
I would like to request comments about this changes.
Questions
before_load
method for executing timezone check SQL.select @@system_time_zone
for get server timezone.@@system_time_zone
parameter. (I'll comment later)getServerTimezoneTZ()
method. But It always returnsnull
System.getProperty("user.timezone");
sys_tz.hasSameRules(usr_tz)
.false
when I compareGMT+9
andJST
(See below)Same timezone
Difference timezone
Compare timezone