mirror of
				https://github.com/Infinidat/infi.clickhouse_orm.git
				synced 2025-10-31 15:57:32 +03:00 
			
		
		
		
	allow ISO 8601 compliant values in DateTimeField
This commit is contained in:
		
							parent
							
								
									444b8a6b39
								
							
						
					
					
						commit
						38472012db
					
				|  | @ -10,6 +10,7 @@ name = infi.clickhouse_orm | ||||||
| company = Infinidat | company = Infinidat | ||||||
| namespace_packages = ['infi'] | namespace_packages = ['infi'] | ||||||
| install_requires = [ | install_requires = [ | ||||||
|  | 	'iso8601 >= 0.1.12', | ||||||
| 	'pytz', | 	'pytz', | ||||||
| 	'requests', | 	'requests', | ||||||
| 	'setuptools', | 	'setuptools', | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ A `DateTimeField` can be assigned values from one of the following types: | ||||||
| -   datetime | -   datetime | ||||||
| -   date | -   date | ||||||
| -   integer - number of seconds since the Unix epoch | -   integer - number of seconds since the Unix epoch | ||||||
| -   string in `YYYY-MM-DD HH:MM:SS` format | -   string in `YYYY-MM-DD HH:MM:SS` format or [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-compatible format | ||||||
| 
 | 
 | ||||||
| The assigned value always gets converted to a timezone-aware `datetime` in UTC. If the assigned value is a timezone-aware `datetime` in another timezone, it will be converted to UTC. Otherwise, the assigned value is assumed to already be in UTC. | The assigned value always gets converted to a timezone-aware `datetime` in UTC. If the assigned value is a timezone-aware `datetime` in another timezone, it will be converted to UTC. Otherwise, the assigned value is assumed to already be in UTC. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| from six import string_types, text_type, binary_type | from six import string_types, text_type, binary_type | ||||||
| import datetime | import datetime | ||||||
|  | import iso8601 | ||||||
| import pytz | import pytz | ||||||
| import time | import time | ||||||
| from calendar import timegm | from calendar import timegm | ||||||
|  | @ -157,8 +158,16 @@ class DateTimeField(Field): | ||||||
|                     return datetime.datetime.utcfromtimestamp(value).replace(tzinfo=pytz.utc) |                     return datetime.datetime.utcfromtimestamp(value).replace(tzinfo=pytz.utc) | ||||||
|                 except ValueError: |                 except ValueError: | ||||||
|                     pass |                     pass | ||||||
|             dt = datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') |             try: | ||||||
|             return timezone_in_use.localize(dt).astimezone(pytz.utc) |                 # left the date naive in case of no tzinfo set | ||||||
|  |                 dt = iso8601.parse_date(value, default_timezone=None) | ||||||
|  |             except iso8601.ParseError as e: | ||||||
|  |                 raise ValueError(text_type(e)) | ||||||
|  | 
 | ||||||
|  |             # convert naive to aware | ||||||
|  |             if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None: | ||||||
|  |                 dt = timezone_in_use.localize(dt) | ||||||
|  |             return dt.astimezone(pytz.utc) | ||||||
|         raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value)) |         raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value)) | ||||||
| 
 | 
 | ||||||
|     def to_db_string(self, value, quote=True): |     def to_db_string(self, value, quote=True): | ||||||
|  |  | ||||||
|  | @ -13,14 +13,17 @@ class SimpleFieldsTest(unittest.TestCase): | ||||||
|         # Valid values |         # Valid values | ||||||
|         for value in (date(1970, 1, 1), datetime(1970, 1, 1), epoch, |         for value in (date(1970, 1, 1), datetime(1970, 1, 1), epoch, | ||||||
|                       epoch.astimezone(pytz.timezone('US/Eastern')), epoch.astimezone(pytz.timezone('Asia/Jerusalem')), |                       epoch.astimezone(pytz.timezone('US/Eastern')), epoch.astimezone(pytz.timezone('Asia/Jerusalem')), | ||||||
|                       '1970-01-01 00:00:00', '1970-01-17 00:00:17', '0000-00-00 00:00:00', 0): |                       '1970-01-01 00:00:00', '1970-01-17 00:00:17', '0000-00-00 00:00:00', 0, | ||||||
|  |                       '2017-07-26T08:31:05', '2017-07-26T08:31:05Z', '2017-07-26 08:31', | ||||||
|  |                       '2017-07-26T13:31:05+05', '2017-07-26 13:31:05+0500'): | ||||||
|             dt = f.to_python(value, pytz.utc) |             dt = f.to_python(value, pytz.utc) | ||||||
|             self.assertEquals(dt.tzinfo, pytz.utc) |             self.assertEquals(dt.tzinfo, pytz.utc) | ||||||
|             # Verify that conversion to and from db string does not change value |             # Verify that conversion to and from db string does not change value | ||||||
|             dt2 = f.to_python(f.to_db_string(dt, quote=False), pytz.utc) |             dt2 = f.to_python(f.to_db_string(dt, quote=False), pytz.utc) | ||||||
|             self.assertEquals(dt, dt2) |             self.assertEquals(dt, dt2) | ||||||
|         # Invalid values |         # Invalid values | ||||||
|         for value in ('nope', '21/7/1999', 0.5): |         for value in ('nope', '21/7/1999', 0.5, | ||||||
|  |                       '2017-01 15:06:00', '2017-01-01X15:06:00', '2017-13-01T15:06:00'): | ||||||
|             with self.assertRaises(ValueError): |             with self.assertRaises(ValueError): | ||||||
|                 f.to_python(value, pytz.utc) |                 f.to_python(value, pytz.utc) | ||||||
| 
 | 
 | ||||||
|  | @ -49,6 +52,19 @@ class SimpleFieldsTest(unittest.TestCase): | ||||||
|         dt = datetime(2017, 10, 5, tzinfo=pytz.timezone('Asia/Jerusalem')) |         dt = datetime(2017, 10, 5, tzinfo=pytz.timezone('Asia/Jerusalem')) | ||||||
|         self.assertEquals(f.to_python(dt, pytz.utc), date(2017, 10, 4)) |         self.assertEquals(f.to_python(dt, pytz.utc), date(2017, 10, 4)) | ||||||
| 
 | 
 | ||||||
|  |     def test_datetime_field_timezone(self): | ||||||
|  |         # Verify that conversion of timezone-aware datetime is correct | ||||||
|  |         f = DateTimeField() | ||||||
|  |         utc_value = datetime(2017, 7, 26, 8, 31, 5, tzinfo=pytz.UTC) | ||||||
|  |         for value  in ( | ||||||
|  |                 '2017-07-26T08:31:05', | ||||||
|  |                 '2017-07-26T08:31:05Z', | ||||||
|  |                 '2017-07-26T11:31:05+03', | ||||||
|  |                 '2017-07-26 11:31:05+0300', | ||||||
|  |                 '2017-07-26T03:31:05-0500', | ||||||
|  |         ): | ||||||
|  |             self.assertEquals(f.to_python(value, pytz.utc), utc_value) | ||||||
|  | 
 | ||||||
|     def test_uint8_field(self): |     def test_uint8_field(self): | ||||||
|         f = UInt8Field() |         f = UInt8Field() | ||||||
|         # Valid values |         # Valid values | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user