mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-31 15:57:31 +03:00 
			
		
		
		
	Merge remote-tracking branch 'origin/fix-536'
This commit is contained in:
		
						commit
						adf55babe8
					
				
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							|  | @ -9,6 +9,8 @@ What's new in psycopg 2.7.2 | ||||||
|   2.7 by mistake. |   2.7 by mistake. | ||||||
| - Don't display the password in `connection.dsn` when the connection | - Don't display the password in `connection.dsn` when the connection | ||||||
|   string is specified as an URI (:ticket:`#528`). |   string is specified as an URI (:ticket:`#528`). | ||||||
|  | - Return objects with timezone parsing "infinity" :sql:`timestamptz` | ||||||
|  |   (:ticket:`#536`). | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| What's new in psycopg 2.7.1 | What's new in psycopg 2.7.1 | ||||||
|  |  | ||||||
|  | @ -823,10 +823,12 @@ from the database.  See :ref:`unicode-handling` for details. | ||||||
| 
 | 
 | ||||||
| .. data:: PYDATE | .. data:: PYDATE | ||||||
|           PYDATETIME |           PYDATETIME | ||||||
|  |           PYDATETIMETZ | ||||||
|           PYINTERVAL |           PYINTERVAL | ||||||
|           PYTIME |           PYTIME | ||||||
|           PYDATEARRAY |           PYDATEARRAY | ||||||
|           PYDATETIMEARRAY |           PYDATETIMEARRAY | ||||||
|  |           PYDATETIMETZARRAY | ||||||
|           PYINTERVALARRAY |           PYINTERVALARRAY | ||||||
|           PYTIMEARRAY |           PYTIMEARRAY | ||||||
| 
 | 
 | ||||||
|  | @ -835,10 +837,12 @@ from the database.  See :ref:`unicode-handling` for details. | ||||||
| 
 | 
 | ||||||
| .. data:: MXDATE | .. data:: MXDATE | ||||||
|           MXDATETIME |           MXDATETIME | ||||||
|  |           MXDATETIMETZ | ||||||
|           MXINTERVAL |           MXINTERVAL | ||||||
|           MXTIME |           MXTIME | ||||||
|           MXDATEARRAY |           MXDATEARRAY | ||||||
|           MXDATETIMEARRAY |           MXDATETIMEARRAY | ||||||
|  |           MXDATETIMETZARRAY | ||||||
|           MXINTERVALARRAY |           MXINTERVALARRAY | ||||||
|           MXTIMEARRAY |           MXTIMEARRAY | ||||||
| 
 | 
 | ||||||
|  | @ -851,3 +855,5 @@ from the database.  See :ref:`unicode-handling` for details. | ||||||
|         module. In older versions they can be imported from the implementation |         module. In older versions they can be imported from the implementation | ||||||
|         module `!psycopg2._psycopg`. |         module `!psycopg2._psycopg`. | ||||||
| 
 | 
 | ||||||
|  | .. versionchanged:: 2.7.2 | ||||||
|  |         added `!*DATETIMETZ*` objects. | ||||||
|  |  | ||||||
|  | @ -43,16 +43,16 @@ from psycopg2._psycopg import (                             # noqa | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     from psycopg2._psycopg import (                         # noqa |     from psycopg2._psycopg import (                         # noqa | ||||||
|         MXDATE, MXDATETIME, MXINTERVAL, MXTIME, |         MXDATE, MXDATETIME, MXDATETIMETZ, MXINTERVAL, MXTIME, MXDATEARRAY, | ||||||
|         MXDATEARRAY, MXDATETIMEARRAY, MXINTERVALARRAY, MXTIMEARRAY, |         MXDATETIMEARRAY, MXDATETIMETZARRAY, MXINTERVALARRAY, MXTIMEARRAY, | ||||||
|         DateFromMx, TimeFromMx, TimestampFromMx, IntervalFromMx, ) |         DateFromMx, TimeFromMx, TimestampFromMx, IntervalFromMx, ) | ||||||
| except ImportError: | except ImportError: | ||||||
|     pass |     pass | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     from psycopg2._psycopg import (                         # noqa |     from psycopg2._psycopg import (                         # noqa | ||||||
|         PYDATE, PYDATETIME, PYINTERVAL, PYTIME, |         PYDATE, PYDATETIME, PYDATETIMETZ, PYINTERVAL, PYTIME, PYDATEARRAY, | ||||||
|         PYDATEARRAY, PYDATETIMEARRAY, PYINTERVALARRAY, PYTIMEARRAY, |         PYDATETIMEARRAY, PYDATETIMETZARRAY, PYINTERVALARRAY, PYTIMEARRAY, | ||||||
|         DateFromPy, TimeFromPy, TimestampFromPy, IntervalFromPy, ) |         DateFromPy, TimeFromPy, TimestampFromPy, IntervalFromPy, ) | ||||||
| except ImportError: | except ImportError: | ||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  | @ -197,6 +197,7 @@ typecast_UNKNOWN_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| #include "psycopg/typecast_builtins.c" | #include "psycopg/typecast_builtins.c" | ||||||
| 
 | 
 | ||||||
