Skip to content

Instantly share code, notes, and snippets.

@matthewd
Created December 2, 2010 08:56
Show Gist options
  • Save matthewd/725009 to your computer and use it in GitHub Desktop.
Save matthewd/725009 to your computer and use it in GitHub Desktop.
From 2621822b8a88c438de81c221a6a2d7f65c98c558 Mon Sep 17 00:00:00 2001
From: Matthew Draper <matthew@trebex.net>
Date: Thu, 2 Dec 2010 20:51:43 +1030
Subject: [PATCH] Consider DST status of the given date, not today.
In passing, use the thread-safe time.h functions, and don't assume
tm_isdst will always be 0 or 1.
---
.../data_objects/spec/typecast/datetime_spec.rb | 26 +++++++++++++
do_derby/spec/spec_helper.rb | 4 ++
do_h2/spec/spec_helper.rb | 4 ++
do_hsqldb/spec/spec_helper.rb | 4 ++
do_mysql/ext/do_mysql/do_mysql.c | 40 ++++++++++++++-----
do_mysql/spec/spec_helper.rb | 4 ++
do_oracle/spec/spec_helper.rb | 4 ++
do_postgres/ext/do_postgres/do_postgres.c | 40 ++++++++++++++-----
do_postgres/spec/spec_helper.rb | 4 ++
do_sqlite3/ext/do_sqlite3/do_sqlite3.c | 40 ++++++++++++++-----
do_sqlite3/spec/spec_helper.rb | 4 ++
do_sqlserver/spec/spec_helper.rb | 4 ++
12 files changed, 145 insertions(+), 33 deletions(-)
diff --git a/data_objects/lib/data_objects/spec/typecast/datetime_spec.rb b/data_objects/lib/data_objects/spec/typecast/datetime_spec.rb
index 442ff9a..bb1f63a 100644
--- a/data_objects/lib/data_objects/spec/typecast/datetime_spec.rb
+++ b/data_objects/lib/data_objects/spec/typecast/datetime_spec.rb
@@ -63,6 +63,32 @@ shared 'supporting DateTime' do
end
+ describe 'with manual typecasting a datetime column' do
+
+ before do
+ @command = @connection.create_command("SELECT release_datetime FROM widgets WHERE id = ? OR id = ? ORDER BY id")
+ @command.set_types(DateTime)
+ @reader = @command.execute_reader(1, 10)
+ @reader.next!
+ @feb_row = @reader.values
+ @reader.next!
+ @jul_row = @reader.values
+ end
+
+ after do
+ @reader.close
+ end
+
+ it 'should return the correct offset in Feb' do
+ (@feb_row.first.offset * 86400).to_i.should == Time.local(2008, 2, 14, 0, 31, 12).utc_offset
+ end
+
+ it 'should return the correct offset in Jul' do
+ (@jul_row.first.offset * 86400).to_i.should == Time.local(2008, 7, 14, 0, 31, 12).utc_offset
+ end
+
+ end
+
end
describe 'writing an DateTime' do
diff --git a/do_derby/spec/spec_helper.rb b/do_derby/spec/spec_helper.rb
index 1e83bb1..3d38f42 100644
--- a/do_derby/spec/spec_helper.rb
+++ b/do_derby/spec/spec_helper.rb
@@ -176,6 +176,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
diff --git a/do_h2/spec/spec_helper.rb b/do_h2/spec/spec_helper.rb
index 8abdbe8..f886e4b 100644
--- a/do_h2/spec/spec_helper.rb
+++ b/do_h2/spec/spec_helper.rb
@@ -155,6 +155,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
diff --git a/do_hsqldb/spec/spec_helper.rb b/do_hsqldb/spec/spec_helper.rb
index ce09c13..601f16d 100644
--- a/do_hsqldb/spec/spec_helper.rb
+++ b/do_hsqldb/spec/spec_helper.rb
@@ -154,6 +154,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
## TODO: change the hexadecimal examples
conn.close
end
diff --git a/do_mysql/ext/do_mysql/do_mysql.c b/do_mysql/ext/do_mysql/do_mysql.c
index 92fe5b3..232437b 100755
--- a/do_mysql/ext/do_mysql/do_mysql.c
+++ b/do_mysql/ext/do_mysql/do_mysql.c
@@ -230,10 +230,10 @@ static VALUE parse_date_time(const char *date) {
time_t gmt_offset;
- int is_dst;
+ int dst_adjustment;
time_t rawtime;
- struct tm * timeinfo;
+ struct tm timeinfo;
int tokens_read, max_tokens;
@@ -267,22 +267,40 @@ static VALUE parse_date_time(const char *date) {
}
// We read the Date and Time, default to the current locale's offset
+ tzset();
+
// Get localtime
time(&rawtime);
- timeinfo = localtime(&rawtime);
+ localtime_r(&rawtime, &timeinfo);
+
+ timeinfo.tm_sec = sec;
+ timeinfo.tm_min = min;
+ timeinfo.tm_hour = hour;
+ timeinfo.tm_mday = day;
+ timeinfo.tm_mon = month;
+ timeinfo.tm_year = year - 1900;
+ timeinfo.tm_isdst = -1;
+
+ // Update tm_isdst
+ mktime(&timeinfo);
- is_dst = timeinfo->tm_isdst * 3600;
+ if (timeinfo.tm_isdst) {
+ dst_adjustment = 3600;
+ } else {
+ dst_adjustment = 0;
+ }
// Reset to GM Time
- timeinfo = gmtime(&rawtime);
+ gmtime_r(&rawtime, &timeinfo);
- gmt_offset = mktime(timeinfo) - rawtime;
+ gmt_offset = rawtime - mktime(&timeinfo);
- if ( is_dst > 0 )
- gmt_offset -= is_dst;
+ if (dst_adjustment) {
+ gmt_offset += dst_adjustment;
+ }
- hour_offset = -((int)gmt_offset / 3600);
- minute_offset = -((int)gmt_offset % 3600 / 60);
+ hour_offset = ((int)gmt_offset / 3600);
+ minute_offset = ((int)gmt_offset % 3600 / 60);
} else {
// Something went terribly wrong
diff --git a/do_mysql/spec/spec_helper.rb b/do_mysql/spec/spec_helper.rb
index d4615c0..e23b37c 100644
--- a/do_mysql/spec/spec_helper.rb
+++ b/do_mysql/spec/spec_helper.rb
@@ -141,6 +141,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
diff --git a/do_oracle/spec/spec_helper.rb b/do_oracle/spec/spec_helper.rb
index 0f4586f..07246cc 100644
--- a/do_oracle/spec/spec_helper.rb
+++ b/do_oracle/spec/spec_helper.rb
@@ -181,6 +181,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
$test_environment_setup_done = true
end
diff --git a/do_postgres/ext/do_postgres/do_postgres.c b/do_postgres/ext/do_postgres/do_postgres.c
index ea77885..f5d3901 100755
--- a/do_postgres/ext/do_postgres/do_postgres.c
+++ b/do_postgres/ext/do_postgres/do_postgres.c
@@ -201,10 +201,10 @@ static VALUE parse_date_time(const char *date) {
do_int64 num, den;
long int gmt_offset;
- int is_dst;
+ int dst_adjustment;
time_t rawtime;
- struct tm * timeinfo;
+ struct tm timeinfo;
int tokens_read, max_tokens;
@@ -234,22 +234,40 @@ static VALUE parse_date_time(const char *date) {
}
// We read the Date and Time, default to the current locale's offset
+ tzset();
+
// Get localtime
time(&rawtime);
- timeinfo = localtime(&rawtime);
+ localtime_r(&rawtime, &timeinfo);
+
+ timeinfo.tm_sec = sec;
+ timeinfo.tm_min = min;
+ timeinfo.tm_hour = hour;
+ timeinfo.tm_mday = day;
+ timeinfo.tm_mon = month;
+ timeinfo.tm_year = year - 1900;
+ timeinfo.tm_isdst = -1;
+
+ // Update tm_isdst
+ mktime(&timeinfo);
- is_dst = timeinfo->tm_isdst * 3600;
+ if (timeinfo.tm_isdst) {
+ dst_adjustment = 3600;
+ } else {
+ dst_adjustment = 0;
+ }
// Reset to GM Time
- timeinfo = gmtime(&rawtime);
+ gmtime_r(&rawtime, &timeinfo);
- gmt_offset = mktime(timeinfo) - rawtime;
+ gmt_offset = rawtime - mktime(&timeinfo);
- if ( is_dst > 0 )
- gmt_offset -= is_dst;
+ if (dst_adjustment) {
+ gmt_offset += dst_adjustment;
+ }
- hour_offset = -((int)gmt_offset / 3600);
- minute_offset = -((int)gmt_offset % 3600 / 60);
+ hour_offset = ((int)gmt_offset / 3600);
+ minute_offset = ((int)gmt_offset % 3600 / 60);
} else {
// Something went terribly wrong
diff --git a/do_postgres/spec/spec_helper.rb b/do_postgres/spec/spec_helper.rb
index 3f657bd..8067863 100644
--- a/do_postgres/spec/spec_helper.rb
+++ b/do_postgres/spec/spec_helper.rb
@@ -139,6 +139,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
diff --git a/do_sqlite3/ext/do_sqlite3/do_sqlite3.c b/do_sqlite3/ext/do_sqlite3/do_sqlite3.c
index 7fb7964..18ef604 100755
--- a/do_sqlite3/ext/do_sqlite3/do_sqlite3.c
+++ b/do_sqlite3/ext/do_sqlite3/do_sqlite3.c
@@ -142,10 +142,10 @@ static VALUE parse_date_time(char *date) {
do_int64 num, den;
long int gmt_offset;
- int is_dst;
+ int dst_adjustment;
time_t rawtime;
- struct tm * timeinfo;
+ struct tm timeinfo;
int tokens_read, max_tokens;
@@ -179,22 +179,40 @@ static VALUE parse_date_time(char *date) {
}
// We read the Date and Time, default to the current locale's offset
+ tzset();
+
// Get localtime
time(&rawtime);
- timeinfo = localtime(&rawtime);
+ localtime_r(&rawtime, &timeinfo);
+
+ timeinfo.tm_sec = sec;
+ timeinfo.tm_min = min;
+ timeinfo.tm_hour = hour;
+ timeinfo.tm_mday = day;
+ timeinfo.tm_mon = month;
+ timeinfo.tm_year = year - 1900;
+ timeinfo.tm_isdst = -1;
+
+ // Update tm_isdst
+ mktime(&timeinfo);
- is_dst = timeinfo->tm_isdst * 3600;
+ if (timeinfo.tm_isdst) {
+ dst_adjustment = 3600;
+ } else {
+ dst_adjustment = 0;
+ }
// Reset to GM Time
- timeinfo = gmtime(&rawtime);
+ gmtime_r(&rawtime, &timeinfo);
- gmt_offset = mktime(timeinfo) - rawtime;
+ gmt_offset = rawtime - mktime(&timeinfo);
- if ( is_dst > 0 )
- gmt_offset -= is_dst;
+ if (dst_adjustment) {
+ gmt_offset += dst_adjustment;
+ }
- hour_offset = -((int)gmt_offset / 3600);
- minute_offset = -((int)gmt_offset % 3600 / 60);
+ hour_offset = ((int)gmt_offset / 3600);
+ minute_offset = ((int)gmt_offset % 3600 / 60);
} else {
// Something went terribly wrong
diff --git a/do_sqlite3/spec/spec_helper.rb b/do_sqlite3/spec/spec_helper.rb
index 1d9694c..0777d31 100644
--- a/do_sqlite3/spec/spec_helper.rb
+++ b/do_sqlite3/spec/spec_helper.rb
@@ -131,6 +131,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
diff --git a/do_sqlserver/spec/spec_helper.rb b/do_sqlserver/spec/spec_helper.rb
index 8b30cb2..18514c0 100644
--- a/do_sqlserver/spec/spec_helper.rb
+++ b/do_sqlserver/spec/spec_helper.rb
@@ -138,6 +138,10 @@ module DataObjectsSpecHelpers
update widgets set release_timestamp = NULL where id = 9
EOF
+ conn.create_command(<<-EOF).execute_non_query
+ update widgets set release_datetime = '2008-07-14 00:31:12' where id = 10
+ EOF
+
conn.close
end
--
1.7.2.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment