dfdatetime 20260730__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.
@@ -0,0 +1,425 @@
1
+ """Date and time precision helpers."""
2
+
3
+ import decimal
4
+
5
+ from dfdatetime import definitions
6
+
7
+
8
+ class DateTimePrecisionHelper:
9
+ """Date time precision helper interface.
10
+
11
+ This is the super class of different date and time precision helpers.
12
+
13
+ Time precision helpers provide functionality for converting date and time values
14
+ between different precisions.
15
+ """
16
+
17
+ # pylint: disable=missing-raises-doc,redundant-returns-doc
18
+
19
+ @classmethod
20
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
21
+ """Copies the number of nanoseconds to a fraction of second value.
22
+
23
+ Args:
24
+ nanoseconds (int): number of nanoseconds.
25
+
26
+ Returns:
27
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
28
+ 1.0.
29
+ """
30
+ raise NotImplementedError()
31
+
32
+ @classmethod
33
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
34
+ """Copies the time elements and fraction of second to a string.
35
+
36
+ Args:
37
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
38
+ time elements, contains year, month, day of month, hours, minutes and
39
+ seconds.
40
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
41
+ value between 0.0 and 1.0.
42
+
43
+ Returns:
44
+ str: date and time value formatted as: YYYY-MM-DD hh:mm:ss with fraction
45
+ of second part that corresponds to the precision.
46
+ """
47
+ raise NotImplementedError()
48
+
49
+
50
+ class SecondsPrecisionHelper(DateTimePrecisionHelper):
51
+ """Seconds precision helper."""
52
+
53
+ @classmethod
54
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
55
+ """Copies the number of nanoseconds to a fraction of second value.
56
+
57
+ Args:
58
+ nanoseconds (int): number of nanoseconds.
59
+
60
+ Returns:
61
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
62
+ 1.0. For the seconds precision helper this will always be 0.0.
63
+
64
+ Raises:
65
+ ValueError: if the number of nanoseconds is out of bounds.
66
+ """
67
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
68
+ raise ValueError(
69
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
70
+ )
71
+
72
+ return decimal.Decimal(0.0)
73
+
74
+ @classmethod
75
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
76
+ """Copies the time elements and fraction of second to a string.
77
+
78
+ Args:
79
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
80
+ time elements, contains year, month, day of month, hours, minutes and
81
+ seconds.
82
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
83
+ value between 0.0 and 1.0.
84
+
85
+ Returns:
86
+ str: date and time value formatted as:
87
+ YYYY-MM-DD hh:mm:ss
88
+
89
+ Raises:
90
+ ValueError: if the fraction of second is out of bounds.
91
+ """
92
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
93
+ raise ValueError(
94
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
95
+ )
96
+
97
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
98
+
99
+ return (
100
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
101
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}"
102
+ )
103
+
104
+
105
+ class CentisecondsPrecisionHelper(DateTimePrecisionHelper):
106
+ """Centiseconds (10 ms) precision helper."""
107
+
108
+ @classmethod
109
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
110
+ """Copies the number of nanoseconds to a fraction of second value.
111
+
112
+ Args:
113
+ nanoseconds (int): number of nanoseconds.
114
+
115
+ Returns:
116
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
117
+ 1.0.
118
+
119
+ Raises:
120
+ ValueError: if the number of nanoseconds is out of bounds.
121
+ """
122
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
123
+ raise ValueError(
124
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
125
+ )
126
+
127
+ centiseconds, _ = divmod(nanoseconds, definitions.NANOSECONDS_PER_CENTISECOND)
128
+ return decimal.Decimal(centiseconds) / definitions.CENTISECONDS_PER_SECOND
129
+
130
+ @classmethod
131
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
132
+ """Copies the time elements and fraction of second to a string.
133
+
134
+ Args:
135
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
136
+ time elements, contains year, month, day of month, hours, minutes and
137
+ seconds.
138
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
139
+ value between 0.0 and 1.0.
140
+
141
+ Returns:
142
+ str: date and time value formatted as:
143
+ YYYY-MM-DD hh:mm:ss.##
144
+
145
+ Raises:
146
+ ValueError: if the fraction of second is out of bounds.
147
+ """
148
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
149
+ raise ValueError(
150
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
151
+ )
152
+
153
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
154
+ centiseconds = int(fraction_of_second * definitions.CENTISECONDS_PER_SECOND)
155
+
156
+ return (
157
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
158
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}.{centiseconds:02d}"
159
+ )
160
+
161
+
162
+ class MillisecondsPrecisionHelper(DateTimePrecisionHelper):
163
+ """Milliseconds precision helper."""
164
+
165
+ @classmethod
166
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
167
+ """Copies the number of nanoseconds to a fraction of second value.
168
+
169
+ Args:
170
+ nanoseconds (int): number of nanoseconds.
171
+
172
+ Returns:
173
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
174
+ 1.0.
175
+
176
+ Raises:
177
+ ValueError: if the number of nanoseconds is out of bounds.
178
+ """
179
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
180
+ raise ValueError(
181
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
182
+ )
183
+
184
+ milliseconds, _ = divmod(nanoseconds, definitions.NANOSECONDS_PER_MILLISECOND)
185
+ return decimal.Decimal(milliseconds) / definitions.MILLISECONDS_PER_SECOND
186
+
187
+ @classmethod
188
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
189
+ """Copies the time elements and fraction of second to a string.
190
+
191
+ Args:
192
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
193
+ time elements, contains year, month, day of month, hours, minutes and
194
+ seconds.
195
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
196
+ value between 0.0 and 1.0.
197
+
198
+ Returns:
199
+ str: date and time value formatted as:
200
+ YYYY-MM-DD hh:mm:ss.###
201
+
202
+ Raises:
203
+ ValueError: if the fraction of second is out of bounds.
204
+ """
205
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
206
+ raise ValueError(
207
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
208
+ )
209
+
210
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
211
+ milliseconds = int(fraction_of_second * definitions.MILLISECONDS_PER_SECOND)
212
+
213
+ return (
214
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
215
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}"
216
+ )
217
+
218
+
219
+ class DecimillisecondsPrecisionHelper(DateTimePrecisionHelper):
220
+ """Decimilliseconds (100 microseconds) precision helper."""
221
+
222
+ @classmethod
223
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
224
+ """Copies the number of nanoseconds to a fraction of second value.
225
+
226
+ Args:
227
+ nanoseconds (int): number of nanoseconds.
228
+
229
+ Returns:
230
+ decimal.Decimal: fraction of second, which must be a value between 0.0
231
+ and 1.0.
232
+
233
+ Raises:
234
+ ValueError: if the number of nanoseconds is out of bounds.
235
+ """
236
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
237
+ raise ValueError(
238
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
239
+ )
240
+
241
+ decimiliseconds, _ = divmod(
242
+ nanoseconds, definitions.NANOSECONDS_PER_DECIMILISECOND
243
+ )
244
+ return (
245
+ decimal.Decimal(decimiliseconds) / definitions.DECIMICROSECONDS_PER_SECOND
246
+ )
247
+
248
+ @classmethod
249
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
250
+ """Copies the time elements and fraction of second to a string.
251
+
252
+ Args:
253
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
254
+ time elements, contains year, month, day of month, hours, minutes and
255
+ seconds.
256
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
257
+ value between 0.0 and 1.0.
258
+
259
+ Returns:
260
+ str: date and time value formatted as:
261
+ YYYY-MM-DD hh:mm:ss.####
262
+
263
+ Raises:
264
+ ValueError: if the fraction of second is out of bounds.
265
+ """
266
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
267
+ raise ValueError(
268
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
269
+ )
270
+
271
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
272
+ decimicroseconds = int(
273
+ fraction_of_second * definitions.DECIMICROSECONDS_PER_SECOND
274
+ )
275
+
276
+ return (
277
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
278
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}.{decimicroseconds:04d}"
279
+ )
280
+
281
+
282
+ class MicrosecondsPrecisionHelper(DateTimePrecisionHelper):
283
+ """Microseconds precision helper."""
284
+
285
+ @classmethod
286
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
287
+ """Copies the number of nanoseconds to a fraction of second value.
288
+
289
+ Args:
290
+ nanoseconds (int): number of nanoseconds.
291
+
292
+ Returns:
293
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
294
+ 1.0.
295
+
296
+ Raises:
297
+ ValueError: if the number of nanoseconds is out of bounds.
298
+ """
299
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
300
+ raise ValueError(
301
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
302
+ )
303
+
304
+ microseconds, _ = divmod(nanoseconds, definitions.NANOSECONDS_PER_MICROSECOND)
305
+ return decimal.Decimal(microseconds) / definitions.MICROSECONDS_PER_SECOND
306
+
307
+ @classmethod
308
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
309
+ """Copies the time elements and fraction of second to a string.
310
+
311
+ Args:
312
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
313
+ time elements, contains year, month, day of month, hours, minutes and
314
+ seconds.
315
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
316
+ value between 0.0 and 1.0.
317
+
318
+ Returns:
319
+ str: date and time value formatted as:
320
+ YYYY-MM-DD hh:mm:ss.######
321
+
322
+ Raises:
323
+ ValueError: if the fraction of second is out of bounds.
324
+ """
325
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
326
+ raise ValueError(
327
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
328
+ )
329
+
330
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
331
+ microseconds = int(fraction_of_second * definitions.MICROSECONDS_PER_SECOND)
332
+
333
+ return (
334
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
335
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}.{microseconds:06d}"
336
+ )
337
+
338
+
339
+ class NanosecondsPrecisionHelper(DateTimePrecisionHelper):
340
+ """Nanoseconds precision helper."""
341
+
342
+ @classmethod
343
+ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
344
+ """Copies the number of nanoseconds to a fraction of second value.
345
+
346
+ Args:
347
+ nanoseconds (int): number of nanoseconds.
348
+
349
+ Returns:
350
+ decimal.Decimal: fraction of second, which must be a value between 0.0 and
351
+ 1.0.
352
+
353
+ Raises:
354
+ ValueError: if the number of nanoseconds is out of bounds.
355
+ """
356
+ if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
357
+ raise ValueError(
358
+ f"Number of nanoseconds value: {nanoseconds:d} out of bounds."
359
+ )
360
+
361
+ return decimal.Decimal(nanoseconds) / definitions.NANOSECONDS_PER_SECOND
362
+
363
+ @classmethod
364
+ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
365
+ """Copies the time elements and fraction of second to a string.
366
+
367
+ Args:
368
+ time_elements_tuple (tuple[int, int, int, int, int, int]):
369
+ time elements, contains year, month, day of month, hours, minutes and
370
+ seconds.
371
+ fraction_of_second (decimal.Decimal): fraction of second, which must be a
372
+ value between 0.0 and 1.0.
373
+
374
+ Returns:
375
+ str: date and time value formatted as:
376
+ YYYY-MM-DD hh:mm:ss.######
377
+
378
+ Raises:
379
+ ValueError: if the fraction of second is out of bounds.
380
+ """
381
+ if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
382
+ raise ValueError(
383
+ f"Fraction of second value: {fraction_of_second:f} out of bounds."
384
+ )
385
+
386
+ year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
387
+ nanoseconds = int(fraction_of_second * definitions.NANOSECONDS_PER_SECOND)
388
+
389
+ return (
390
+ f"{year:04d}-{month:02d}-{day_of_month:02d} "
391
+ f"{hours:02d}:{minutes:02d}:{seconds:02d}.{nanoseconds:09d}"
392
+ )
393
+
394
+
395
+ class PrecisionHelperFactory:
396
+ """Date time precision helper factory."""
397
+
398
+ _PRECISION_CLASSES = {
399
+ definitions.PRECISION_10_MILLISECONDS: CentisecondsPrecisionHelper,
400
+ definitions.PRECISION_100_MICROSECONDS: DecimillisecondsPrecisionHelper,
401
+ definitions.PRECISION_1_MICROSECOND: MicrosecondsPrecisionHelper,
402
+ definitions.PRECISION_1_MILLISECOND: MillisecondsPrecisionHelper,
403
+ definitions.PRECISION_1_NANOSECOND: NanosecondsPrecisionHelper,
404
+ definitions.PRECISION_1_SECOND: SecondsPrecisionHelper,
405
+ }
406
+
407
+ @classmethod
408
+ def CreatePrecisionHelper(cls, precision):
409
+ """Creates a precision helper.
410
+
411
+ Args:
412
+ precision (str): precision of the date and time value, which should
413
+ be one of the PRECISION_VALUES in definitions.
414
+
415
+ Returns:
416
+ class: date time precision helper class.
417
+
418
+ Raises:
419
+ ValueError: if the precision value is unsupported.
420
+ """
421
+ precision_helper_class = cls._PRECISION_CLASSES.get(precision)
422
+ if not precision_helper_class:
423
+ raise ValueError(f"Unsupported precision: {precision!s}")
424
+
425
+ return precision_helper_class