Skip to content

Commit bc95629

Browse files
droratajorisvandenbossche
authored andcommitted
BUG: formating integers datetimes using sql GH17855 (pandas-dev#17882)
1 parent d421a09 commit bc95629

File tree

2 files changed

+45
-17
lines changed

2 files changed

+45
-17
lines changed

pandas/io/sql.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ def _handle_date_column(col, utc=None, format=None):
103103
if isinstance(format, dict):
104104
return to_datetime(col, errors='ignore', **format)
105105
else:
106-
if format in ['D', 's', 'ms', 'us', 'ns']:
107-
return to_datetime(col, errors='coerce', unit=format, utc=utc)
108-
elif (issubclass(col.dtype.type, np.floating) or
109-
issubclass(col.dtype.type, np.integer)):
110-
# parse dates as timestamp
111-
format = 's' if format is None else format
106+
# Allow passing of formatting string for integers
107+
# GH17855
108+
if format is None and (issubclass(col.dtype.type, np.floating) or
109+
issubclass(col.dtype.type, np.integer)):
110+
format = 's'
111+
if format in ['D', 'd', 'h', 'm', 's', 'ms', 'us', 'ns']:
112112
return to_datetime(col, errors='coerce', unit=format, utc=utc)
113113
elif is_datetime64tz_dtype(col):
114114
# coerce to UTC timezone

pandas/tests/io/test_sql.py

+39-11
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
"TextCol" TEXT,
8989
"DateCol" TEXT,
9090
"IntDateCol" INTEGER,
91+
"IntDateOnlyCol" INTEGER,
9192
"FloatCol" REAL,
9293
"IntCol" INTEGER,
9394
"BoolCol" INTEGER,
@@ -98,6 +99,7 @@
9899
`TextCol` TEXT,
99100
`DateCol` DATETIME,
100101
`IntDateCol` INTEGER,
102+
`IntDateOnlyCol` INTEGER,
101103
`FloatCol` DOUBLE,
102104
`IntCol` INTEGER,
103105
`BoolCol` BOOLEAN,
@@ -109,6 +111,7 @@
109111
"DateCol" TIMESTAMP,
110112
"DateColWithTz" TIMESTAMP WITH TIME ZONE,
111113
"IntDateCol" INTEGER,
114+
"IntDateOnlyCol" INTEGER,
112115
"FloatCol" DOUBLE PRECISION,
113116
"IntCol" INTEGER,
114117
"BoolCol" BOOLEAN,
@@ -120,31 +123,33 @@
120123
'sqlite': {
121124
'query': """
122125
INSERT INTO types_test_data
123-
VALUES(?, ?, ?, ?, ?, ?, ?, ?)
126+
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
124127
""",
125128
'fields': (
126-
'TextCol', 'DateCol', 'IntDateCol', 'FloatCol',
127-
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
129+
'TextCol', 'DateCol', 'IntDateCol', 'IntDateOnlyCol',
130+
'FloatCol', 'IntCol', 'BoolCol', 'IntColWithNull',
131+
'BoolColWithNull'
128132
)
129133
},
130134
'mysql': {
131135
'query': """
132136
INSERT INTO types_test_data
133-
VALUES("%s", %s, %s, %s, %s, %s, %s, %s)
137+
VALUES("%s", %s, %s, %s, %s, %s, %s, %s, %s)
134138
""",
135139
'fields': (
136-
'TextCol', 'DateCol', 'IntDateCol', 'FloatCol',
137-
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
140+
'TextCol', 'DateCol', 'IntDateCol', 'IntDateOnlyCol',
141+
'FloatCol', 'IntCol', 'BoolCol', 'IntColWithNull',
142+
'BoolColWithNull'
138143
)
139144
},
140145
'postgresql': {
141146
'query': """
142147
INSERT INTO types_test_data
143-
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s)
148+
VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
144149
""",
145150
'fields': (
146151
'TextCol', 'DateCol', 'DateColWithTz',
147-
'IntDateCol', 'FloatCol',
152+
'IntDateCol', 'IntDateOnlyCol', 'FloatCol',
148153
'IntCol', 'BoolCol', 'IntColWithNull', 'BoolColWithNull'
149154
)
150155
},
@@ -313,13 +318,13 @@ def _load_raw_sql(self):
313318
self.drop_table('types_test_data')
314319
self._get_exec().execute(SQL_STRINGS['create_test_types'][self.flavor])
315320
ins = SQL_STRINGS['insert_test_types'][self.flavor]
316-
317321
data = [
318322
{
319323
'TextCol': 'first',
320324
'DateCol': '2000-01-03 00:00:00',
321325
'DateColWithTz': '2000-01-01 00:00:00-08:00',
322326
'IntDateCol': 535852800,
327+
'IntDateOnlyCol': 20101010,
323328
'FloatCol': 10.10,
324329
'IntCol': 1,
325330
'BoolCol': False,
@@ -331,6 +336,7 @@ def _load_raw_sql(self):
331336
'DateCol': '2000-01-04 00:00:00',
332337
'DateColWithTz': '2000-06-01 00:00:00-07:00',
333338
'IntDateCol': 1356998400,
339+
'IntDateOnlyCol': 20101212,
334340
'FloatCol': 10.10,
335341
'IntCol': 1,
336342
'BoolCol': False,
@@ -610,20 +616,42 @@ def test_date_parsing(self):
610616
df = sql.read_sql_query("SELECT * FROM types_test_data", self.conn,
611617
parse_dates=['DateCol'])
612618
assert issubclass(df.DateCol.dtype.type, np.datetime64)
619+
assert df.DateCol.tolist() == [
620+
pd.Timestamp(2000, 1, 3, 0, 0, 0),
621+
pd.Timestamp(2000, 1, 4, 0, 0, 0)
622+
]
613623

614624
df = sql.read_sql_query("SELECT * FROM types_test_data", self.conn,
615625
parse_dates={'DateCol': '%Y-%m-%d %H:%M:%S'})
616626
assert issubclass(df.DateCol.dtype.type, np.datetime64)
627+
assert df.DateCol.tolist() == [
628+
pd.Timestamp(2000, 1, 3, 0, 0, 0),
629+
pd.Timestamp(2000, 1, 4, 0, 0, 0)
630+
]
617631

618632
df = sql.read_sql_query("SELECT * FROM types_test_data", self.conn,
619633
parse_dates=['IntDateCol'])
620-
621634
assert issubclass(df.IntDateCol.dtype.type, np.datetime64)
635+
assert df.IntDateCol.tolist() == [
636+
pd.Timestamp(1986, 12, 25, 0, 0, 0),
637+
pd.Timestamp(2013, 1, 1, 0, 0, 0)
638+
]
622639

623640
df = sql.read_sql_query("SELECT * FROM types_test_data", self.conn,
624641
parse_dates={'IntDateCol': 's'})
625-
626642
assert issubclass(df.IntDateCol.dtype.type, np.datetime64)
643+
assert df.IntDateCol.tolist() == [
644+
pd.Timestamp(1986, 12, 25, 0, 0, 0),
645+
pd.Timestamp(2013, 1, 1, 0, 0, 0)
646+
]
647+
648+
df = sql.read_sql_query("SELECT * FROM types_test_data", self.conn,
649+
parse_dates={'IntDateOnlyCol': '%Y%m%d'})
650+
assert issubclass(df.IntDateOnlyCol.dtype.type, np.datetime64)
651+
assert df.IntDateOnlyCol.tolist() == [
652+
pd.Timestamp('2010-10-10'),
653+
pd.Timestamp('2010-12-12')
654+
]
627655

628656
def test_date_and_index(self):
629657
# Test case where same column appears in parse_date and index_col

0 commit comments

Comments
 (0)