mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-12-01 21:23:43 +03:00
* tests/__init__.py (test_suite): add date tests to test suite.
* tests/test_dates.py: add tests for date/time typecasting and adaption. * psycopg/adapter_mxdatetime.c (mxdatetime_str): add support for outputting BC dates (which involves switching them to one-based dates). Also remove broken handling of microseconds. * psycopg/typecast.c (typecast_parse_date): if the string ends with "BC" adjust the year value to be a zero-based BC value as used by mx.DateTime (datetime doesn't support BC dates). (typecast_parse_time): ignore ' ', 'B' and 'C' in time strings rather than treating them as part of the seconds part of the time.
This commit is contained in:
parent
f18881983b
commit
46bf23caf4
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
||||||
|
2008-01-16 James Henstridge <james@jamesh.id.au>
|
||||||
|
|
||||||
|
* tests/__init__.py (test_suite): add date tests to test suite.
|
||||||
|
|
||||||
|
* tests/test_dates.py: add tests for date/time typecasting and
|
||||||
|
adaption.
|
||||||
|
|
||||||
|
* psycopg/adapter_mxdatetime.c (mxdatetime_str): add support for
|
||||||
|
outputting BC dates (which involves switching them to one-based
|
||||||
|
dates). Also remove broken handling of microseconds.
|
||||||
|
|
||||||
|
* psycopg/typecast.c (typecast_parse_date): if the string ends
|
||||||
|
with "BC" adjust the year value to be a zero-based BC value as
|
||||||
|
used by mx.DateTime (datetime doesn't support BC dates).
|
||||||
|
(typecast_parse_time): ignore ' ', 'B' and 'C' in time strings
|
||||||
|
rather than treating them as part of the seconds part of the time.
|
||||||
|
|
||||||
2008-01-14 James Henstridge <james@jamesh.id.au>
|
2008-01-14 James Henstridge <james@jamesh.id.au>
|
||||||
|
|
||||||
* psycopg/typecast_array.c (typecast_array_scan): set an initial
|
* psycopg/typecast_array.c (typecast_array_scan): set an initial
|
||||||
|
|
|
@ -43,71 +43,70 @@ extern mxDateTimeModule_APIObject *mxDateTimeP;
|
||||||
static PyObject *
|
static PyObject *
|
||||||
mxdatetime_str(mxdatetimeObject *self)
|
mxdatetime_str(mxdatetimeObject *self)
|
||||||
{
|
{
|
||||||
PyObject *str = NULL, *res = NULL;
|
mxDateTimeObject *dt;
|
||||||
PyObject *supa, *supb;
|
mxDateTimeDeltaObject *dtd;
|
||||||
|
char buf[128] = { 0, };
|
||||||
|
|
||||||
switch (self->type) {
|
switch (self->type) {
|
||||||
|
|
||||||
case PSYCO_MXDATETIME_DATE:
|
case PSYCO_MXDATETIME_DATE:
|
||||||
str = PyObject_GetAttrString(self->wrapped, "date");
|
dt = (mxDateTimeObject *)self->wrapped;
|
||||||
|
if (dt->year >= 1)
|
||||||
|
PyOS_snprintf(buf, sizeof(buf) - 1, "'%04ld-%02d-%02d'",
|
||||||
|
dt->year, (int)dt->month, (int)dt->day);
|
||||||
|
else
|
||||||
|
PyOS_snprintf(buf, sizeof(buf) - 1, "'%04ld-%02d-%02d BC'",
|
||||||
|
1 - dt->year, (int)dt->month, (int)dt->day);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PSYCO_MXDATETIME_TIMESTAMP:
|
case PSYCO_MXDATETIME_TIMESTAMP:
|
||||||
/* here we build the right ISO string from date and time */
|
dt = (mxDateTimeObject *)self->wrapped;
|
||||||
supa = PyObject_GetAttrString(self->wrapped, "date");
|
if (dt->year >= 1)
|
||||||
supb = PyObject_GetAttrString(self->wrapped, "time");
|
PyOS_snprintf(buf, sizeof(buf) - 1,
|
||||||
str = PyString_FromFormat("%sT%s",
|
"'%04ld-%02d-%02dT%02d:%02d:%09.6f'",
|
||||||
PyString_AsString(supa), PyString_AsString(supb));
|
dt->year, (int)dt->month, (int)dt->day,
|
||||||
Py_XDECREF(supa);
|
(int)dt->hour, (int)dt->minute, dt->second);
|
||||||
Py_XDECREF(supb);
|
else
|
||||||
|
PyOS_snprintf(buf, sizeof(buf) - 1,
|
||||||
|
"'%04ld-%02d-%02dT%02d:%02d:%09.6f BC'",
|
||||||
|
1 - dt->year, (int)dt->month, (int)dt->day,
|
||||||
|
(int)dt->hour, (int)dt->minute, dt->second);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PSYCO_MXDATETIME_TIME:
|
case PSYCO_MXDATETIME_TIME:
|
||||||
case PSYCO_MXDATETIME_INTERVAL:
|
case PSYCO_MXDATETIME_INTERVAL:
|
||||||
str = PyObject_Str(self->wrapped);
|
|
||||||
|
|
||||||
/* given the limitation of the mx.DateTime module that uses the same
|
/* given the limitation of the mx.DateTime module that uses the same
|
||||||
type for both time and delta values we need to do some black magic
|
type for both time and delta values we need to do some black magic
|
||||||
and make sure we're not using an adapt()ed interval as a simple
|
and make sure we're not using an adapt()ed interval as a simple
|
||||||
time */
|
time */
|
||||||
if (PyString_Size(str) > 8 && PyString_AsString(str)[8] == ':') {
|
dtd = (mxDateTimeDeltaObject *)self->wrapped;
|
||||||
mxDateTimeDeltaObject *obj = (mxDateTimeDeltaObject*)self->wrapped;
|
if (0 <= dtd->seconds && dtd->seconds < 24*3600) {
|
||||||
|
PyOS_snprintf(buf, sizeof(buf) - 1, "'%02d:%02d:%09.6f'",
|
||||||
|
(int)dtd->hour, (int)dtd->minute, dtd->second);
|
||||||
|
} else {
|
||||||
|
double ss = dtd->hour*3600.0 + dtd->minute*60.0 + dtd->second;
|
||||||
|
|
||||||
char buffer[8];
|
if (dtd->seconds >= 0)
|
||||||
int i, j, x;
|
PyOS_snprintf(buf, sizeof(buf) - 1, "'%ld days %.6f seconds'",
|
||||||
|
dtd->day, ss);
|
||||||
double ss = obj->hour*3600.0 + obj->minute*60.0 + obj->second;
|
else
|
||||||
int us = (int)((ss - floor(ss))*1000000);
|
PyOS_snprintf(buf, sizeof(buf) - 1, "'-%ld days -%.6f seconds'",
|
||||||
|
dtd->day, ss);
|
||||||
for (i=1000000, j=0; i > 0 ; i /= 10) {
|
|
||||||
x = us/i;
|
|
||||||
us -= x*i;
|
|
||||||
buffer[j++] = '0'+x;
|
|
||||||
}
|
|
||||||
buffer[j] = '\0';
|
|
||||||
|
|
||||||
res = PyString_FromFormat("'%ld days %d.%s seconds'",
|
|
||||||
obj->day, (int)round(ss), buffer);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str != NULL && res == NULL) {
|
return PyString_FromString(buf);
|
||||||
res = PyString_FromFormat("'%s'", PyString_AsString(str));
|
|
||||||
}
|
|
||||||
Py_XDECREF(str);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
mxdatetime_getquoted(mxdatetimeObject *self, PyObject *args)
|
mxdatetime_getquoted(mxdatetimeObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
if (!PyArg_ParseTuple(args, "")) return NULL;
|
if (!PyArg_ParseTuple(args, "")) return NULL;
|
||||||
return mxdatetime_str(self);
|
return mxdatetime_str(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
static PyObject *
|
||||||
mxdatetime_conform(mxdatetimeObject *self, PyObject *args)
|
mxdatetime_conform(mxdatetimeObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *res, *proto;
|
PyObject *res, *proto;
|
||||||
|
|
|
@ -79,6 +79,13 @@ typecast_parse_date(char* s, char** t, Py_ssize_t* len,
|
||||||
*day = acc;
|
*day = acc;
|
||||||
cz += 1;
|
cz += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is this a BC date? If so, adjust the year value. Note that
|
||||||
|
* mx.DateTime numbers BC dates from zero rather than one. The
|
||||||
|
* Python datetime module does not support BC dates at all. */
|
||||||
|
if (*len >= 2 && s[*len-2] == 'B' && s[*len-1] == 'C')
|
||||||
|
*year = 1 - (*year);
|
||||||
|
|
||||||
if (t != NULL) *t = s;
|
if (t != NULL) *t = s;
|
||||||
|
|
||||||
return cz;
|
return cz;
|
||||||
|
@ -123,6 +130,12 @@ typecast_parse_time(char* s, char** t, Py_ssize_t* len,
|
||||||
else if (cz == 3) *us = acc;
|
else if (cz == 3) *us = acc;
|
||||||
acc = -1; cz = 4;
|
acc = -1; cz = 4;
|
||||||
break;
|
break;
|
||||||
|
case ' ':
|
||||||
|
case 'B':
|
||||||
|
case 'C':
|
||||||
|
/* Ignore the " BC" suffix, if passed -- it is handled
|
||||||
|
* when parsing the date portion. */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
|
acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
|
||||||
if (cz == 3) usd += 1;
|
if (cz == 3) usd += 1;
|
||||||
|
|
|
@ -6,6 +6,7 @@ dbname = os.environ.get('PSYCOPG2_TESTDB', 'psycopg2_test')
|
||||||
|
|
||||||
import bugX000
|
import bugX000
|
||||||
import extras_dictcursor
|
import extras_dictcursor
|
||||||
|
import test_dates
|
||||||
import test_psycopg2_dbapi20
|
import test_psycopg2_dbapi20
|
||||||
import test_quote
|
import test_quote
|
||||||
import test_transaction
|
import test_transaction
|
||||||
|
@ -15,6 +16,7 @@ def test_suite():
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
suite.addTest(bugX000.test_suite())
|
suite.addTest(bugX000.test_suite())
|
||||||
suite.addTest(extras_dictcursor.test_suite())
|
suite.addTest(extras_dictcursor.test_suite())
|
||||||
|
suite.addTest(test_dates.test_suite())
|
||||||
suite.addTest(test_psycopg2_dbapi20.test_suite())
|
suite.addTest(test_psycopg2_dbapi20.test_suite())
|
||||||
suite.addTest(test_quote.test_suite())
|
suite.addTest(test_quote.test_suite())
|
||||||
suite.addTest(test_transaction.test_suite())
|
suite.addTest(test_transaction.test_suite())
|
||||||
|
|
468
tests/test_dates.py
Normal file
468
tests/test_dates.py
Normal file
|
@ -0,0 +1,468 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import math
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
import tests
|
||||||
|
|
||||||
|
|
||||||
|
class CommonDatetimeTestsMixin:
|
||||||
|
|
||||||
|
def execute(self, *args):
|
||||||
|
conn = psycopg2.connect("dbname=%s" % tests.dbname)
|
||||||
|
curs = conn.cursor()
|
||||||
|
curs.execute(*args)
|
||||||
|
return curs.fetchone()[0]
|
||||||
|
|
||||||
|
def test_parse_date(self):
|
||||||
|
value = self.DATE('2007-01-01', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.year, 2007)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
|
||||||
|
def test_parse_null_date(self):
|
||||||
|
value = self.DATE(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_time(self):
|
||||||
|
value = self.TIME('13:30:29', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_null_time(self):
|
||||||
|
value = self.TIME(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_datetime(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.year, 2007)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_null_datetime(self):
|
||||||
|
value = self.DATETIME(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_null_interval(self):
|
||||||
|
value = self.INTERVAL(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
|
||||||
|
class DatetimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
||||||
|
"""Tests for the datetime based date handling in psycopg2."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.DATE = psycopg2._psycopg.PYDATE
|
||||||
|
self.TIME = psycopg2._psycopg.PYTIME
|
||||||
|
self.DATETIME = psycopg2._psycopg.PYDATETIME
|
||||||
|
self.INTERVAL = psycopg2._psycopg.PYINTERVAL
|
||||||
|
|
||||||
|
def test_parse_bc_date(self):
|
||||||
|
# datetime does not support BC dates
|
||||||
|
self.assertRaises(ValueError, self.DATE, '00042-01-01 BC', None)
|
||||||
|
|
||||||
|
def test_parse_bc_datetime(self):
|
||||||
|
# datetime does not support BC dates
|
||||||
|
self.assertRaises(ValueError, self.DATETIME,
|
||||||
|
'00042-01-01 13:30:29 BC', None)
|
||||||
|
|
||||||
|
def test_parse_time_microseconds(self):
|
||||||
|
value = self.TIME('13:30:29.123456', None)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
self.assertEqual(value.microsecond, 123456)
|
||||||
|
|
||||||
|
def test_parse_datetime_microseconds(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
self.assertEqual(value.microsecond, 123456)
|
||||||
|
|
||||||
|
def test_parse_interval(self):
|
||||||
|
value = self.INTERVAL('42 days 12:34:56.123456', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.days, 42)
|
||||||
|
self.assertEqual(value.seconds, 45296)
|
||||||
|
self.assertEqual(value.microseconds, 123456)
|
||||||
|
|
||||||
|
def test_parse_negative_interval(self):
|
||||||
|
value = self.INTERVAL('-42 days -12:34:56.123456', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.days, -43)
|
||||||
|
self.assertEqual(value.seconds, 41103)
|
||||||
|
self.assertEqual(value.microseconds, 876544)
|
||||||
|
|
||||||
|
def test_adapt_date(self):
|
||||||
|
from datetime import date
|
||||||
|
value = self.execute('select (%s)::date::text',
|
||||||
|
[date(2007, 1, 1)])
|
||||||
|
self.assertEqual(value, '2007-01-01')
|
||||||
|
|
||||||
|
def test_adapt_time(self):
|
||||||
|
from datetime import time
|
||||||
|
value = self.execute('select (%s)::time::text',
|
||||||
|
[time(13, 30, 29)])
|
||||||
|
self.assertEqual(value, '13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_datetime(self):
|
||||||
|
from datetime import datetime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[datetime(2007, 1, 1, 13, 30, 29)])
|
||||||
|
self.assertEqual(value, '2007-01-01 13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_timedelta(self):
|
||||||
|
from datetime import timedelta
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[timedelta(days=42, seconds=45296,
|
||||||
|
microseconds=123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, 3674096)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
def test_adapt_megative_timedelta(self):
|
||||||
|
from datetime import timedelta
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[timedelta(days=-42, seconds=45296,
|
||||||
|
microseconds=123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, -3583504)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
|
||||||
|
# Only run the datetime tests if psycopg was compiled with support.
|
||||||
|
if not hasattr(psycopg2._psycopg, 'PYDATETIME'):
|
||||||
|
del DatetimeTests
|
||||||
|
|
||||||
|
|
||||||
|
class mxDateTimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
||||||
|
"""Tests for the mx.DateTime based date handling in psycopg2."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.DATE = psycopg2._psycopg.MXDATE
|
||||||
|
self.TIME = psycopg2._psycopg.MXTIME
|
||||||
|
self.DATETIME = psycopg2._psycopg.MXDATETIME
|
||||||
|
self.INTERVAL = psycopg2._psycopg.MXINTERVAL
|
||||||
|
|
||||||
|
def test_parse_bc_date(self):
|
||||||
|
value = self.DATE('00042-01-01 BC', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
||||||
|
self.assertEqual(value.year, -41)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
|
||||||
|
def test_parse_bc_datetime(self):
|
||||||
|
value = self.DATETIME('00042-01-01 13:30:29 BC', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
||||||
|
self.assertEqual(value.year, -41)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_time_microseconds(self):
|
||||||
|
value = self.TIME('13:30:29.123456', None)
|
||||||
|
self.assertEqual(math.floor(value.second), 29)
|
||||||
|
self.assertEqual(
|
||||||
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
||||||
|
|
||||||
|
def test_parse_datetime_microseconds(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
||||||
|
self.assertEqual(math.floor(value.second), 29)
|
||||||
|
self.assertEqual(
|
||||||
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
||||||
|
|
||||||
|
def test_parse_interval(self):
|
||||||
|
value = self.INTERVAL('42 days 05:50:05', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.day, 42)
|
||||||
|
self.assertEqual(value.hour, 5)
|
||||||
|
self.assertEqual(value.minute, 50)
|
||||||
|
self.assertEqual(value.second, 5)
|
||||||
|
|
||||||
|
def test_adapt_time(self):
|
||||||
|
from mx.DateTime import Time
|
||||||
|
value = self.execute('select (%s)::time::text',
|
||||||
|
[Time(13, 30, 29)])
|
||||||
|
self.assertEqual(value, '13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_datetime(self):
|
||||||
|
from mx.DateTime import DateTime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[DateTime(2007, 1, 1, 13, 30, 29.123456)])
|
||||||
|
self.assertEqual(value, '2007-01-01 13:30:29.123456')
|
||||||
|
|
||||||
|
def test_adapt_bc_datetime(self):
|
||||||
|
from mx.DateTime import DateTime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[DateTime(-41, 1, 1, 13, 30, 29.123456)])
|
||||||
|
self.assertEqual(value, '0042-01-01 13:30:29.123456 BC')
|
||||||
|
|
||||||
|
def test_adapt_timedelta(self):
|
||||||
|
from mx.DateTime import DateTimeDeltaFrom
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[DateTimeDeltaFrom(days=42,
|
||||||
|
seconds=45296.123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, 3674096)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
def test_adapt_megative_timedelta(self):
|
||||||
|
from mx.DateTime import DateTimeDeltaFrom
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[DateTimeDeltaFrom(days=-42,
|
||||||
|
seconds=45296.123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, -3583504)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
|
||||||
|
# Only run the mx.DateTime tests if psycopg was compiled with support.
|
||||||
|
if not hasattr(psycopg2._psycopg, 'MXDATETIME'):
|
||||||
|
del mxDateTimeTests
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import math
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
import tests
|
||||||
|
|
||||||
|
|
||||||
|
class CommonDatetimeTestsMixin:
|
||||||
|
|
||||||
|
def execute(self, *args):
|
||||||
|
conn = psycopg2.connect("dbname=%s" % tests.dbname)
|
||||||
|
curs = conn.cursor()
|
||||||
|
curs.execute(*args)
|
||||||
|
return curs.fetchone()[0]
|
||||||
|
|
||||||
|
def test_parse_date(self):
|
||||||
|
value = self.DATE('2007-01-01', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.year, 2007)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
|
||||||
|
def test_parse_null_date(self):
|
||||||
|
value = self.DATE(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_time(self):
|
||||||
|
value = self.TIME('13:30:29', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_null_time(self):
|
||||||
|
value = self.TIME(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_datetime(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.year, 2007)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_null_datetime(self):
|
||||||
|
value = self.DATETIME(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
def test_parse_null_interval(self):
|
||||||
|
value = self.INTERVAL(None, None)
|
||||||
|
self.assertEqual(value, None)
|
||||||
|
|
||||||
|
|
||||||
|
class DatetimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
||||||
|
"""Tests for the datetime based date handling in psycopg2."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.DATE = psycopg2._psycopg.PYDATE
|
||||||
|
self.TIME = psycopg2._psycopg.PYTIME
|
||||||
|
self.DATETIME = psycopg2._psycopg.PYDATETIME
|
||||||
|
self.INTERVAL = psycopg2._psycopg.PYINTERVAL
|
||||||
|
|
||||||
|
def test_parse_bc_date(self):
|
||||||
|
# datetime does not support BC dates
|
||||||
|
self.assertRaises(ValueError, self.DATE, '00042-01-01 BC', None)
|
||||||
|
|
||||||
|
def test_parse_bc_datetime(self):
|
||||||
|
# datetime does not support BC dates
|
||||||
|
self.assertRaises(ValueError, self.DATETIME,
|
||||||
|
'00042-01-01 13:30:29 BC', None)
|
||||||
|
|
||||||
|
def test_parse_time_microseconds(self):
|
||||||
|
value = self.TIME('13:30:29.123456', None)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
self.assertEqual(value.microsecond, 123456)
|
||||||
|
|
||||||
|
def test_parse_datetime_microseconds(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
self.assertEqual(value.microsecond, 123456)
|
||||||
|
|
||||||
|
def test_parse_interval(self):
|
||||||
|
value = self.INTERVAL('42 days 12:34:56.123456', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.days, 42)
|
||||||
|
self.assertEqual(value.seconds, 45296)
|
||||||
|
self.assertEqual(value.microseconds, 123456)
|
||||||
|
|
||||||
|
def test_parse_negative_interval(self):
|
||||||
|
value = self.INTERVAL('-42 days -12:34:56.123456', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.days, -43)
|
||||||
|
self.assertEqual(value.seconds, 41103)
|
||||||
|
self.assertEqual(value.microseconds, 876544)
|
||||||
|
|
||||||
|
def test_adapt_date(self):
|
||||||
|
from datetime import date
|
||||||
|
value = self.execute('select (%s)::date::text',
|
||||||
|
[date(2007, 1, 1)])
|
||||||
|
self.assertEqual(value, '2007-01-01')
|
||||||
|
|
||||||
|
def test_adapt_time(self):
|
||||||
|
from datetime import time
|
||||||
|
value = self.execute('select (%s)::time::text',
|
||||||
|
[time(13, 30, 29)])
|
||||||
|
self.assertEqual(value, '13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_datetime(self):
|
||||||
|
from datetime import datetime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[datetime(2007, 1, 1, 13, 30, 29)])
|
||||||
|
self.assertEqual(value, '2007-01-01 13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_timedelta(self):
|
||||||
|
from datetime import timedelta
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[timedelta(days=42, seconds=45296,
|
||||||
|
microseconds=123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, 3674096)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
def test_adapt_megative_timedelta(self):
|
||||||
|
from datetime import timedelta
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[timedelta(days=-42, seconds=45296,
|
||||||
|
microseconds=123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, -3583504)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
|
||||||
|
# Only run the datetime tests if psycopg was compiled with support.
|
||||||
|
if not hasattr(psycopg2._psycopg, 'PYDATETIME'):
|
||||||
|
del DatetimeTests
|
||||||
|
|
||||||
|
|
||||||
|
class mxDateTimeTests(unittest.TestCase, CommonDatetimeTestsMixin):
|
||||||
|
"""Tests for the mx.DateTime based date handling in psycopg2."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.DATE = psycopg2._psycopg.MXDATE
|
||||||
|
self.TIME = psycopg2._psycopg.MXTIME
|
||||||
|
self.DATETIME = psycopg2._psycopg.MXDATETIME
|
||||||
|
self.INTERVAL = psycopg2._psycopg.MXINTERVAL
|
||||||
|
|
||||||
|
def test_parse_bc_date(self):
|
||||||
|
value = self.DATE('00042-01-01 BC', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
||||||
|
self.assertEqual(value.year, -41)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
|
||||||
|
def test_parse_bc_datetime(self):
|
||||||
|
value = self.DATETIME('00042-01-01 13:30:29 BC', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
# mx.DateTime numbers BC dates from 0 rather than 1.
|
||||||
|
self.assertEqual(value.year, -41)
|
||||||
|
self.assertEqual(value.month, 1)
|
||||||
|
self.assertEqual(value.day, 1)
|
||||||
|
self.assertEqual(value.hour, 13)
|
||||||
|
self.assertEqual(value.minute, 30)
|
||||||
|
self.assertEqual(value.second, 29)
|
||||||
|
|
||||||
|
def test_parse_time_microseconds(self):
|
||||||
|
value = self.TIME('13:30:29.123456', None)
|
||||||
|
self.assertEqual(math.floor(value.second), 29)
|
||||||
|
self.assertEqual(
|
||||||
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
||||||
|
|
||||||
|
def test_parse_datetime_microseconds(self):
|
||||||
|
value = self.DATETIME('2007-01-01 13:30:29.123456', None)
|
||||||
|
self.assertEqual(math.floor(value.second), 29)
|
||||||
|
self.assertEqual(
|
||||||
|
int((value.second - math.floor(value.second)) * 1000000), 123456)
|
||||||
|
|
||||||
|
def test_parse_interval(self):
|
||||||
|
value = self.INTERVAL('42 days 05:50:05', None)
|
||||||
|
self.assertNotEqual(value, None)
|
||||||
|
self.assertEqual(value.day, 42)
|
||||||
|
self.assertEqual(value.hour, 5)
|
||||||
|
self.assertEqual(value.minute, 50)
|
||||||
|
self.assertEqual(value.second, 5)
|
||||||
|
|
||||||
|
def test_adapt_time(self):
|
||||||
|
from mx.DateTime import Time
|
||||||
|
value = self.execute('select (%s)::time::text',
|
||||||
|
[Time(13, 30, 29)])
|
||||||
|
self.assertEqual(value, '13:30:29')
|
||||||
|
|
||||||
|
def test_adapt_datetime(self):
|
||||||
|
from mx.DateTime import DateTime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[DateTime(2007, 1, 1, 13, 30, 29.123456)])
|
||||||
|
self.assertEqual(value, '2007-01-01 13:30:29.123456')
|
||||||
|
|
||||||
|
def test_adapt_bc_datetime(self):
|
||||||
|
from mx.DateTime import DateTime
|
||||||
|
value = self.execute('select (%s)::timestamp::text',
|
||||||
|
[DateTime(-41, 1, 1, 13, 30, 29.123456)])
|
||||||
|
self.assertEqual(value, '0042-01-01 13:30:29.123456 BC')
|
||||||
|
|
||||||
|
def test_adapt_timedelta(self):
|
||||||
|
from mx.DateTime import DateTimeDeltaFrom
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[DateTimeDeltaFrom(days=42,
|
||||||
|
seconds=45296.123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, 3674096)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
def test_adapt_megative_timedelta(self):
|
||||||
|
from mx.DateTime import DateTimeDeltaFrom
|
||||||
|
value = self.execute('select extract(epoch from (%s)::interval)',
|
||||||
|
[DateTimeDeltaFrom(days=-42,
|
||||||
|
seconds=45296.123456)])
|
||||||
|
seconds = math.floor(value)
|
||||||
|
self.assertEqual(seconds, -3583504)
|
||||||
|
self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
|
||||||
|
|
||||||
|
|
||||||
|
# Only run the mx.DateTime tests if psycopg was compiled with support.
|
||||||
|
if not hasattr(psycopg2._psycopg, 'MXDATETIME'):
|
||||||
|
del mxDateTimeTests
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user