Merge remote-tracking branch 'origin/pycurl' into planetlab-4_0-branch
[plcapi.git] / trunk / psycopg2 / psycopg / typecast_datetime.c
1 /* typecast_datetime.c - date and time typecasting functions to python types
2  *
3  * Copyright (C) 2001-2003 Federico Di Gregorio <fog@debian.org>
4  *
5  * This file is part of the psycopg module.
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 <math.h>
23 #include "datetime.h"
24
25
26 /* the pointer to the datetime module API is initialized by the module init
27    code, we just need to grab it */
28 extern PyObject* pyDateTimeModuleP;
29 extern PyObject *pyDateTypeP;
30 extern PyObject *pyTimeTypeP;
31 extern PyObject *pyDateTimeTypeP;
32 extern PyObject *pyDeltaTypeP;
33
34 /** DATE - cast a date into a date python object **/
35
36 static PyObject *
37 typecast_PYDATE_cast(char *str, int len, PyObject *curs)
38 {
39     PyObject* obj = NULL;
40     int n, y=0, m=0, d=0;
41      
42     if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
43     
44     if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) {
45         if (str[0] == '-') {
46             obj = PyObject_GetAttrString(pyDateTypeP, "min");
47         }
48         else {
49             obj = PyObject_GetAttrString(pyDateTypeP, "max");
50         }
51     }
52
53     else {
54         n = typecast_parse_date(str, NULL, &len, &y, &m, &d);
55         Dprintf("typecast_PYDATE_cast: "
56                 "n = %d, len = %d, y = %d, m = %d, d = %d",
57                  n, len, y, m, d);
58         if (n != 3) {
59             PyErr_SetString(DataError, "unable to parse date");
60         }
61         else {
62             obj = PyObject_CallFunction(pyDateTypeP, "iii", y, m, d);
63         }
64     }
65     return obj;
66 }
67
68 /** DATETIME - cast a timestamp into a datetime python object **/
69
70 static PyObject *
71 typecast_PYDATETIME_cast(char *str, int len, PyObject *curs)
72 {
73     PyObject* obj = NULL;
74     int n, y=0, m=0, d=0;
75     int hh=0, mm=0, ss=0, us=0, tz=0;
76     char *tp = NULL;
77     
78     if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
79     
80     /* check for infinity */
81     if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) {
82         if (str[0] == '-') {
83             obj = PyObject_GetAttrString(pyDateTimeTypeP, "min");
84         }
85         else {
86             obj = PyObject_GetAttrString(pyDateTimeTypeP, "max");
87         }
88     }
89
90     else {
91         Dprintf("typecast_PYDATETIME_cast: s = %s", str);
92         n = typecast_parse_date(str, &tp, &len, &y, &m, &d);
93         Dprintf("typecast_PYDATE_cast: tp = %p "
94                 "n = %d, len = %d, y = %d, m = %d, d = %d",
95                  tp, n, len, y, m, d);        
96         if (n != 3) {
97             PyErr_SetString(DataError, "unable to parse date");
98         }
99         
100         if (len > 0) {
101             n = typecast_parse_time(tp, NULL, &len, &hh, &mm, &ss, &us, &tz);
102             Dprintf("typecast_PYDATETIME_cast: n = %d, len = %d, "
103                 "hh = %d, mm = %d, ss = %d, us = %d, tz = %d",
104                 n, len, hh, mm, ss, us, tz);
105             if (n < 3 || n > 5) {
106                 PyErr_SetString(DataError, "unable to parse time");
107             }
108         }
109         
110         if (ss > 59) {
111             mm += 1;
112             ss -= 60;
113         }
114         
115         if (n == 5 && ((cursorObject*)curs)->tzinfo_factory != Py_None) {
116             /* we have a time zone, calculate minutes and create
117                appropriate tzinfo object calling the factory */
118             PyObject *tzinfo;
119             Dprintf("typecast_PYDATETIME_cast: UTC offset = %dm", tz);
120             tzinfo = PyObject_CallFunction(
121                 ((cursorObject*)curs)->tzinfo_factory, "i", tz);
122             obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO",
123                  y, m, d, hh, mm, ss, us, tzinfo);
124             Dprintf("typecast_PYDATETIME_cast: tzinfo: %p, refcnt = %d",
125                     tzinfo, tzinfo->ob_refcnt);
126             Py_XDECREF(tzinfo);
127         }
128         else {
129             obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii",
130                  y, m, d, hh, mm, ss, us);
131         }
132     }
133     return obj;
134 }
135
136 /** TIME - parse time into a time object **/
137
138 static PyObject *
139 typecast_PYTIME_cast(char *str, int len, PyObject *curs)
140 {
141     PyObject* obj = NULL;
142     int n, hh=0, mm=0, ss=0, us=0, tz=0;
143     
144     if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
145         
146     n = typecast_parse_time(str, NULL, &len, &hh, &mm, &ss, &us, &tz);
147     Dprintf("typecast_PYTIME_cast: n = %d, len = %d, "
148             "hh = %d, mm = %d, ss = %d, us = %d, tz = %d",
149             n, len, hh, mm, ss, us, tz);
150                 
151     if (n < 3 || n > 5) {
152         PyErr_SetString(DataError, "unable to parse time");
153     }
154     else {
155         if (ss > 59) {
156             mm += 1;
157             ss -= 60;
158         }
159         obj = PyObject_CallFunction(pyTimeTypeP, "iiii", hh, mm, ss, us);
160     }
161     return obj;          
162 }
163
164 /** INTERVAL - parse an interval into a timedelta object **/
165
166 static PyObject *
167 typecast_PYINTERVAL_cast(char *str, int len, PyObject *curs)
168 {
169     long years = 0, months = 0, days = 0;
170     double hours = 0.0, minutes = 0.0, seconds = 0.0, hundredths = 0.0;
171     double v = 0.0, sign = 1.0, denominator = 1.0;
172     int part = 0, sec;
173     double micro;
174
175     if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
176
177     Dprintf("typecast_PYINTERVAL_cast: s = %s", str);
178     
179     while (len-- > 0 && *str) {
180         switch (*str) {
181
182         case '-':
183             sign = -1.0;
184             break;
185
186         case '0': case '1': case '2': case '3': case '4':
187         case '5': case '6': case '7': case '8': case '9':
188             v = v*10 + (double)*str - (double)'0';
189             if (part == 6){
190                 denominator *= 10;
191             }
192             break;
193
194         case 'y':
195             if (part == 0) {
196                 years = (long)(v*sign);
197                 str = skip_until_space2(str, &len);
198                 v = 0.0; sign = 1.0; part = 1;
199             }
200             break;
201
202         case 'm':
203             if (part <= 1) {
204                 months = (long)(v*sign);
205                 str = skip_until_space2(str, &len);
206                 v = 0.0; sign = 1.0; part = 2;
207             }
208             break;
209
210         case 'd':
211             if (part <= 2) {
212                 days = (long)(v*sign);
213                 str = skip_until_space2(str, &len);
214                 v = 0.0; sign = 1.0; part = 3;
215             }
216             break;
217
218         case ':':
219             if (part <= 3) {
220                 hours = v;
221                 v = 0.0; part = 4;
222             }
223             else if (part == 4) {
224                 minutes = v;
225                 v = 0.0; part = 5;
226             }
227             break;
228
229         case '.':
230             if (part == 5) {
231                 seconds = v;
232                 v = 0.0; part = 6;
233             }
234             break;   
235
236         default:
237             break;
238         }
239         
240         str++;
241     }
242
243     /* manage last value, be it minutes or seconds or hundredths of a second */
244     if (part == 4) {
245         minutes = v;
246     }
247     else if (part == 5) {
248         seconds = v;
249     }
250     else if (part == 6) {
251         hundredths = v;
252         hundredths = hundredths/denominator;
253     }
254     
255     /* calculates seconds */
256     if (sign < 0.0) {
257         seconds = - (hundredths + seconds + minutes*60 + hours*3600);
258     }
259     else {
260         seconds += hundredths + minutes*60 + hours*3600;
261     }
262
263     /* calculates days */ 
264     days += years*365 + months*30;
265
266     micro = (seconds - floor(seconds)) * 1000000.0;
267     sec = (int)floor(seconds);
268     return PyObject_CallFunction(pyDeltaTypeP, "iii",
269                                  days, sec, (int)round(micro));
270 }
271
272 /* psycopg defaults to using python datetime types */
273
274 #ifdef PSYCOPG_DEFAULT_PYDATETIME 
275 #define typecast_DATE_cast typecast_PYDATE_cast
276 #define typecast_TIME_cast typecast_PYTIME_cast
277 #define typecast_INTERVAL_cast typecast_PYINTERVAL_cast
278 #define typecast_DATETIME_cast typecast_PYDATETIME_cast
279 #endif