| #define typecast_PYDATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_PYDATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
|  | #define typecast_PYDATETIMETZARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_PYDATEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_PYDATEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_PYTIMEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_PYTIMEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_PYINTERVALARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_PYINTERVALARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
|  | @ -204,10 +205,12 @@ typecast_UNKNOWN_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| /* a list of initializers, used to make the typecasters accessible anyway */ | /* a list of initializers, used to make the typecasters accessible anyway */ | ||||||
| static typecastObject_initlist typecast_pydatetime[] = { | static typecastObject_initlist typecast_pydatetime[] = { | ||||||
|     {"PYDATETIME", typecast_DATETIME_types, typecast_PYDATETIME_cast}, |     {"PYDATETIME", typecast_DATETIME_types, typecast_PYDATETIME_cast}, | ||||||
|  |     {"PYDATETIMETZ", typecast_DATETIMETZ_types, typecast_PYDATETIMETZ_cast}, | ||||||
|     {"PYTIME", typecast_TIME_types, typecast_PYTIME_cast}, |     {"PYTIME", typecast_TIME_types, typecast_PYTIME_cast}, | ||||||
|     {"PYDATE", typecast_DATE_types, typecast_PYDATE_cast}, |     {"PYDATE", typecast_DATE_types, typecast_PYDATE_cast}, | ||||||
|     {"PYINTERVAL", typecast_INTERVAL_types, typecast_PYINTERVAL_cast}, |     {"PYINTERVAL", typecast_INTERVAL_types, typecast_PYINTERVAL_cast}, | ||||||
|     {"PYDATETIMEARRAY", typecast_DATETIMEARRAY_types, typecast_PYDATETIMEARRAY_cast, "PYDATETIME"}, |     {"PYDATETIMEARRAY", typecast_DATETIMEARRAY_types, typecast_PYDATETIMEARRAY_cast, "PYDATETIME"}, | ||||||
|  |     {"PYDATETIMETZARRAY", typecast_DATETIMETZARRAY_types, typecast_PYDATETIMETZARRAY_cast, "PYDATETIMETZ"}, | ||||||
|     {"PYTIMEARRAY", typecast_TIMEARRAY_types, typecast_PYTIMEARRAY_cast, "PYTIME"}, |     {"PYTIMEARRAY", typecast_TIMEARRAY_types, typecast_PYTIMEARRAY_cast, "PYTIME"}, | ||||||
|     {"PYDATEARRAY", typecast_DATEARRAY_types, typecast_PYDATEARRAY_cast, "PYDATE"}, |     {"PYDATEARRAY", typecast_DATEARRAY_types, typecast_PYDATEARRAY_cast, "PYDATE"}, | ||||||
|     {"PYINTERVALARRAY", typecast_INTERVALARRAY_types, typecast_PYINTERVALARRAY_cast, "PYINTERVAL"}, |     {"PYINTERVALARRAY", typecast_INTERVALARRAY_types, typecast_PYINTERVALARRAY_cast, "PYINTERVAL"}, | ||||||
|  | @ -216,6 +219,7 @@ static typecastObject_initlist typecast_pydatetime[] = { | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_MXDATETIME | #ifdef HAVE_MXDATETIME | ||||||
| #define typecast_MXDATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_MXDATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
|  | #define typecast_MXDATETIMETZARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_MXDATEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_MXDATEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_MXTIMEARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_MXTIMEARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
| #define typecast_MXINTERVALARRAY_cast typecast_GENERIC_ARRAY_cast | #define typecast_MXINTERVALARRAY_cast typecast_GENERIC_ARRAY_cast | ||||||
|  | @ -223,10 +227,12 @@ static typecastObject_initlist typecast_pydatetime[] = { | ||||||
| /* a list of initializers, used to make the typecasters accessible anyway */ | /* a list of initializers, used to make the typecasters accessible anyway */ | ||||||
| static typecastObject_initlist typecast_mxdatetime[] = { | static typecastObject_initlist typecast_mxdatetime[] = { | ||||||
|     {"MXDATETIME", typecast_DATETIME_types, typecast_MXDATE_cast}, |     {"MXDATETIME", typecast_DATETIME_types, typecast_MXDATE_cast}, | ||||||
|  |     {"MXDATETIMETZ", typecast_DATETIMETZ_types, typecast_MXDATE_cast}, | ||||||
|     {"MXTIME", typecast_TIME_types, typecast_MXTIME_cast}, |     {"MXTIME", typecast_TIME_types, typecast_MXTIME_cast}, | ||||||
|     {"MXDATE", typecast_DATE_types, typecast_MXDATE_cast}, |     {"MXDATE", typecast_DATE_types, typecast_MXDATE_cast}, | ||||||
|     {"MXINTERVAL", typecast_INTERVAL_types, typecast_MXINTERVAL_cast}, |     {"MXINTERVAL", typecast_INTERVAL_types, typecast_MXINTERVAL_cast}, | ||||||
|     {"MXDATETIMEARRAY", typecast_DATETIMEARRAY_types, typecast_MXDATETIMEARRAY_cast, "MXDATETIME"}, |     {"MXDATETIMEARRAY", typecast_DATETIMEARRAY_types, typecast_MXDATETIMEARRAY_cast, "MXDATETIME"}, | ||||||
|  |     {"MXDATETIMETZARRAY", typecast_DATETIMETZARRAY_types, typecast_MXDATETIMETZARRAY_cast, "MXDATETIMETZ"}, | ||||||
|     {"MXTIMEARRAY", typecast_TIMEARRAY_types, typecast_MXTIMEARRAY_cast, "MXTIME"}, |     {"MXTIMEARRAY", typecast_TIMEARRAY_types, typecast_MXTIMEARRAY_cast, "MXTIME"}, | ||||||
|     {"MXDATEARRAY", typecast_DATEARRAY_types, typecast_MXDATEARRAY_cast, "MXDATE"}, |     {"MXDATEARRAY", typecast_DATEARRAY_types, typecast_MXDATEARRAY_cast, "MXDATE"}, | ||||||
|     {"MXINTERVALARRAY", typecast_INTERVALARRAY_types, typecast_MXINTERVALARRAY_cast, "MXINTERVAL"}, |     {"MXINTERVALARRAY", typecast_INTERVALARRAY_types, typecast_MXINTERVALARRAY_cast, "MXINTERVAL"}, | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ static long int typecast_UNICODE_types[] = {19, 18, 25, 1042, 1043, 0}; | ||||||
| static long int typecast_STRING_types[] = {19, 18, 25, 1042, 1043, 0}; | static long int typecast_STRING_types[] = {19, 18, 25, 1042, 1043, 0}; | ||||||
| static long int typecast_BOOLEAN_types[] = {16, 0}; | static long int typecast_BOOLEAN_types[] = {16, 0}; | ||||||
| static long int typecast_DATETIME_types[] = {1114, 1184, 704, 1186, 0}; | static long int typecast_DATETIME_types[] = {1114, 1184, 704, 1186, 0}; | ||||||
|  | static long int typecast_DATETIMETZ_types[] = {1184, 0}; | ||||||
| static long int typecast_TIME_types[] = {1083, 1266, 0}; | static long int typecast_TIME_types[] = {1083, 1266, 0}; | ||||||
| static long int typecast_DATE_types[] = {1082, 0}; | static long int typecast_DATE_types[] = {1082, 0}; | ||||||
| static long int typecast_INTERVAL_types[] = {704, 1186, 0}; | static long int typecast_INTERVAL_types[] = {704, 1186, 0}; | ||||||
|  | @ -20,6 +21,7 @@ static long int typecast_UNICODEARRAY_types[] = {1002, 1003, 1009, 1014, 1015, 0 | ||||||
| static long int typecast_STRINGARRAY_types[] = {1002, 1003, 1009, 1014, 1015, 0}; | static long int typecast_STRINGARRAY_types[] = {1002, 1003, 1009, 1014, 1015, 0}; | ||||||
| static long int typecast_BOOLEANARRAY_types[] = {1000, 0}; | static long int typecast_BOOLEANARRAY_types[] = {1000, 0}; | ||||||
| static long int typecast_DATETIMEARRAY_types[] = {1115, 1185, 0}; | static long int typecast_DATETIMEARRAY_types[] = {1115, 1185, 0}; | ||||||
|  | static long int typecast_DATETIMETZARRAY_types[] = {1185, 0}; | ||||||
| static long int typecast_TIMEARRAY_types[] = {1183, 1270, 0}; | static long int typecast_TIMEARRAY_types[] = {1183, 1270, 0}; | ||||||
| static long int typecast_DATEARRAY_types[] = {1182, 0}; | static long int typecast_DATEARRAY_types[] = {1182, 0}; | ||||||
| static long int typecast_INTERVALARRAY_types[] = {1187, 0}; | static long int typecast_INTERVALARRAY_types[] = {1187, 0}; | ||||||
|  | @ -41,6 +43,7 @@ static typecastObject_initlist typecast_builtins[] = { | ||||||
|   {"STRING", typecast_STRING_types, typecast_STRING_cast, NULL}, |   {"STRING", typecast_STRING_types, typecast_STRING_cast, NULL}, | ||||||
|   {"BOOLEAN", typecast_BOOLEAN_types, typecast_BOOLEAN_cast, NULL}, |   {"BOOLEAN", typecast_BOOLEAN_types, typecast_BOOLEAN_cast, NULL}, | ||||||
|   {"DATETIME", typecast_DATETIME_types, typecast_DATETIME_cast, NULL}, |   {"DATETIME", typecast_DATETIME_types, typecast_DATETIME_cast, NULL}, | ||||||
|  |   {"DATETIMETZ", typecast_DATETIMETZ_types, typecast_DATETIMETZ_cast, NULL}, | ||||||
|   {"TIME", typecast_TIME_types, typecast_TIME_cast, NULL}, |   {"TIME", typecast_TIME_types, typecast_TIME_cast, NULL}, | ||||||
|   {"DATE", typecast_DATE_types, typecast_DATE_cast, NULL}, |   {"DATE", typecast_DATE_types, typecast_DATE_cast, NULL}, | ||||||
|   {"INTERVAL", typecast_INTERVAL_types, typecast_INTERVAL_cast, NULL}, |   {"INTERVAL", typecast_INTERVAL_types, typecast_INTERVAL_cast, NULL}, | ||||||
|  |  | ||||||
|  | @ -80,34 +80,63 @@ typecast_PYDATE_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|     return obj; |     return obj; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** DATETIME - cast a timestamp into a datetime python object **/ | /* convert the strings -infinity and infinity into a datetime with timezone */ | ||||||
|  | static PyObject * | ||||||
|  | _parse_inftz(const char *str, PyObject *curs) | ||||||
|  | { | ||||||
|  |     PyObject *rv = NULL; | ||||||
|  |     PyObject *m = NULL; | ||||||
|  |     PyObject *tzinfo_factory = NULL; | ||||||
|  |     PyObject *tzinfo = NULL; | ||||||
|  |     PyObject *args = NULL; | ||||||
|  |     PyObject *kwargs = NULL; | ||||||
|  |     PyObject *replace = NULL; | ||||||
|  | 
 | ||||||
|  |     if (!(m = PyObject_GetAttrString( | ||||||
|  |             (PyObject*)PyDateTimeAPI->DateTimeType, | ||||||
|  |             (str[0] == '-' ? "min" : "max")))) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     tzinfo_factory = ((cursorObject *)curs)->tzinfo_factory; | ||||||
|  |     if (tzinfo_factory == Py_None) { | ||||||
|  |         rv = m; | ||||||
|  |         m = NULL; | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!(tzinfo = PyObject_CallFunction(tzinfo_factory, "i", 0))) { | ||||||
|  |         goto exit; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* m.replace(tzinfo=tzinfo) */ | ||||||
|  |     if (!(args = PyTuple_New(0))) { goto exit; } | ||||||
|  |     if (!(kwargs = PyDict_New())) { goto exit; } | ||||||
|  |     if (0 != PyDict_SetItemString(kwargs, "tzinfo", tzinfo)) { goto exit; } | ||||||
|  |     if (!(replace = PyObject_GetAttrString(m, "replace"))) { goto exit; } | ||||||
|  |     rv = PyObject_Call(replace, args, kwargs); | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  |     Py_XDECREF(replace); | ||||||
|  |     Py_XDECREF(args); | ||||||
|  |     Py_XDECREF(kwargs); | ||||||
|  |     Py_XDECREF(tzinfo); | ||||||
|  |     Py_XDECREF(m); | ||||||
|  | 
 | ||||||
|  |     return rv; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) | _parse_noninftz(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| { | { | ||||||
|     PyObject* obj = NULL; |     PyObject* rv = NULL; | ||||||
|     PyObject *tzinfo = NULL; |     PyObject *tzinfo = NULL; | ||||||
|     PyObject *tzinfo_factory; |     PyObject *tzinfo_factory; | ||||||
|     int n, y=0, m=0, d=0; |     int n, y=0, m=0, d=0; | ||||||
|     int hh=0, mm=0, ss=0, us=0, tz=0; |     int hh=0, mm=0, ss=0, us=0, tz=0; | ||||||
|     const char *tp = NULL; |     const char *tp = NULL; | ||||||
| 
 | 
 | ||||||
|     if (str == NULL) { Py_RETURN_NONE; } |     Dprintf("typecast_PYDATETIMETZ_cast: s = %s", str); | ||||||
| 
 |  | ||||||
|     /* check for infinity */ |  | ||||||
|     if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { |  | ||||||
|         if (str[0] == '-') { |  | ||||||
|             obj = PyObject_GetAttrString( |  | ||||||
|                 (PyObject*)PyDateTimeAPI->DateTimeType, "min"); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             obj = PyObject_GetAttrString( |  | ||||||
|                 (PyObject*)PyDateTimeAPI->DateTimeType, "max"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     else { |  | ||||||
|         Dprintf("typecast_PYDATETIME_cast: s = %s", str); |  | ||||||
|     n = typecast_parse_date(str, &tp, &len, &y, &m, &d); |     n = typecast_parse_date(str, &tp, &len, &y, &m, &d); | ||||||
|     Dprintf("typecast_PYDATE_cast: tp = %p " |     Dprintf("typecast_PYDATE_cast: tp = %p " | ||||||
|             "n = %d, len = " FORMAT_CODE_PY_SSIZE_T "," |             "n = %d, len = " FORMAT_CODE_PY_SSIZE_T "," | ||||||
|  | @ -115,18 +144,18 @@ typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|              tp, n, len, y, m, d); |              tp, n, len, y, m, d); | ||||||
|     if (n != 3) { |     if (n != 3) { | ||||||
|         PyErr_SetString(DataError, "unable to parse date"); |         PyErr_SetString(DataError, "unable to parse date"); | ||||||
|             return NULL; |         goto exit; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (len > 0) { |     if (len > 0) { | ||||||
|         n = typecast_parse_time(tp, NULL, &len, &hh, &mm, &ss, &us, &tz); |         n = typecast_parse_time(tp, NULL, &len, &hh, &mm, &ss, &us, &tz); | ||||||
|             Dprintf("typecast_PYDATETIME_cast: n = %d," |         Dprintf("typecast_PYDATETIMETZ_cast: n = %d," | ||||||
|             " len = " FORMAT_CODE_PY_SSIZE_T "," |             " len = " FORMAT_CODE_PY_SSIZE_T "," | ||||||
|             " hh = %d, mm = %d, ss = %d, us = %d, tz = %d", |             " hh = %d, mm = %d, ss = %d, us = %d, tz = %d", | ||||||
|             n, len, hh, mm, ss, us, tz); |             n, len, hh, mm, ss, us, tz); | ||||||
|         if (n < 3 || n > 6) { |         if (n < 3 || n > 6) { | ||||||
|             PyErr_SetString(DataError, "unable to parse time"); |             PyErr_SetString(DataError, "unable to parse time"); | ||||||
|                 return NULL; |             goto exit; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -141,30 +170,62 @@ typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|     if (n >= 5 && tzinfo_factory != Py_None) { |     if (n >= 5 && tzinfo_factory != Py_None) { | ||||||
|         /* we have a time zone, calculate minutes and create
 |         /* we have a time zone, calculate minutes and create
 | ||||||
|            appropriate tzinfo object calling the factory */ |            appropriate tzinfo object calling the factory */ | ||||||
|             Dprintf("typecast_PYDATETIME_cast: UTC offset = %ds", tz); |         Dprintf("typecast_PYDATETIMETZ_cast: UTC offset = %ds", tz); | ||||||
| 
 | 
 | ||||||
|         /* The datetime module requires that time zone offsets be
 |         /* The datetime module requires that time zone offsets be
 | ||||||
|            a whole number of minutes, so truncate the seconds to the |            a whole number of minutes, so truncate the seconds to the | ||||||
|            closest minute. */ |            closest minute. */ | ||||||
|         // printf("%d %d %d\n", tz, tzmin, round(tz / 60.0));
 |         // printf("%d %d %d\n", tz, tzmin, round(tz / 60.0));
 | ||||||
|             tzinfo = PyObject_CallFunction(tzinfo_factory, "i", |         if (!(tzinfo = PyObject_CallFunction(tzinfo_factory, "i", | ||||||
|                 (int)round(tz / 60.0)); |                 (int)round(tz / 60.0)))) { | ||||||
|  |             goto exit; | ||||||
|  |         } | ||||||
|     } else { |     } else { | ||||||
|         Py_INCREF(Py_None); |         Py_INCREF(Py_None); | ||||||
|         tzinfo = Py_None; |         tzinfo = Py_None; | ||||||
|     } |     } | ||||||
|         if (tzinfo != NULL) { | 
 | ||||||
|             obj = PyObject_CallFunction( |     Dprintf("typecast_PYDATETIMETZ_cast: tzinfo: %p, refcnt = " | ||||||
|  |         FORMAT_CODE_PY_SSIZE_T, | ||||||
|  |         tzinfo, Py_REFCNT(tzinfo)); | ||||||
|  |     rv = PyObject_CallFunction( | ||||||
|         (PyObject*)PyDateTimeAPI->DateTimeType, "iiiiiiiO", |         (PyObject*)PyDateTimeAPI->DateTimeType, "iiiiiiiO", | ||||||
|         y, m, d, hh, mm, ss, us, tzinfo); |         y, m, d, hh, mm, ss, us, tzinfo); | ||||||
|             Dprintf("typecast_PYDATETIME_cast: tzinfo: %p, refcnt = " | 
 | ||||||
|                 FORMAT_CODE_PY_SSIZE_T, | exit: | ||||||
|                 tzinfo, Py_REFCNT(tzinfo) |     Py_XDECREF(tzinfo); | ||||||
|               ); |     return rv; | ||||||
|             Py_DECREF(tzinfo); | } | ||||||
|  | 
 | ||||||
|  | /** DATETIME - cast a timestamp into a datetime python object **/ | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | typecast_PYDATETIME_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|  | { | ||||||
|  |     if (str == NULL) { Py_RETURN_NONE; } | ||||||
|  | 
 | ||||||
|  |     /* check for infinity */ | ||||||
|  |     if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { | ||||||
|  |         return PyObject_GetAttrString( | ||||||
|  |             (PyObject*)PyDateTimeAPI->DateTimeType, | ||||||
|  |             (str[0] == '-' ? "min" : "max")); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return _parse_noninftz(str, len, curs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** DATETIMETZ - cast a timestamptz into a datetime python object **/ | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | typecast_PYDATETIMETZ_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
|  | { | ||||||
|  |     if (str == NULL) { Py_RETURN_NONE; } | ||||||
|  | 
 | ||||||
|  |     if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { | ||||||
|  |         return _parse_inftz(str, curs); | ||||||
|     } |     } | ||||||
|     return obj; | 
 | ||||||
|  |     return _parse_noninftz(str, len, curs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** TIME - parse time into a time object **/ | /** TIME - parse time into a time object **/ | ||||||
|  | @ -345,4 +406,5 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| #define typecast_TIME_cast typecast_PYTIME_cast | #define typecast_TIME_cast typecast_PYTIME_cast | ||||||
| #define typecast_INTERVAL_cast typecast_PYINTERVAL_cast | #define typecast_INTERVAL_cast typecast_PYINTERVAL_cast | ||||||
| #define typecast_DATETIME_cast typecast_PYDATETIME_cast | #define typecast_DATETIME_cast typecast_PYDATETIME_cast | ||||||
|  | #define typecast_DATETIMETZ_cast typecast_PYDATETIMETZ_cast | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -248,5 +248,6 @@ typecast_MXINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs) | ||||||
| #define typecast_TIME_cast typecast_MXTIME_cast | #define typecast_TIME_cast typecast_MXTIME_cast | ||||||
| #define typecast_INTERVAL_cast typecast_MXINTERVAL_cast | #define typecast_INTERVAL_cast typecast_MXINTERVAL_cast | ||||||
| #define typecast_DATETIME_cast typecast_MXDATE_cast | #define typecast_DATETIME_cast typecast_MXDATE_cast | ||||||
|  | #define typecast_DATETIMETZ_cast typecast_MXDATE_cast | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -528,9 +528,10 @@ have_mxdatetime = False | ||||||
| use_pydatetime = int(parser.get('build_ext', 'use_pydatetime')) | use_pydatetime = int(parser.get('build_ext', 'use_pydatetime')) | ||||||
| 
 | 
 | ||||||
| # check for mx package | # check for mx package | ||||||
|  | mxincludedir = '' | ||||||
| if parser.has_option('build_ext', 'mx_include_dir'): | if parser.has_option('build_ext', 'mx_include_dir'): | ||||||
|     mxincludedir = parser.get('build_ext', 'mx_include_dir') |     mxincludedir = parser.get('build_ext', 'mx_include_dir') | ||||||
| else: | if not mxincludedir: | ||||||
|     mxincludedir = os.path.join(get_python_inc(plat_specific=1), "mx") |     mxincludedir = os.path.join(get_python_inc(plat_specific=1), "mx") | ||||||
| if mxincludedir.strip() and os.path.exists(mxincludedir): | if mxincludedir.strip() and os.path.exists(mxincludedir): | ||||||
|     # Build the support for mx: we will check at runtime if it can be imported |     # Build the support for mx: we will check at runtime if it can be imported | ||||||
|  |  | ||||||
|  | @ -392,6 +392,25 @@ class DatetimeTests(ConnectingTestCase, CommonDatetimeTestsMixin): | ||||||
|         self.assertRaises(OverflowError, f, '00:00:100000000000000000:00') |         self.assertRaises(OverflowError, f, '00:00:100000000000000000:00') | ||||||
|         self.assertRaises(OverflowError, f, '00:00:00.100000000000000000') |         self.assertRaises(OverflowError, f, '00:00:00.100000000000000000') | ||||||
| 
 | 
 | ||||||
|  |     def test_adapt_infinity_tz(self): | ||||||
|  |         from datetime import datetime | ||||||
|  | 
 | ||||||
|  |         t = self.execute("select 'infinity'::timestamp") | ||||||
|  |         self.assert_(t.tzinfo is None) | ||||||
|  |         self.assert_(t > datetime(4000, 1, 1)) | ||||||
|  | 
 | ||||||
|  |         t = self.execute("select '-infinity'::timestamp") | ||||||
|  |         self.assert_(t.tzinfo is None) | ||||||
|  |         self.assert_(t < datetime(1000, 1, 1)) | ||||||
|  | 
 | ||||||
|  |         t = self.execute("select 'infinity'::timestamptz") | ||||||
|  |         self.assert_(t.tzinfo is not None) | ||||||
|  |         self.assert_(t > datetime(4000, 1, 1, tzinfo=FixedOffsetTimezone())) | ||||||
|  | 
 | ||||||
|  |         t = self.execute("select '-infinity'::timestamptz") | ||||||
|  |         self.assert_(t.tzinfo is not None) | ||||||
|  |         self.assert_(t < datetime(1000, 1, 1, tzinfo=FixedOffsetTimezone())) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| # Only run the datetime tests if psycopg was compiled with support. | # Only run the datetime tests if psycopg was compiled with support. | ||||||
| if not hasattr(psycopg2.extensions, 'PYDATETIME'): | if not hasattr(psycopg2.extensions, 'PYDATETIME'): | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user