Definitely fixed date and time adapting problems (for mx too!)

This commit is contained in:
Federico Di Gregorio 2005-11-16 17:30:45 +00:00
parent 000aa345ac
commit 996bd07c85
7 changed files with 78 additions and 39 deletions

View File

@ -1,6 +1,14 @@
2005-11-16 Federico Di Gregorio <fog@initd.org> 2005-11-16 Federico Di Gregorio <fog@initd.org>
* Preparing release 2.0 beta 6. * Preparing release 2.0 beta 6.
* psycopg/adapter_mxdatetime.c: fixed all problems with mx conversions.
* psycopg/typecast.c: now the timezone is set correctly even if there
are no microseconds and/or the offset is 0;
* examples/encoding.py: fixed example by using python utf8 encoding for
the whole file.
* lib/__init__.py: very nice hack from Harald Armin Massa to allow * lib/__init__.py: very nice hack from Harald Armin Massa to allow
py2exe and similar tools to do their work without problems. py2exe and similar tools to do their work without problems.

View File

@ -23,6 +23,8 @@ import psycopg2
import mx.DateTime import mx.DateTime
import datetime import datetime
from psycopg2.extensions import adapt
if len(sys.argv) > 1: if len(sys.argv) > 1:
DSN = sys.argv[1] DSN = sys.argv[1]
@ -73,9 +75,11 @@ for n, x in zip(mx1[1:], curs.fetchone()):
try: try:
# this will work only is psycopg has been compiled with datetime # this will work only is psycopg has been compiled with datetime
# as the default typecaster for date/time values # as the default typecaster for date/time values
s = repr(n) + "\n -> " + repr(x) + "\n -> " + x.isoformat() s = repr(n) + "\n -> " + str(adapt(n)) + \
"\n -> " + repr(x) + "\n -> " + x.isoformat()
except: except:
s = repr(n) + "\n -> " + repr(x) + "\n -> " + str(x) s = repr(n) + "\n -> " + str(adapt(n)) + \
"\n -> " + repr(x) + "\n -> " + str(x)
print s print s
print print

View File

