@@ -110,6 +110,13 @@ def sfdatetime_to_snowflake(value):
110
110
111
111
112
112
class SnowflakeDateTime (UnicodeMixin ):
113
+ """
114
+ Snowflake DateTime class.
115
+
116
+ The differene to the native datetime class is Snowflake supports up to
117
+ nanoseconds precision.
118
+ """
119
+
113
120
def __init__ (self , ts , nanosecond ):
114
121
self ._datetime = ts
115
122
self ._nanosecond = nanosecond
@@ -133,57 +140,85 @@ def __bytes__(self):
133
140
134
141
135
142
class SnowflakeDateTimeFormat (object ):
136
- def __init__ (self , sql_format ):
143
+ """
144
+ Snowflake DateTime Formatter
145
+ """
146
+
147
+ def __init__ (self , sql_format , datetime_class = datetime , scale = None ):
137
148
self ._sql_format = sql_format
138
149
self ._fragments = []
150
+ self ._scale = scale
139
151
self .logger = getLogger (__name__ )
140
152
141
153
self ._compile ()
142
- self ._fraction_pos = - 1
143
154
if len (self ._fragments ) != 1 :
144
155
raise errors .InternalError (
145
156
u'Only one fragment is allowed {0}' .format (
146
157
u',' .join (self ._fragments )))
147
158
148
159
self ._simple_datetime_pattern = self ._to_simple_datetime_pattern ()
149
160
150
- def python_format (self ):
151
- return self ._python_format
161
+ if self ._scale is None and self ._fractions_len >= 0 :
162
+ self ._scale = self ._fractions_len
163
+ else :
164
+ self ._scale = 6
152
165
153
- def format (self , value , scale = 6 ):
154
- if isinstance (value , time .struct_time ):
155
- return TO_UNICODE (time .strftime (
156
- self ._simple_datetime_pattern , value ))
166
+ self ._nano_str = None
157
167
if self ._fractions_pos >= 0 :
158
- if self ._fractions_len >= 0 :
159
- scale = self ._fractions_len
160
- if isinstance (value , datetime ):
161
- nanos = value .microsecond
162
- nano_str = (u"{0:06d}" .format (nanos ))[:scale ]
168
+ if issubclass (datetime_class , datetime ):
169
+ self ._nano_str = u"{0:06d}" # milliseconds precision
163
170
else :
164
- nanos = value .nanosecond
165
- nano_str = (u"{0:09d}" .format (nanos ))[:scale ]
166
- old_format = self ._fragments [0 ][u'python_format' ]
171
+ self ._nano_str = u"{0:09d}" # nanoseconds precision
167
172
if self ._fractions_with_dot :
168
- nano_str = u'.{0}' .format (nano_str )
169
- new_format = old_format [:self ._fractions_pos ] + nano_str + \
170
- old_format [self ._fractions_pos :]
171
- else :
172
- new_format = self ._simple_datetime_pattern
173
+ self ._nano_str = u'.{0}' .format (self ._nano_str )
174
+ self ._scale += 1
173
175
174
- if isinstance (value , SnowflakeDateTime ):
175
- if isinstance (value .datetime , time .struct_time ):
176
- return TO_UNICODE (time .strftime (new_format , value .datetime ))
176
+ self .format = getattr (self , u'_format_{type_name}' .format (
177
+ type_name = datetime_class .__name__ ))
178
+
179
+ def python_format (self ):
180
+ return self ._python_format
181
+
182
+ def _pre_format (self , value ):
183
+ updated_format = self ._simple_datetime_pattern
184
+
185
+ if self ._nano_str :
186
+ if hasattr (value , 'microsecond' ):
187
+ nanos = value .microsecond
188
+ elif hasattr (value , 'nanosecond' ):
189
+ nanos = value .nanosecond
177
190
else :
178
- if value .datetime .year < 1900 :
179
- # NOTE: still not supported
180
- return value .datetime .isoformat ()
181
- return value .datetime .strftime (new_format )
182
- else :
183
- if value .year < 1900 :
184
- # NOTE: still not supported
185
- return value .isoformat ()
186
- return value .strftime (new_format )
191
+ nanos = 0 # struct_time. no fraction of second
192
+ nano_value = self ._nano_str .format (nanos )[:self ._scale ]
193
+ updated_format = \
194
+ updated_format [:self ._fractions_pos ] + nano_value + \
195
+ updated_format [self ._fractions_pos :]
196
+ return updated_format
197
+
198
+ def _format_SnowflakeDateTime (self , value ):
199
+ """
200
+ Formats SnowflakeDateTime object
201
+ """
202
+ updated_format = self ._pre_format (value )
203
+ if isinstance (value .datetime , time .struct_time ):
204
+ return TO_UNICODE (time .strftime (
205
+ updated_format , value .datetime ))
206
+ if value .datetime .year < 1900 :
207
+ # NOTE: still not supported
208
+ return value .datetime .isoformat ()
209
+ return value .datetime .strftime (updated_format )
210
+
211
+ def _format_datetime (self , value ):
212
+ """
213
+ Formats datetime object
214
+ """
215
+ updated_format = self ._pre_format (value )
216
+ if isinstance (value , time .struct_time ):
217
+ return TO_UNICODE (time .strftime (updated_format , value ))
218
+ if value .year < 1900 :
219
+ # NOTE: still not supported
220
+ return value .isoformat ()
221
+ return value .strftime (updated_format )
187
222
188
223
def _to_simple_datetime_pattern (self ):
189
224
if len (self ._fragments ) == 1 :
0 commit comments