e6data-python-connector 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
e6xdb/common.py ADDED
@@ -0,0 +1,269 @@
1
+ """Package private common utilities. Do not use directly.
2
+ Many docstrings in this file are based on PEP-249, which is in the public domain.
3
+ """
4
+
5
+ from __future__ import absolute_import
6
+ from __future__ import unicode_literals
7
+
8
+ import abc
9
+ import collections
10
+ import datetime
11
+ import logging
12
+ import time
13
+ from builtins import bytes
14
+ from builtins import int
15
+ from builtins import object
16
+ from builtins import str
17
+
18
+ from future.utils import with_metaclass
19
+ from past.builtins import basestring
20
+
21
+ from e6xdb.exceptions import ProgrammingError
22
+
23
+ _logger = logging.getLogger(__name__)
24
+
25
+
26
+ class DBAPICursor(with_metaclass(abc.ABCMeta, object)):
27
+ """Base class for some common DB-API logic"""
28
+
29
+ _STATE_NONE = 0
30
+ _STATE_RUNNING = 1
31
+ _STATE_FINISHED = 2
32
+
33
+ def __init__(self, poll_interval=1):
34
+ self._poll_interval = poll_interval
35
+ self._reset_state()
36
+ self.lastrowid = None
37
+ self._data = None
38
+
39
+ def _reset_state(self):
40
+ """Reset state about the previous query in preparation for running another query"""
41
+ # State to return as part of DB-API
42
+ self._rownumber = 0
43
+
44
+ # Internal helper state
45
+ self._data = collections.deque()
46
+ self._columns = None
47
+
48
+ def _fetch_while(self, fn):
49
+ _logger.info("Commons - fetch while.... fn type - {}".format(type(fn)))
50
+ while fn():
51
+ _logger.info("fetching next fetch more from fetch while")
52
+ self._fetch_more()
53
+ if fn():
54
+ time.sleep(self._poll_interval)
55
+
56
+ @abc.abstractmethod
57
+ def description(self):
58
+ raise NotImplementedError # pragma: no cover
59
+
60
+ def close(self):
61
+ """By default, do nothing"""
62
+ pass
63
+
64
+ @abc.abstractmethod
65
+ def _fetch_more(self):
66
+ """Get more results, append it to ``self._data``, and update ``self._state``."""
67
+ raise NotImplementedError # pragma: no cover
68
+
69
+ @property
70
+ def rowcount(self):
71
+ """By default, return -1 to indicate that this is not supported."""
72
+ return self.rowcount
73
+
74
+ @abc.abstractmethod
75
+ def execute(self, operation, parameters=None):
76
+ """Prepare and execute a database operation (query or command).
77
+ Parameters may be provided as sequence or mapping and will be bound to variables in the
78
+ operation. Variables are specified in a database-specific notation (see the e6xdb's
79
+ ``paramstyle`` attribute for details).
80
+ Return values are not defined.
81
+ """
82
+ raise NotImplementedError # pragma: no cover
83
+
84
+ def executemany(self, operation, seq_of_parameters):
85
+ """Prepare a database operation (query or command) and then execute it against all parameter
86
+ sequences or mappings found in the sequence ``seq_of_parameters``.
87
+ Only the final result set is retained.
88
+ Return values are not defined.
89
+ """
90
+ for parameters in seq_of_parameters[:-1]:
91
+ self.execute(operation, parameters)
92
+ # while self._state != self._STATE_FINISHED:
93
+ # self._fetch_more()
94
+ if seq_of_parameters:
95
+ self.execute(operation, seq_of_parameters[-1])
96
+
97
+ def fetchone(self):
98
+ """Fetch the next row of a query result set, returning a single sequence, or ``None`` when
99
+ no more data is available.
100
+ An :py:class:`~pyhive.exc.Error` (or subclass) exception is raised if the previous call to
101
+ :py:meth:`execute` did not produce any result set or no call was issued yet.
102
+ """
103
+ # if self._state == self._STATE_NONE:
104
+ # raise ProgrammingError("No query yet")
105
+ #
106
+ # # Sleep until we're done or we have some data to return
107
+ # self._fetch_while(lambda: not self._data and self._state != self._STATE_FINISHED)
108
+
109
+ # Sleep until we're done or we have some data to return
110
+ # self._fetch_while(lambda: not self._data and self._state != self._STATE_FINISHED)
111
+ if not self._data:
112
+ return None
113
+ else:
114
+ # if self._rownumber <= 1000:
115
+ # _logger.info("Commons - Breaking the loop after 1000Commons - fetch many records")
116
+ # return None
117
+ self._rownumber += 1
118
+ return self._data.popleft()
119
+
120
+ def fetchmany(self, size=None):
121
+ """Fetch the next set of rows of a query result, returning a sequence of sequences (e.g. a
122
+ list of tuples). An empty sequence is returned when no more rows are available.
123
+ The number of rows to fetch per call is specified by the parameter. If it is not given, the
124
+ cursor's arraysize determines the number of rows to be fetched. The method should try to
125
+ fetch as many rows as indicated by the size parameter. If this is not possible due to the
126
+ specified number of rows not being available, fewer rows may be returned.
127
+ An :py:class:`~pyhive.exc.Error` (or subclass) exception is raised if the previous call to
128
+ :py:meth:`execute` did not produce any result set or no call was issued yet.
129
+ """
130
+ _logger.info("Commons - fetch many.... size - {}".format(size))
131
+ rowsToReturn = self.fetchone()
132
+
133
+ if rowsToReturn is None:
134
+ return list()
135
+ return list(rowsToReturn)
136
+
137
+ def fetchall(self):
138
+ """Fetch all (remaining) rows of a query result, returning them as a sequence of sequences
139
+ (e.g. a list of tuples).
140
+ An :py:class:`~pyhive.exc.Error` (or subclass) exception is raised if the previous call to
141
+ :py:meth:`execute` did not produce any result set or no call was issued yet.
142
+ """
143
+ _logger.info("Commons - fetch all")
144
+ return list(iter(self.fetchone, None))
145
+
146
+ @property
147
+ def arraysize(self):
148
+ """This read/write attribute specifies the number of rows to fetch at a time with
149
+ :py:meth:`fetchmany`. It defaults to 1 meaning to fetch a single row at a time.
150
+ """
151
+ return self._arraysize
152
+
153
+ @arraysize.setter
154
+ def arraysize(self, value):
155
+ self._arraysize = value
156
+
157
+ def setinputsizes(self, sizes):
158
+ """Does nothing by default"""
159
+ pass
160
+
161
+ def setoutputsize(self, size, column=None):
162
+ """Does nothing by default"""
163
+ pass
164
+
165
+ #
166
+ # Optional DB API Extensions
167
+ #
168
+
169
+ @property
170
+ def rownumber(self):
171
+ """This read-only attribute should provide the current 0-based index of the cursor in the
172
+ result set.
173
+ The index can be seen as index of the cursor in a sequence (the result set). The next fetch
174
+ operation will fetch the row indexed by ``rownumber`` in that sequence.
175
+ """
176
+ return self._rownumber
177
+
178
+ def __next__(self):
179
+ """Return the next row from the currently executing SQL statement using the same semantics
180
+ as :py:meth:`fetchone`. A ``StopIteration`` exception is raised when the result set is
181
+ exhausted.
182
+ """
183
+ _logger.info("Commons - fetching the next row")
184
+ one = self.fetchone()
185
+ if one is None:
186
+ raise StopIteration
187
+ else:
188
+ return one
189
+
190
+ next = __next__
191
+
192
+ def __iter__(self):
193
+ """Return self to make cursors compatible to the iteration protocol."""
194
+ return self
195
+
196
+
197
+ class DBAPITypeObject(object):
198
+ # Taken from http://www.python.org/dev/peps/pep-0249/#implementation-hints
199
+ def __init__(self, *values):
200
+ self.values = values
201
+
202
+ def __cmp__(self, other):
203
+ if other in self.values:
204
+ return 0
205
+ if other < self.values:
206
+ return 1
207
+ else:
208
+ return -1
209
+
210
+
211
+ class ParamEscaper(object):
212
+ _DATE_FORMAT = "%Y-%m-%d"
213
+ _TIME_FORMAT = "%H:%M:%S.%f"
214
+ _DATETIME_FORMAT = "{} {}".format(_DATE_FORMAT, _TIME_FORMAT)
215
+
216
+ def escape_args(self, parameters):
217
+ if isinstance(parameters, dict):
218
+ return {k: self.escape_item(v) for k, v in parameters.items()}
219
+ elif isinstance(parameters, (list, tuple)):
220
+ return tuple(self.escape_item(x) for x in parameters)
221
+ else:
222
+ raise ProgrammingError("Unsupported param format: {}".format(parameters))
223
+
224
+ def escape_number(self, item):
225
+ return item
226
+
227
+ def escape_string(self, item):
228
+ # Need to decode UTF-8 because of old sqlalchemy.
229
+ # Newer SQLAlchemy checks dialect.supports_unicode_binds before encoding Unicode strings
230
+ # as byte strings. The old version always encodes Unicode as byte strings, which breaks
231
+ # string formatting here.
232
+ if isinstance(item, bytes):
233
+ item = item.decode('utf-8')
234
+ # This is good enough when backslashes are literal, newlines are just followed, and the way
235
+ # to escape a single quote is to put two single quotes.
236
+ # (i.e. only special character is single quote)
237
+ return "'{}'".format(item.replace("'", "''"))
238
+
239
+ def escape_sequence(self, item):
240
+ l = map(str, map(self.escape_item, item))
241
+ return '(' + ','.join(l) + ')'
242
+
243
+ def escape_datetime(self, item, format, cutoff=0):
244
+ dt_str = item.strftime(format)
245
+ formatted = dt_str[:-cutoff] if cutoff and format.endswith(".%f") else dt_str
246
+ return "'{}'".format(formatted)
247
+
248
+ def escape_item(self, item):
249
+ if item is None:
250
+ return 'NULL'
251
+ elif isinstance(item, (int, float)):
252
+ return self.escape_number(item)
253
+ elif isinstance(item, basestring):
254
+ return self.escape_string(item)
255
+ elif isinstance(item, collections.Iterable):
256
+ return self.escape_sequence(item)
257
+ elif isinstance(item, datetime.datetime):
258
+ return self.escape_datetime(item, self._DATETIME_FORMAT)
259
+ elif isinstance(item, datetime.date):
260
+ return self.escape_datetime(item, self._DATE_FORMAT)
261
+ else:
262
+ raise ProgrammingError("Unsupported object {}".format(item))
263
+
264
+
265
+ class UniversalSet(object):
266
+ """set containing everything"""
267
+
268
+ def __contains__(self, item):
269
+ return True
e6xdb/constants.py ADDED
@@ -0,0 +1,32 @@
1
+ import pytz
2
+
3
+ PRIMITIVE_TYPES = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 19, 20, 21}
4
+ COMPLEX_TYPES = {10, 11, 12, 13, 14}
5
+ COLLECTION_TYPES = {10, 11}
6
+ TYPE_NAMES = {
7
+ 0: "BOOLEAN",
8
+ 1: "TINYINT",
9
+ 2: "SMALLINT",
10
+ 3: "INT",
11
+ 4: "BIGINT",
12
+ 5: "FLOAT",
13
+ 6: "DOUBLE",
14
+ 7: "STRING",
15
+ 8: "TIMESTAMP",
16
+ 9: "BINARY",
17
+ 10: "ARRAY",
18
+ 11: "MAP",
19
+ 12: "STRUCT",
20
+ 13: "UNIONTYPE",
21
+ 15: "DECIMAL",
22
+ 16: "NULL",
23
+ 17: "DATE",
24
+ 18: "VARCHAR",
25
+ 19: "CHAR",
26
+ 20: "INTERVAL_YEAR_MONTH",
27
+ 21: "INTERVAL_DAY_TIME",
28
+ }
29
+ CHARACTER_MAXIMUM_LENGTH = "characterMaximumLength"
30
+ PRECISION = "precision"
31
+ SCALE = "scale"
32
+ ZONE = pytz.timezone('UTC')
@@ -0,0 +1,170 @@
1
+ import struct
2
+ import logging
3
+ from e6xdb.date_time_utils import FORMATS, floor_div, floor_mod
4
+ from datetime import datetime, timedelta
5
+ from e6xdb.constants import ZONE
6
+
7
+ _logger = logging.getLogger(__name__)
8
+
9
+
10
+ class DataInputStream:
11
+ def __init__(self, stream):
12
+ self.stream = stream
13
+
14
+ def read_boolean(self):
15
+ return struct.unpack('?', self.stream.read(1))[0]
16
+
17
+ def read_bytes(self, byte_array):
18
+ for i in range(len(byte_array)):
19
+ byte_array[i] = struct.unpack('B', self.stream.read(1))[0]
20
+ return byte_array
21
+
22
+ def read_int_96(self):
23
+ return struct.unpack('B', self.stream.read(12))[0]
24
+
25
+ def read_byte(self):
26
+ return struct.unpack('b', self.stream.read(1))[0]
27
+
28
+ def read_unsigned_byte(self):
29
+ return struct.unpack('B', self.stream.read(1))[0]
30
+
31
+ def read_char(self):
32
+ return chr(struct.unpack('>H', self.stream.read(2))[0])
33
+
34
+ def read_double(self):
35
+ return struct.unpack('>d', self.stream.read(8))[0]
36
+
37
+ def read_float(self):
38
+ return struct.unpack('>f', self.stream.read(4))[0]
39
+
40
+ def read_short(self):
41
+ return struct.unpack('>h', self.stream.read(2))[0]
42
+
43
+ def read_unsigned_short(self):
44
+ return struct.unpack('>H', self.stream.read(2))[0]
45
+
46
+ def read_long(self):
47
+ return struct.unpack('>q', self.stream.read(8))[0]
48
+
49
+ def read_utf(self):
50
+ utf_length = struct.unpack('>H', self.stream.read(2))[0]
51
+ return self.stream.read(utf_length)
52
+
53
+ def read_int(self):
54
+ return struct.unpack('>i', self.stream.read(4))[0]
55
+
56
+ def read_unsigned_int(self):
57
+ return struct.unpack('>I', self.stream.read(4))[0]
58
+
59
+
60
+ class FieldInfo:
61
+ def __init__(self, name, field_type, date_format, zone):
62
+ self.name = name
63
+ self.field_type = field_type
64
+ self.date_format = date_format
65
+ self.zone = zone
66
+
67
+ def get_zone(self):
68
+ if self.field_type == 'DATE' or self.field_type == 'DATETIME':
69
+ return self.zone
70
+ return None
71
+
72
+ def get_format(self):
73
+ if self.field_type == 'DATE' or self.field_type == 'DATETIME':
74
+ return self.date_format
75
+ return None
76
+
77
+ def get_field_type(self):
78
+ return self.field_type
79
+
80
+ def get_name(self):
81
+ return self.name
82
+
83
+
84
+ def get_query_columns_info(buffer):
85
+ result_meta_bytes = DataInputStream(buffer)
86
+ rowcount = result_meta_bytes.read_long()
87
+ field_count = result_meta_bytes.read_int()
88
+ columns_description = list()
89
+
90
+ for i in range(field_count):
91
+ name = result_meta_bytes.read_utf().decode()
92
+ field_type = result_meta_bytes.read_utf().decode()
93
+ zone = result_meta_bytes.read_utf().decode()
94
+ date_format = result_meta_bytes.read_utf().decode()
95
+ field_info = FieldInfo(name, field_type, date_format, zone)
96
+ columns_description.append(field_info)
97
+ return rowcount, columns_description
98
+
99
+
100
+ def read_values_from_array(query_columns_description: list, dis: DataInputStream) -> list:
101
+ value_array = list()
102
+ for i in query_columns_description:
103
+ dtype = i.get_field_type()
104
+ isPresent = dis.read_byte()
105
+ date_format = i.get_format()
106
+ if isPresent == 0:
107
+ value_array.append(None)
108
+ continue
109
+ try:
110
+ if dtype == "LONG":
111
+ value_array.append(dis.read_long())
112
+ elif dtype == "DATE":
113
+ epoch_seconds = floor_div(dis.read_long(), 1000_000)
114
+ date = datetime.fromtimestamp(epoch_seconds, ZONE)
115
+ value_array.append(date.strftime("%Y-%m-%d"))
116
+ elif dtype == "DATETIME":
117
+ epoch_micros = dis.read_long()
118
+ epoch_seconds = floor_div(epoch_micros, 1000_000)
119
+ micros_of_the_day = floor_mod(epoch_micros, 1000_000)
120
+ date_time = datetime.fromtimestamp(epoch_seconds, ZONE)
121
+ date_time = date_time + timedelta(microseconds=micros_of_the_day)
122
+ value_array.append(date_time.strftime("%Y-%m-%d %H:%M:%S"))
123
+ elif dtype == "STRING" or dtype == "ARRAY" or dtype == "MAP" or dtype == "STRUCT":
124
+ value_array.append(dis.read_utf().decode())
125
+ elif dtype == "INT":
126
+ value_array.append(dis.read_int())
127
+ elif dtype == "DOUBLE":
128
+ value_array.append(dis.read_double())
129
+ elif dtype == "BINARY":
130
+ value_array.append(dis.read_utf())
131
+ elif dtype == "FLOAT":
132
+ value_array.append(dis.read_float())
133
+ elif dtype == "CHAR":
134
+ value_array.append(dis.read_char())
135
+ elif dtype == "BOOLEAN":
136
+ value_array.append(dis.read_boolean())
137
+ elif dtype == "SHORT":
138
+ value_array.append(dis.read_short())
139
+ elif dtype == "BYTE":
140
+ value_array.append(dis.read_byte())
141
+ elif dtype == "INT96":
142
+ julian_day = dis.read_int()
143
+ time = dis.read_long()
144
+ date_time = datetime.fromtimestamp((julian_day - 2440588) * 86400)
145
+ date_time_with_nanos = date_time + timedelta(microseconds=(time / 1000))
146
+ value_array.append(date_time_with_nanos)
147
+ elif dtype == "INTEGER":
148
+ value_array.append(dis.read_int())
149
+ except Exception as e:
150
+ _logger.error(e)
151
+ value_array.append('Failed to parse.')
152
+
153
+ return value_array
154
+
155
+
156
+ def read_rows_from_batch(query_columns_description: list, dis: DataInputStream):
157
+ is_row_present = dis.read_byte()
158
+ if not is_row_present:
159
+ return None
160
+ rows = list()
161
+ while is_row_present == 1:
162
+ if is_row_present:
163
+ row = read_values_from_array(query_columns_description, dis)
164
+ rows.append(row)
165
+ # if rows become 1000, break it
166
+ # if len(rows) == 1000:
167
+ # _logger.info("Read Batch - Breaking the loop after 1000 records")
168
+ # break
169
+ is_row_present = dis.read_byte()
170
+ return rows
@@ -0,0 +1,167 @@
1
+ TIME_ZONES = {
2
+ "+12:00": ["Pacific/Kwajalein", "Pacific/Wallis", "Pacific/Funafuti", "Pacific/Nauru", "Kwajalein", "Pacific/Wake",
3
+ "Pacific/Norfolk", "Pacific/Tarawa", "Asia/Kamchatka", "Etc/GMT-12", "Asia/Anadyr", "Pacific/Majuro", ],
4
+ "+14:00": ["Pacific/Kiritimati", "Etc/GMT-14", ],
5
+ "UTC": ["UTC"],
6
+ "-01:00": ["Etc/GMT+1", "Atlantic/Cape_Verde", "Atlantic/Azores", "America/Scoresbysund", ],
7
+ "-03:00": ["Chile/Continental", "America/Miquelon", "America/Argentina/Catamarca", "America/Argentina/Cordoba",
8
+ "America/Araguaina", "America/Argentina/Salta", "Etc/GMT+3", "America/Montevideo", "Brazil/East",
9
+ "America/Argentina/Mendoza", "America/Argentina/Rio_Gallegos", "America/Catamarca", "America/Godthab",
10
+ "America/Cordoba", "America/Sao_Paulo", "America/Argentina/Jujuy", "America/Cayenne", "America/Recife",
11
+ "America/Buenos_Aires", "America/Paramaribo", "America/Mendoza", "America/Santarem", "America/Asuncion",
12
+ "America/Maceio", "Atlantic/Stanley", "Antarctica/Rothera", "America/Argentina/San_Luis",
13
+ "America/Santiago", "America/Argentina/Ushuaia", "Antarctica/Palmer", "America/Punta_Arenas",
14
+ "America/Fortaleza", "America/Argentina/La_Rioja", "America/Belem", "America/Jujuy", "America/Bahia",
15
+ "America/Argentina/San_Juan", "America/Argentina/ComodRivadavia", "America/Argentina/Tucuman",
16
+ "America/Nuuk", "America/Rosario", "America/Argentina/Buenos_Aires", ],
17
+ "-09:00": ["Etc/GMT+9", "US/Alaska", "America/Juneau", "America/Metlakatla", "Pacific/Gambier", "America/Yakutat",
18
+ "America/Sitka", "SystemV/YST9", "America/Anchorage", "America/Nome", "SystemV/YST9YDT", ],
19
+ "-07:00": ["Canada/Yukon", "Etc/GMT+7", "US/Arizona", "Mexico/BajaSur", "America/Dawson_Creek", "America/Denver",
20
+ "America/Yellowknife", "America/Inuvik", "America/Mazatlan", "SystemV/MST7", "America/Boise",
21
+ "America/Dawson", "MST7MDT", "America/Chihuahua", "America/Ojinaga", "US/Mountain", "America/Creston",
22
+ "America/Edmonton", "America/Hermosillo", "Canada/Mountain", "America/Cambridge_Bay", "Navajo",
23
+ "America/Phoenix", "America/Whitehorse", "SystemV/MST7MDT", "America/Fort_Nelson", "America/Shiprock", ],
24
+ "-05:00": ["America/Panama", "America/Indiana/Petersburg", "America/Eirunepe", "America/Grand_Turk", "Cuba",
25
+ "Etc/GMT+5", "Pacific/Easter", "America/Fort_Wayne", "America/Havana", "America/Porto_Acre",
26
+ "US/Michigan", "America/Louisville", "America/Guayaquil", "America/Indiana/Vevay",
27
+ "America/Indiana/Vincennes", "America/Indianapolis", "America/Iqaluit", "America/Kentucky/Louisville",
28
+ "EST5EDT", "America/Nassau", "America/Jamaica", "America/Atikokan", "America/Kentucky/Monticello",
29
+ "America/Coral_Harbour", "America/Cayman", "Chile/EasterIsland", "America/Indiana/Indianapolis",
30
+ "America/Thunder_Bay", "America/Indiana/Marengo", "America/Bogota", "SystemV/EST5", "US/Eastern",
31
+ "Canada/Eastern", "America/Port-au-Prince", "America/Nipigon", "Brazil/Acre", "US/East-Indiana",
32
+ "America/Cancun", "America/Lima", "America/Rio_Branco", "America/Detroit", "Jamaica",
33
+ "America/Pangnirtung", "America/Montreal", "America/Indiana/Winamac", "America/New_York",
34
+ "America/Toronto", "SystemV/EST5EDT", ],
35
+ "+03:00": ["Asia/Aden", "Africa/Nairobi", "Europe/Istanbul", "Etc/GMT-3", "Indian/Comoro", "Antarctica/Syowa",
36
+ "Africa/Mogadishu", "Africa/Asmera", "Asia/Istanbul", "Europe/Moscow", "Africa/Djibouti",
37
+ "Europe/Simferopol", "Africa/Asmara", "Asia/Baghdad", "Africa/Dar_es_Salaam", "Africa/Addis_Ababa",
38
+ "Asia/Riyadh", "Asia/Kuwait", "Europe/Kirov", "Africa/Kampala", "Europe/Minsk", "Asia/Qatar",
39
+ "Asia/Bahrain", "Indian/Antananarivo", "Indian/Mayotte", "Europe/Volgograd", "Turkey", "W-SU", ],
40
+ "+01:00": ["Europe/Brussels", "Europe/Warsaw", "CET", "Etc/GMT-1", "Europe/Luxembourg", "Africa/Tunis",
41
+ "Europe/Malta", "Europe/Busingen", "Africa/Malabo", "Europe/Skopje", "Europe/Sarajevo", "Africa/Lagos",
42
+ "Europe/Rome", "Africa/Algiers", "Europe/Zurich", "Europe/Gibraltar", "Europe/Vaduz", "Europe/Ljubljana",
43
+ "Europe/Berlin", "Europe/Stockholm", "Europe/Budapest", "Europe/Zagreb", "Europe/Paris",
44
+ "Africa/Ndjamena", "Africa/Ceuta", "Europe/Prague", "Europe/Copenhagen", "Europe/Vienna",
45
+ "Europe/Tirane", "MET", "Europe/Amsterdam", "Africa/Libreville", "Africa/El_Aaiun", "Europe/San_Marino",
46
+ "Africa/Douala", "Africa/Brazzaville", "Africa/Porto-Novo", "Poland", "Europe/Andorra", "Europe/Oslo",
47
+ "Europe/Podgorica", "Africa/Casablanca", "Africa/Luanda", "Atlantic/Jan_Mayen", "Africa/Kinshasa",
48
+ "Europe/Madrid", "Africa/Bangui", "Europe/Belgrade", "Africa/Niamey", "Europe/Bratislava",
49
+ "Arctic/Longyearbyen", "Europe/Vatican", "Europe/Monaco", ],
50
+ "+04:30": ["Asia/Kabul", ],
51
+ "+07:00": ["Asia/Pontianak", "Etc/GMT-7", "Asia/Phnom_Penh", "Asia/Novosibirsk", "Antarctica/Davis", "Asia/Tomsk",
52
+ "Asia/Jakarta", "Asia/Barnaul", "Indian/Christmas", "Asia/Ho_Chi_Minh", "Asia/Hovd", "Asia/Bangkok",
53
+ "Asia/Vientiane", "Asia/Novokuznetsk", "Asia/Krasnoyarsk", "Asia/Saigon", ],
54
+ "+05:45": ["Asia/Kathmandu", "Asia/Katmandu", ],
55
+ "+05:00": ["Asia/Aqtau", "Etc/GMT-5", "Asia/Samarkand", "Asia/Karachi", "Asia/Yekaterinburg", "Asia/Dushanbe",
56
+ "Indian/Maldives", "Asia/Oral", "Asia/Tashkent", "Antarctica/Mawson", "Asia/Qyzylorda", "Asia/Aqtobe",
57
+ "Asia/Ashkhabad", "Asia/Ashgabat", "Asia/Atyrau", "Indian/Kerguelen", ],
58
+ "+06:30": ["Asia/Yangon", "Asia/Rangoon", "Indian/Cocos", ],
59
+ "+10:00": ["Pacific/Yap", "Pacific/Port_Moresby", "Pacific/Chuuk", "Australia/Queensland", "Pacific/Guam",
60
+ "Pacific/Truk", "Asia/Vladivostok", "Pacific/Saipan", "Antarctica/DumontDUrville", "Australia/Brisbane",
61
+ "Etc/GMT-10", "Asia/Ust-Nera", "Australia/Lindeman", ],
62
+ "+09:00": ["Etc/GMT-9", "Pacific/Palau", "Asia/Chita", "Asia/Dili", "Asia/Jayapura", "Asia/Yakutsk",
63
+ "Asia/Pyongyang", "ROK", "Asia/Seoul", "Asia/Khandyga", "Japan", "Asia/Tokyo", ],
64
+ "Z": ["UTC", "Europe/London", "GMT", "Etc/GMT-0", "Europe/Jersey", "Atlantic/St_Helena", "Europe/Guernsey",
65
+ "Europe/Isle_of_Man", "Etc/GMT+0", "Africa/Banjul", "Etc/GMT", "Africa/Freetown", "GB-Eire", "Africa/Bamako",
66
+ "GB", "Africa/Conakry", "Portugal", "Universal", "Africa/Sao_Tome", "Africa/Nouakchott", "Antarctica/Troll",
67
+ "UTC", "Etc/Universal", "Atlantic/Faeroe", "Africa/Abidjan", "Eire", "Africa/Accra", "Atlantic/Faroe",
68
+ "Etc/UCT", "GMT0", "Europe/Dublin", "Zulu", "Africa/Ouagadougou", "Atlantic/Reykjavik", "Atlantic/Madeira",
69
+ "Etc/Zulu", "Iceland", "Europe/Lisbon", "Atlantic/Canary", "Africa/Lome", "Greenwich", "Europe/Belfast",
70
+ "Etc/GMT0", "America/Danmarkshavn", "Africa/Dakar", "Africa/Bissau", "WET", "Etc/Greenwich",
71
+ "Africa/Timbuktu", "UCT", "Africa/Monrovia", "Etc/UTC", ],
72
+ "-11:00": ["Pacific/Pago_Pago", "Pacific/Samoa", "Pacific/Niue", "US/Samoa", "Etc/GMT+11", "Pacific/Midway", ],
73
+ "-06:00": ["America/El_Salvador", "America/Guatemala", "America/Belize", "America/Managua", "America/Chicago",
74
+ "America/Tegucigalpa", "Etc/GMT+6", "America/Regina", "Mexico/General", "America/Rankin_Inlet",
75
+ "US/Central", "Pacific/Galapagos", "America/Rainy_River", "America/Swift_Current", "America/Costa_Rica",
76
+ "America/Indiana/Knox", "America/North_Dakota/Beulah", "America/Monterrey", "SystemV/CST6",
77
+ "America/North_Dakota/Center", "America/Indiana/Tell_City", "America/Mexico_City", "America/Matamoros",
78
+ "CST6CDT", "America/Knox_IN", "America/Menominee", "America/Resolute", "Canada/Central",
79
+ "America/Bahia_Banderas", "US/Indiana-Starke", "SystemV/CST6CDT", "America/Merida",
80
+ "Canada/Saskatchewan", "America/North_Dakota/New_Salem", "America/Winnipeg", ],
81
+ "-03:30": ["America/St_Johns", "Canada/Newfoundland", ],
82
+ "+13:45": ["NZ-CHAT", "Pacific/Chatham", ],
83
+ "+10:30": ["Australia/Yancowinna", "Australia/Adelaide", "Australia/Broken_Hill", "Australia/South", ],
84
+ "+11:00": ["Australia/Hobart", "Australia/Tasmania", "Australia/ACT", "Pacific/Ponape", "Pacific/Bougainville",
85
+ "Australia/Victoria", "Antarctica/Macquarie", "Antarctica/Casey", "Australia/Canberra",
86
+ "Australia/Currie", "Australia/Lord_Howe", "Australia/NSW", "Pacific/Pohnpei", "Pacific/Efate",
87
+ "Asia/Magadan", "Pacific/Kosrae", "Australia/Sydney", "Australia/LHI", "Asia/Sakhalin", "Pacific/Noumea",
88
+ "Etc/GMT-11", "Asia/Srednekolymsk", "Australia/Melbourne", "Pacific/Guadalcanal", ],
89
+ "+13:00": ["Pacific/Fakaofo", "Antarctica/McMurdo", "Pacific/Fiji", "Pacific/Enderbury", "NZ", "Pacific/Apia",
90
+ "Antarctica/South_Pole", "Pacific/Kanton", "Pacific/Auckland", "Pacific/Tongatapu", "Etc/GMT-13", ],
91
+ "-09:30": ["Pacific/Marquesas", ],
92
+ "-08:00": ["Etc/GMT+8", "Canada/Pacific", "PST8PDT", "Pacific/Pitcairn", "Mexico/BajaNorte", "America/Tijuana",
93
+ "SystemV/PST8", "America/Santa_Isabel", "America/Vancouver", "America/Ensenada", "SystemV/PST8PDT",
94
+ "America/Los_Angeles", "US/Pacific", ],
95
+ "-02:00": ["Etc/GMT+2", "America/Noronha", "Brazil/DeNoronha", "Atlantic/South_Georgia", ],
96
+ "-04:00": ["America/Cuiaba", "America/Marigot", "Canada/Atlantic", "Etc/GMT+4", "America/Manaus",
97
+ "America/St_Thomas", "America/Anguilla", "America/Barbados", "America/Curacao", "America/Guyana",
98
+ "America/Martinique", "America/Puerto_Rico", "America/Port_of_Spain", "SystemV/AST4",
99
+ "America/Kralendijk", "America/Antigua", "America/Moncton", "America/St_Vincent", "America/Dominica",
100
+ "Atlantic/Bermuda", "Brazil/West", "America/Aruba", "America/Halifax", "America/La_Paz",
101
+ "America/Blanc-Sablon", "America/Santo_Domingo", "America/Glace_Bay", "America/St_Barthelemy",
102
+ "America/St_Lucia", "America/Montserrat", "America/Lower_Princes", "America/Thule", "America/Tortola",
103
+ "America/Porto_Velho", "America/Campo_Grande", "America/Goose_Bay", "America/Virgin",
104
+ "America/Boa_Vista", "America/Grenada", "America/St_Kitts", "America/Caracas", "America/Guadeloupe",
105
+ "SystemV/AST4ADT", ],
106
+ "+02:00": ["Africa/Cairo", "Africa/Mbabane", "Etc/GMT-2", "Europe/Zaporozhye", "Libya", "Africa/Kigali",
107
+ "Africa/Tripoli", "Israel", "Europe/Kaliningrad", "Africa/Windhoek", "Europe/Bucharest",
108
+ "Europe/Mariehamn", "Africa/Lubumbashi", "Europe/Tiraspol", "Europe/Chisinau", "Europe/Helsinki",
109
+ "Asia/Beirut", "Asia/Tel_Aviv", "Europe/Sofia", "Africa/Gaborone", "Asia/Gaza", "Europe/Riga",
110
+ "Africa/Maputo", "Asia/Damascus", "Europe/Uzhgorod", "Asia/Jerusalem", "Africa/Bujumbura", "Europe/Kiev",
111
+ "Europe/Vilnius", "Africa/Maseru", "Africa/Blantyre", "Africa/Lusaka", "Africa/Harare", "Europe/Tallinn",
112
+ "Africa/Khartoum", "Africa/Johannesburg", "Africa/Juba", "Asia/Nicosia", "Asia/Famagusta", "EET",
113
+ "Asia/Hebron", "Egypt", "Asia/Amman", "Europe/Nicosia", "Europe/Athens", ],
114
+ "+03:30": ["Iran", "Asia/Tehran", ],
115
+ "+04:00": ["Asia/Yerevan", "Etc/GMT-4", "Asia/Dubai", "Indian/Reunion", "Indian/Mauritius", "Europe/Saratov",
116
+ "Europe/Samara", "Indian/Mahe", "Asia/Baku", "Asia/Muscat", "Europe/Astrakhan", "Asia/Tbilisi",
117
+ "Europe/Ulyanovsk", ],
118
+ "+06:00": ["Asia/Kashgar", "Etc/GMT-6", "Asia/Almaty", "Asia/Dacca", "Asia/Omsk", "Asia/Dhaka", "Indian/Chagos",
119
+ "Asia/Qostanay", "Asia/Bishkek", "Antarctica/Vostok", "Asia/Urumqi", "Asia/Thimbu", "Asia/Thimphu", ],
120
+ "+08:45": ["Australia/Eucla", ],
121
+ "+08:00": ["Asia/Kuching", "Asia/Chungking", "Etc/GMT-8", "Australia/Perth", "Asia/Macao", "Asia/Macau",
122
+ "Asia/Choibalsan", "Asia/Shanghai", "Asia/Ulan_Bator", "Asia/Chongqing", "Asia/Ulaanbaatar",
123
+ "Asia/Taipei", "Asia/Manila", "PRC", "Asia/Ujung_Pandang", "Asia/Harbin", "Singapore", "Asia/Brunei",
124
+ "Australia/West", "Asia/Hong_Kong", "Asia/Makassar", "Hongkong", "Asia/Kuala_Lumpur", "Asia/Irkutsk",
125
+ "Asia/Singapore", ],
126
+ "-12:00": ["Etc/GMT+12", ],
127
+ "+05:30": ["Asia/Kolkata", "Asia/Colombo", "Asia/Calcutta", ],
128
+ "+09:30": ["Australia/North", "Australia/Darwin", ],
129
+ "-10:00": ["Pacific/Honolulu", "Pacific/Rarotonga", "Pacific/Tahiti", "Pacific/Johnston", "America/Atka",
130
+ "US/Hawaii", "SystemV/HST10", "America/Adak", "US/Aleutian", "Etc/GMT+10", ],
131
+
132
+ }
133
+
134
+ FORMATS = {
135
+ "yyyy": "%Y",
136
+ "dd": "%d",
137
+ "MM": "%m",
138
+ "HH": "%H",
139
+ "mm": "%M",
140
+ "ss": "%S"
141
+ }
142
+
143
+
144
+ def floor_div(x, y):
145
+ q = x // y
146
+ if x ^ y < 0 and q * y != x:
147
+ return q - 1
148
+ return q
149
+
150
+
151
+ def floor_mod(x, y):
152
+ r = x % y
153
+ if (x ^ y) < 0 and r != 0:
154
+ return r + y
155
+ return r
156
+
157
+
158
+ def get_format(str_format):
159
+ if str_format is None or len(str_format) == 0:
160
+ return "%Y-%m-%d %H:%M:%S"
161
+ return FORMATS[str_format]
162
+
163
+
164
+ def get_zone(zone):
165
+ if zone is None or len(zone) == 0:
166
+ return "UTC"
167
+ return TIME_ZONES[zone][0]