...
[plcapi.git] / psycopg2 / psycopg / adapter_datetime.c
1 /* adapter_datetime.c - python date/time objects
2  *
3  * Copyright (C) 2004 Federico Di Gregorio <fog@debian.org>
4  *
5  * This file is part of psycopg.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #include <Python.h>
23 #include <structmember.h>
24 #include <stringobject.h>
25 #include <datetime.h>
26
27 #include <time.h>
28 #include <string.h>
29
30 #define PSYCOPG_MODULE
31 #include "psycopg/config.h"
32 #include "psycopg/python.h"
33 #include "psycopg/psycopg.h"
34 #include "psycopg/adapter_datetime.h"
35 #include "psycopg/microprotocols_proto.h"
36
37
38 /* the pointer to the datetime module API is initialized by the module init
39    code, we just need to grab it */
40 extern PyObject* pyDateTimeModuleP;
41 extern PyObject *pyDateTypeP;
42 extern PyObject *pyTimeTypeP;
43 extern PyObject *pyDateTimeTypeP;
44 extern PyObject *pyDeltaTypeP;
45
46 extern PyObject *pyPsycopgTzModule;
47 extern PyObject *pyPsycopgTzLOCAL;
48
49 /* datetime_str, datetime_getquoted - return result of quoting */
50
51 static PyObject *
52 pydatetime_str(pydatetimeObject *self)
53 {
54     if (self->type <= PSYCO_DATETIME_TIMESTAMP) {
55         PyObject *res = NULL;
56         PyObject *iso = PyObject_CallMethod(self->wrapped, "isoformat", NULL);
57         if (iso) {
58             res = PyString_FromFormat("'%s'", PyString_AsString(iso));
59             Py_DECREF(iso);
60         }
61         return res;
62     }
63     else {
64         PyDateTime_Delta *obj = (PyDateTime_Delta*)self->wrapped;
65         
66         char buffer[8];
67         int i;
68         int a = obj->microseconds;
69         
70         for (i=0; i < 6 ; i++) {
71             buffer[5-i] = '0' + (a % 10);
72             a /= 10;
73         }
74         buffer[6] = '\0';
75
76         return PyString_FromFormat("'%d days %d.%s seconds'",
77                                    obj->days, obj->seconds, buffer);
78     }
79 }
80
81 PyObject *
82 pydatetime_getquoted(pydatetimeObject *self, PyObject *args)
83 {
84     if (!PyArg_ParseTuple(args, "")) return NULL;
85     return pydatetime_str(self);
86 }
87
88 PyObject *
89 pydatetime_conform(pydatetimeObject *self, PyObject *args)
90 {
91     PyObject *res, *proto;
92     
93     if (!PyArg_ParseTuple(args, "O", &proto)) return NULL;
94
95     if (proto == (PyObject*)&isqlquoteType)
96         res = (PyObject*)self;
97     else
98         res = Py_None;
99     
100     Py_INCREF(res);
101     return res;
102 }
103
104 /** the DateTime wrapper object **/
105
106 /* object member list */
107
108 static struct PyMemberDef pydatetimeObject_members[] = {
109     {"adapted", T_OBJECT, offsetof(pydatetimeObject, wrapped), RO},
110     {"type", T_INT, offsetof(pydatetimeObject, type), RO},
111     {NULL}
112 };
113
114 /* object method table */
115
116 static PyMethodDef pydatetimeObject_methods[] = {
117     {"getquoted", (PyCFunction)pydatetime_getquoted, METH_VARARGS,
118      "getquoted() -> wrapped object value as SQL date/time"},
119     {"__conform__", (PyCFunction)pydatetime_conform, METH_VARARGS, NULL},
120     {NULL}  /* Sentinel */
121 };
122
123 /* initialization and finalization methods */
124
125 static int
126 pydatetime_setup(pydatetimeObject *self, PyObject *obj, int type)
127 {
128     Dprintf("pydatetime_setup: init datetime object at %p, refcnt = %d",
129             self, ((PyObject *)self)->ob_refcnt);
130
131     self->type = type;
132     self->wrapped = obj;
133     Py_INCREF(self->wrapped);
134     
135     Dprintf("pydatetime_setup: good pydatetime object at %p, refcnt = %d",
136             self, ((PyObject *)self)->ob_refcnt);
137     return 0;
138 }
139
140 static void
141 pydatetime_dealloc(PyObject* obj)
142 {
143     pydatetimeObject *self = (pydatetimeObject *)obj;
144
145     Py_XDECREF(self->wrapped);
146     
147     Dprintf("mpydatetime_dealloc: deleted pydatetime object at %p, "
148             "refcnt = %d", obj, obj->ob_refcnt);
149     
150     obj->ob_type->tp_free(obj);
151 }
152
153 static int
154 pydatetime_init(PyObject *obj, PyObject *args, PyObject *kwds)
155 {
156     PyObject *dt;
157     int type = -1; /* raise an error if type was not passed! */
158     
159     if (!PyArg_ParseTuple(args, "O|i", &dt, &type))
160         return -1;
161
162     return pydatetime_setup((pydatetimeObject *)obj, dt, type);
163 }
164
165 static PyObject *
166 pydatetime_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
167 {    
168     return type->tp_alloc(type, 0);
169 }
170
171 static void
172 pydatetime_del(PyObject* self)
173 {
174     PyObject_Del(self);
175 }
176
177 static PyObject *
178 pydatetime_repr(pydatetimeObject *self)
179 {
180     return PyString_FromFormat("<psycopg2._psycopg.datetime object at %p>",
181                                 self);
182 }
183
184 /* object type */
185
186 #define pydatetimeType_doc \
187 "datetime(datetime, type) -> new datetime wrapper object"
188
189 PyTypeObject pydatetimeType = {
190     PyObject_HEAD_INIT(NULL)
191     0,
192     "psycopg2._psycopg.datetime",
193     sizeof(pydatetimeObject),
194     0,
195     pydatetime_dealloc, /*tp_dealloc*/
196     0,          /*tp_print*/
197     0,          /*tp_getattr*/
198     0,          /*tp_setattr*/   
199
200     0,          /*tp_compare*/
201     (reprfunc)pydatetime_repr, /*tp_repr*/
202     0,          /*tp_as_number*/
203     0,          /*tp_as_sequence*/
204     0,          /*tp_as_mapping*/
205     0,          /*tp_hash */
206
207     0,          /*tp_call*/
208     (reprfunc)pydatetime_str, /*tp_str*/
209     0,          /*tp_getattro*/
210     0,          /*tp_setattro*/
211     0,          /*tp_as_buffer*/
212
213     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
214
215     pydatetimeType_doc, /*tp_doc*/
216     
217     0,          /*tp_traverse*/
218     0,          /*tp_clear*/
219
220     0,          /*tp_richcompare*/
221     0,          /*tp_weaklistoffset*/
222
223     0,          /*tp_iter*/
224     0,          /*tp_iternext*/
225
226     /* Attribute descriptor and subclassing stuff */
227
228     pydatetimeObject_methods, /*tp_methods*/
229     pydatetimeObject_members, /*tp_members*/
230     0,          /*tp_getset*/
231     0,          /*tp_base*/
232     0,          /*tp_dict*/
233     
234     0,          /*tp_descr_get*/
235     0,          /*tp_descr_set*/
236     0,          /*tp_dictoffset*/
237     
238     pydatetime_init, /*tp_init*/
239     0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
240     pydatetime_new, /*tp_new*/
241     (freefunc)pydatetime_del, /*tp_free  Low-level free-memory routine */
242     0,          /*tp_is_gc For PyObject_IS_GC */
243     0,          /*tp_bases*/
244     0,          /*tp_mro method resolution order */
245     0,          /*tp_cache*/
246     0,          /*tp_subclasses*/
247     0           /*tp_weaklist*/
248 };
249
250
251 /** module-level functions **/
252
253 #ifdef PSYCOPG_DEFAULT_PYDATETIME
254
255 PyObject *
256 psyco_Date(PyObject *self, PyObject *args) 
257 {
258         PyObject *res = NULL;
259         int year, month, day;
260
261     PyObject* obj = NULL;
262     
263         if (!PyArg_ParseTuple(args, "iii", &year, &month, &day))
264             return NULL;
265
266     obj = PyObject_CallFunction(pyDateTypeP, "iii", year, month, day);
267
268     if (obj) {
269         res = PyObject_CallFunction((PyObject *)&pydatetimeType,
270                                     "Oi", obj, PSYCO_DATETIME_DATE);
271         Py_DECREF(obj);
272     }
273
274     return res;
275 }
276
277 PyObject *
278 psyco_Time(PyObject *self, PyObject *args) 
279 {
280         PyObject *res = NULL;
281     PyObject *tzinfo = NULL;
282     int hours, minutes=0;
283         double micro, seconds=0.0;
284     
285     PyObject* obj = NULL;
286
287     if (!PyArg_ParseTuple(args, "iid|O", &hours, &minutes, &seconds,
288                           &tzinfo))
289             return NULL;
290
291     micro = (seconds - floor(seconds)) * 1000000.0;
292     
293     if (tzinfo == NULL)
294        obj = PyObject_CallFunction(pyTimeTypeP, "iiii",
295             hours, minutes, (int)round(seconds), (int)round(micro));
296     else
297        obj = PyObject_CallFunction(pyTimeTypeP, "iiiiO",
298             hours, minutes, (int)round(seconds), (int)round(micro), tzinfo);
299     
300     if (obj) {
301         res = PyObject_CallFunction((PyObject *)&pydatetimeType,
302                                     "Oi", obj, PSYCO_DATETIME_TIME);
303         Py_DECREF(obj);
304     }
305
306     return res;
307 }
308
309 PyObject *
310 psyco_Timestamp(PyObject *self, PyObject *args) 
311 {
312         PyObject *res = NULL;
313     PyObject *tzinfo = NULL;
314     int year, month, day;
315         int hour=0, minute=0; /* default to midnight */
316         double micro, second=0.0;
317
318     PyObject* obj = NULL;
319     
320     if (!PyArg_ParseTuple(args, "lii|iidO", &year, &month, &day,
321                           &hour, &minute, &second, &tzinfo))
322             return NULL;
323
324     micro = (second - floor(second)) * 1000000.0;
325     
326     if (tzinfo == NULL)
327         obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii",
328             year, month, day, hour, minute, (int)round(second),
329             (int)round(micro));
330     else
331         obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO",
332             year, month, day, hour, minute, (int)round(second),
333             (int)round(micro), tzinfo);
334     
335     if (obj) {
336         res = PyObject_CallFunction((PyObject *)&pydatetimeType,
337                                     "Oi", obj, PSYCO_DATETIME_TIMESTAMP);
338         Py_DECREF(obj);
339     }
340     
341     return res;
342 }
343
344 PyObject *
345 psyco_DateFromTicks(PyObject *self, PyObject *args)
346 {
347     PyObject *res = NULL;
348     struct tm tm;
349     time_t t;
350     double ticks;
351
352     if (!PyArg_ParseTuple(args, "d", &ticks))
353         return NULL;
354
355     t = (time_t)round(ticks);
356     if (localtime_r(&t, &tm)) {
357         args = Py_BuildValue("iii", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
358         if (args) {
359             res = psyco_Date(self, args);
360             Py_DECREF(args);
361         }
362     }    
363     return res; 
364 }
365
366 PyObject *
367 psyco_TimeFromTicks(PyObject *self, PyObject *args)
368 {
369     PyObject *res = NULL;
370     struct tm tm;
371     time_t t;
372     double ticks;
373
374     if (!PyArg_ParseTuple(args,"d", &ticks))
375         return NULL;
376
377     t = (time_t)round(ticks);
378     if (localtime_r(&t, &tm)) {
379         args = Py_BuildValue("iid", tm.tm_hour, tm.tm_min, (double)tm.tm_sec);
380         if (args) {
381             res = psyco_Time(self, args);
382             Py_DECREF(args);
383         }
384     } 
385     return res; 
386 }
387
388 PyObject *
389 psyco_TimestampFromTicks(PyObject *self, PyObject *args)
390 {
391     PyObject *res = NULL;
392     struct tm tm;
393     time_t t;
394     double ticks;
395
396     if (!PyArg_ParseTuple(args,"d", &ticks))
397         return NULL;
398     
399     t = (time_t)round(ticks);
400     if (localtime_r(&t, &tm)) {
401         args = Py_BuildValue("iiiiidO",
402                              tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
403                              tm.tm_hour, tm.tm_min, (double)tm.tm_sec,
404                              pyPsycopgTzLOCAL);
405         if (args) {
406             res = psyco_Timestamp(self, args);
407             Py_DECREF(args);
408         }
409     } 
410     return res; 
411 }
412
413 #endif
414
415 PyObject *
416 psyco_DateFromPy(PyObject *self, PyObject *args)
417 {
418     PyObject *obj;
419
420     if (!PyArg_ParseTuple(args, "O!", pyDateTypeP, &obj))
421         return NULL;
422     
423     return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj,
424                                  PSYCO_DATETIME_DATE);
425 }
426
427 PyObject *
428 psyco_TimeFromPy(PyObject *self, PyObject *args)
429 {
430     PyObject *obj;
431
432     if (!PyArg_ParseTuple(args, "O!", pyTimeTypeP, &obj))
433         return NULL;
434     
435     return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj,
436                                  PSYCO_DATETIME_TIME);
437 }
438
439 PyObject *
440 psyco_TimestampFromPy(PyObject *self, PyObject *args)
441 {
442     PyObject *obj;
443
444     if (!PyArg_ParseTuple(args, "O!", pyDateTimeTypeP, &obj))
445         return NULL;
446     
447     return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj,
448                                  PSYCO_DATETIME_TIMESTAMP);
449 }
450
451 PyObject *
452 psyco_IntervalFromPy(PyObject *self, PyObject *args)
453 {
454     PyObject *obj;
455
456     if (!PyArg_ParseTuple(args, "O!", pyDeltaTypeP, &obj))
457         return NULL;
458     
459     return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj,
460                                  PSYCO_DATETIME_INTERVAL);
461 }