@ -1,5 +1,5 @@
# encoding.py - how to change client encoding (and test it works) # enkoding.py - show to change client enkoding (and test it works)
# -*- encoding: latin-1 -*- # -*- encoding: utf8 -*-
# #
# Copyright (C) 2004 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2004 Federico Di Gregorio <fog@debian.org>
# #
@ -33,27 +33,29 @@ print "Initial encoding for this connection is", conn.encoding
print "\n** This example is supposed to be run in a UNICODE terminal! **\n" print "\n** This example is supposed to be run in a UNICODE terminal! **\n"
print "Available encodings:" print "Available encodings:"
for a, b in psycopg2.extensions.encodings.items(): encs = psycopg2.extensions.encodings.items()
encs.sort()
for a, b in encs:
print " ", a, "<->", b print " ", a, "<->", b
print "Using STRING typecaster" print "Using STRING typecaster"
print "Setting backend encoding to LATIN1 and executing queries:" print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1') conn.set_client_encoding('LATIN1')
curs = conn.cursor() curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", ('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x) print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x) print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x)
print "Setting backend encoding to UTF8 and executing queries:" print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE') conn.set_client_encoding('UNICODE')
curs = conn.cursor() curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'.encode('utf-8'),)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x, type(x) print " ->", x, type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x, type(x) print " ->", x, type(x)
@ -63,20 +65,20 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
print "Setting backend encoding to LATIN1 and executing queries:" print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1') conn.set_client_encoding('LATIN1')
curs = conn.cursor() curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", ('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
print "Setting backend encoding to UTF8 and executing queries:" print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE') conn.set_client_encoding('UNICODE')
curs = conn.cursor() curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'.encode('utf-8'),)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
@ -85,19 +87,19 @@ print "Executing full UNICODE queries"
print "Setting backend encoding to LATIN1 and executing queries:" print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1') conn.set_client_encoding('LATIN1')
curs = conn.cursor() curs = conn.cursor()
curs.execute(u"SELECT %s::TEXT AS foo", ('<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute(u"SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
curs.execute(u"SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
print "Setting backend encoding to UTF8 and executing queries:" print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE') conn.set_client_encoding('UNICODE')
curs = conn.cursor() curs = conn.cursor()
curs.execute(u"SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'.encode('utf-8'),)) curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)
curs.execute(u"SELECT %s::TEXT AS foo", (u'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',)) curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0] x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x) print " ->", x.encode('utf-8'), ":", type(x)

View File

@ -1,5 +1,5 @@
# tz.py - example of datetime objects with time zones # tz.py - example of datetime objects with time zones
# -*- encoding: latin1 -*- # -*- encoding: utf8 -*-
# #
# Copyright (C) 2004 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2004 Federico Di Gregorio <fog@debian.org>
# #

View File

@ -42,35 +42,61 @@ extern mxDateTimeModule_APIObject *mxDateTimeP;
static PyObject * static PyObject *
mxdatetime_str(mxdatetimeObject *self) mxdatetime_str(mxdatetimeObject *self)
{ {
PyObject *res = NULL; PyObject *str = NULL, *res = NULL;
char *buffer = NULL;
/* mxDateTimeObject *obj = (mxDateTimeObject*)self->wrapped; */
switch (self->type) { switch (self->type) {
case PSYCO_MXDATETIME_TIME:
res = PyObject_CallMethod(self->wrapped, "strftime", "s",
"'%H:%M:%S'");
break;
case PSYCO_MXDATETIME_DATE: case PSYCO_MXDATETIME_DATE:
res = PyObject_CallMethod(self->wrapped, "strftime", "s",
"'%Y-%m-%d'");
break;
case PSYCO_MXDATETIME_TIMESTAMP: case PSYCO_MXDATETIME_TIMESTAMP:
res = PyObject_CallMethod(self->wrapped, "strftime", "s", str = PyObject_Str(self->wrapped);
"'%Y-%m-%dT%H:%M:%S'");
/* given the limitation of the mx.DateTime module that uses the same
type for both date and timestamp values we need to do some black
magic and make sure we're not using an adapt()ed timestamp as a
simple date */
if (strncmp(&(PyString_AsString(str)[11]), "00:00:00.000", 12) == 0) {
PyObject *tmp =
PyString_FromStringAndSize(PyString_AsString(str), 10);
Py_DECREF(str);
str = tmp;
}
break; break;
case PSYCO_MXDATETIME_TIME:
case PSYCO_MXDATETIME_INTERVAL: case PSYCO_MXDATETIME_INTERVAL:
res = PyObject_CallMethod(self->wrapped, "strftime", "s", str = PyObject_Str(self->wrapped);
"'%d:%H:%M:%S'");
/* 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
and make sure we're not using an adapt()ed interval as a simple
time */
if (PyString_Size(str) > 8 && PyString_AsString(str)[8] == ':') {
mxDateTimeDeltaObject *obj = (mxDateTimeDeltaObject*)self->wrapped;
char buffer[8];
int i, j, x;
double ss = obj->hour*3600.0 + obj->minute*60.0 + obj->second;
int us = (int)((ss - floor(ss))*1000000);
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 (buffer) free(buffer); if (str != NULL && res == NULL) {
res = PyString_FromFormat("'%s'", PyString_AsString(str));
}
Py_XDECREF(str);
return res; return res;
} }

View File

@ -117,8 +117,7 @@ typecast_parse_time(char* s, char** t, int* len,
if (*s == '-') tzs = -1; if (*s == '-') tzs = -1;
if (cz == 2) *ss = acc; if (cz == 2) *ss = acc;
else if (cz == 3) *us = acc; else if (cz == 3) *us = acc;
else if (cz == 4) *tz = acc; acc = -1; cz = 4;
acc = -1; cz++;
break; break;
default: default:
acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0'); acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');

View File

@ -1,5 +1,5 @@
[build_ext] [build_ext]
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3 define=PSYCOPG_DEBUG,PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
# PSYCOPG_EXTENSIONS enables extensions to PEP-249 (you really want this) # PSYCOPG_EXTENSIONS enables extensions to PEP-249 (you really want this)
# PSYCOPG_DISPLAY_SIZE enable display size calculation (a little slower) # PSYCOPG_DISPLAY_SIZE enable display size calculation (a little slower)
# HAVE_PQFREEMEM should be defined on PostgreSQL >= 7.3 # HAVE_PQFREEMEM should be defined on PostgreSQL >= 7.3