Skip to content

Commit 3d52a93

Browse files
Merge pull request #9109 from jorisvandenbossche/sql-timestamp-object
SQL: fix type conversion for Timestamp object typed columns (GH9085)
2 parents 8b7f7af + 10f7bcb commit 3d52a93

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

doc/source/whatsnew/v0.16.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ Bug Fixes
5858

5959

6060

61+
- Fixed bug in ``to_sql`` when mapping a Timestamp object column (datetime
62+
column with timezone info) to the according sqlalchemy type (:issue:`9085`).
6163

6264

6365

pandas/io/sql.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ def _sqlalchemy_type(self, col):
911911
from sqlalchemy.types import (BigInteger, Float, Text, Boolean,
912912
DateTime, Date, Time)
913913

914-
if col_type == 'datetime64':
914+
if col_type == 'datetime64' or col_type == 'datetime':
915915
try:
916916
tz = col.tzinfo
917917
return DateTime(timezone=True)

pandas/io/tests/test_sql.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,15 @@ def _get_index_columns(self, tbl_name):
792792
ixs = [i['column_names'] for i in ixs]
793793
return ixs
794794

795+
def test_sqlalchemy_type_mapping(self):
796+
797+
# Test Timestamp objects (no datetime64 because of timezone) (GH9085)
798+
df = DataFrame({'time': to_datetime(['201412120154', '201412110254'],
799+
utc=True)})
800+
db = sql.SQLDatabase(self.conn)
801+
table = sql.SQLTable("test_type", db, frame=df)
802+
self.assertTrue(isinstance(table.table.c['time'].type, sqltypes.DateTime))
803+
795804

796805
class TestSQLiteFallbackApi(_TestSQLApi):
797806
"""
@@ -853,6 +862,24 @@ def test_uquery(self):
853862
rows = sql.uquery("SELECT * FROM iris LIMIT 1", con=self.conn)
854863
self.assertEqual(rows, -1)
855864

865+
def _get_sqlite_column_type(self, schema, column):
866+
867+
for col in schema.split('\n'):
868+
if col.split()[0].strip('[]') == column:
869+
return col.split()[1]
870+
raise ValueError('Column %s not found' % (column))
871+
872+
def test_sqlite_type_mapping(self):
873+
874+
# Test Timestamp objects (no datetime64 because of timezone) (GH9085)
875+
df = DataFrame({'time': to_datetime(['201412120154', '201412110254'],
876+
utc=True)})
877+
db = sql.SQLiteDatabase(self.conn, self.flavor)
878+
table = sql.SQLiteTable("test_type", db, frame=df)
879+
schema = table.sql_schema()
880+
self.assertEqual(self._get_sqlite_column_type(schema, 'time'),
881+
"TIMESTAMP")
882+
856883

857884
#------------------------------------------------------------------------------
858885
#--- Database flavor specific tests
@@ -1571,15 +1598,15 @@ def test_dtype(self):
15711598

15721599
# sqlite stores Boolean values as INTEGER
15731600
self.assertEqual(self._get_sqlite_column_type('dtype_test', 'B'), 'INTEGER')
1574-
1601+
15751602
self.assertEqual(self._get_sqlite_column_type('dtype_test2', 'B'), 'STRING')
15761603
self.assertRaises(ValueError, df.to_sql,
15771604
'error', self.conn, dtype={'B': bool})
15781605

15791606
def test_notnull_dtype(self):
15801607
if self.flavor == 'mysql':
15811608
raise nose.SkipTest('Not applicable to MySQL legacy')
1582-
1609+
15831610
cols = {'Bool': Series([True,None]),
15841611
'Date': Series([datetime(2012, 5, 1), None]),
15851612
'Int' : Series([1, None], dtype='object'),

0 commit comments

Comments
 (0)