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,154 @@
1
+ """The date and time values serializer."""
2
+
3
+ from dfdatetime import factory
4
+ from dfdatetime import interface
5
+
6
+
7
+ class Serializer:
8
+ """Date and time values serializer."""
9
+
10
+ @classmethod
11
+ def ConvertDictToDateTimeValues(cls, json_dict):
12
+ """Converts a JSON dict into a date time values object.
13
+
14
+ This method is deprecated use ConvertJSONToDateTimeValues instead.
15
+
16
+ The dictionary of the JSON serialized objects consists of:
17
+ {
18
+ '__type__': 'DateTimeValues'
19
+ '__class_name__': 'RFC2579DateTime'
20
+ ...
21
+ }
22
+
23
+ Here '__type__' indicates the object base type. In this case this should
24
+ be 'DateTimeValues'. The rest of the elements of the dictionary make up the
25
+ date time values object properties.
26
+
27
+ Args:
28
+ json_dict (dict[str, object]): JSON serialized objects.
29
+
30
+ Returns:
31
+ dfdatetime.DateTimeValues: date and time values.
32
+ """
33
+ return cls.ConvertJSONToDateTimeValues(json_dict)
34
+
35
+ @classmethod
36
+ def ConvertDateTimeValuesToDict(cls, date_time_values):
37
+ """Converts a date and time values object into a JSON dictionary.
38
+
39
+ This method is deprecated use ConvertDateTimeValuesToJSON instead.
40
+
41
+ The resulting dictionary of the JSON serialized objects consists of:
42
+ {
43
+ '__type__': 'DateTimeValues'
44
+ '__class_name__': 'RFC2579DateTime'
45
+ ...
46
+ }
47
+
48
+ Here '__type__' indicates the object base type. In this case
49
+ 'DateTimeValues'. The rest of the elements of the dictionary make up the
50
+ date and time value object properties.
51
+
52
+ Args:
53
+ date_time_values (dfdatetime.DateTimeValues): date and time values.
54
+
55
+ Returns:
56
+ dict[str, object]: JSON serialized objects.
57
+
58
+ Raises:
59
+ TypeError: if object is not an instance of DateTimeValues.
60
+ """
61
+ if not isinstance(date_time_values, interface.DateTimeValues):
62
+ raise TypeError
63
+
64
+ return cls.ConvertDateTimeValuesToJSON(date_time_values)
65
+
66
+ @classmethod
67
+ def ConvertDateTimeValuesToJSON(cls, date_time_values):
68
+ """Converts a date and time values object into a JSON dictionary.
69
+
70
+ The resulting dictionary of the JSON serialized objects consists of:
71
+ {
72
+ '__type__': 'DateTimeValues'
73
+ '__class_name__': 'RFC2579DateTime'
74
+ ...
75
+ }
76
+
77
+ Here '__type__' indicates the object base type. In this case
78
+ 'DateTimeValues'. The rest of the elements of the dictionary make up the
79
+ date and time value object properties.
80
+
81
+ Args:
82
+ date_time_values (dfdatetime.DateTimeValues): date and time values.
83
+
84
+ Returns:
85
+ dict[str, object]: JSON serialized objects.
86
+ """
87
+ return date_time_values.CopyToSerializableDict()
88
+
89
+ @classmethod
90
+ def ConvertJSONToDateTimeValues(cls, json_dict):
91
+ """Converts a JSON dict into a date time values object.
92
+
93
+ The dictionary of the JSON serialized objects consists of:
94
+ {
95
+ '__type__': 'DateTimeValues'
96
+ '__class_name__': 'RFC2579DateTime'
97
+ ...
98
+ }
99
+
100
+ Here '__type__' indicates the object base type. In this case this should
101
+ be 'DateTimeValues'. The rest of the elements of the dictionary make up the
102
+ date time values object properties.
103
+
104
+ Args:
105
+ json_dict (dict[str, object]): JSON serialized objects.
106
+
107
+ Returns:
108
+ dfdatetime.DateTimeValues: date and time values.
109
+
110
+ Raises:
111
+ KeyError: If date and time values type is not supported by factory.
112
+ """
113
+ class_name = json_dict.get("__class_name__")
114
+ if class_name:
115
+ del json_dict["__class_name__"]
116
+
117
+ # Remove the class type from the JSON dict since we cannot pass it.
118
+ del json_dict["__type__"]
119
+
120
+ if class_name not in (
121
+ "TimeElements",
122
+ "TimeElementsInMilliseconds",
123
+ "TimeElementsInMicroseconds",
124
+ "TimeElementsInNanoseconds",
125
+ ):
126
+ is_delta = json_dict.get("is_delta")
127
+ if is_delta is not None:
128
+ del json_dict["is_delta"]
129
+
130
+ is_local_time = json_dict.get("is_local_time")
131
+ if is_local_time is not None:
132
+ del json_dict["is_local_time"]
133
+
134
+ time_zone_hint = json_dict.get("time_zone_hint")
135
+ if time_zone_hint is not None:
136
+ del json_dict["time_zone_hint"]
137
+
138
+ if class_name in ("InvalidTime", "Never", "NotSet"):
139
+ string = json_dict.get("string")
140
+ if string is not None:
141
+ del json_dict["string"]
142
+
143
+ if class_name in ("GolangTime", "RFC2579DateTime"):
144
+ time_zone_offset = json_dict.get("time_zone_offset")
145
+ if time_zone_offset is not None:
146
+ del json_dict["time_zone_offset"]
147
+
148
+ date_time = factory.Factory.NewDateTimeValues(class_name, **json_dict)
149
+ if is_local_time:
150
+ date_time.is_local_time = is_local_time
151
+ if time_zone_hint:
152
+ date_time.time_zone_hint = time_zone_hint
153
+
154
+ return date_time
@@ -0,0 +1,253 @@
1
+ """SYSTEMTIME structure implementation."""
2
+
3
+ import decimal
4
+
5
+ from dfdatetime import definitions
6
+ from dfdatetime import factory
7
+ from dfdatetime import interface
8
+
9
+
10
+ class Systemtime(interface.DateTimeValues):
11
+ """SYSTEMTIME structure.
12
+
13
+ The SYSTEMTIME structure is 16 bytes of size and contains:
14
+
15
+ struct {
16
+ WORD year,
17
+ WORD month,
18
+ WORD day_of_week,
19
+ WORD day_of_month,
20
+ WORD hour,
21
+ WORD minute,
22
+ WORD second,
23
+ WORD millisecond
24
+ }
25
+ """
26
+
27
+ def __init__(self, precision=None, system_time_tuple=None, time_zone_offset=None):
28
+ """Initializes a SYSTEMTIME structure.
29
+
30
+ Args:
31
+ precision (Optional[str]): precision of the date and time value, which
32
+ should be one of the PRECISION_VALUES in definitions.
33
+ system_time_tuple
34
+ (Optional[tuple[int, int, int, int, int, int, int, int]]):
35
+ system time, contains year, month, day of week, day of month,
36
+ hours, minutes, seconds and milliseconds.
37
+ time_zone_offset (Optional[int]): time zone offset in number of minutes
38
+ from UTC or None if not set.
39
+
40
+ Raises:
41
+ ValueError: if the system time is invalid.
42
+ """
43
+ super().__init__(
44
+ precision=precision or definitions.PRECISION_1_MILLISECOND,
45
+ time_zone_offset=time_zone_offset,
46
+ )
47
+ self._day_of_month = None
48
+ self._day_of_week = None
49
+ self._hours = None
50
+ self._milliseconds = None
51
+ self._minutes = None
52
+ self._month = None
53
+ self._number_of_seconds = None
54
+ self._seconds = None
55
+ self._year = None
56
+
57
+ if system_time_tuple:
58
+ if len(system_time_tuple) < 8:
59
+ raise ValueError("Invalid system time tuple 8 elements required.")
60
+
61
+ if system_time_tuple[0] < 1601 or system_time_tuple[0] > 30827:
62
+ raise ValueError("Year value out of bounds.")
63
+
64
+ if system_time_tuple[1] not in range(1, 13):
65
+ raise ValueError("Month value out of bounds.")
66
+
67
+ if system_time_tuple[2] not in range(0, 7):
68
+ raise ValueError("Day of week value out of bounds.")
69
+
70
+ days_per_month = self._GetDaysPerMonth(
71
+ system_time_tuple[0], system_time_tuple[1]
72
+ )
73
+ if system_time_tuple[3] < 1 or system_time_tuple[3] > days_per_month:
74
+ raise ValueError("Day of month value out of bounds.")
75
+
76
+ if system_time_tuple[4] not in range(0, 24):
77
+ raise ValueError("Hours value out of bounds.")
78
+
79
+ if system_time_tuple[5] not in range(0, 60):
80
+ raise ValueError("Minutes value out of bounds.")
81
+
82
+ # TODO: support a leap second?
83
+ if system_time_tuple[6] not in range(0, 60):
84
+ raise ValueError("Seconds value out of bounds.")
85
+
86
+ if system_time_tuple[7] < 0 or system_time_tuple[7] > 999:
87
+ raise ValueError("Milliseconds value out of bounds.")
88
+
89
+ self._day_of_month = system_time_tuple[3]
90
+ self._day_of_week = system_time_tuple[2]
91
+ self._hours = system_time_tuple[4]
92
+ self._milliseconds = system_time_tuple[7]
93
+ self._minutes = system_time_tuple[5]
94
+ self._month = system_time_tuple[1]
95
+ self._seconds = system_time_tuple[6]
96
+ self._year = system_time_tuple[0]
97
+
98
+ self._number_of_seconds = self._GetNumberOfSecondsFromElements(
99
+ self._year,
100
+ self._month,
101
+ self._day_of_month,
102
+ self._hours,
103
+ self._minutes,
104
+ self._seconds,
105
+ )
106
+
107
+ @property
108
+ def day_of_month(self):
109
+ """day_of_month (int): day of month, 1 through 31."""
110
+ return self._day_of_month
111
+
112
+ @property
113
+ def day_of_week(self):
114
+ """day_of_week (int): day of week, 0 through 6."""
115
+ return self._day_of_week
116
+
117
+ @property
118
+ def hours(self):
119
+ """Hours (int): hours, 0 through 23."""
120
+ return self._hours
121
+
122
+ @property
123
+ def milliseconds(self):
124
+ """Milliseconds (int): milliseconds, 0 through 999."""
125
+ return self._milliseconds
126
+
127
+ @property
128
+ def minutes(self):
129
+ """Minutes (int): minutes, 0 through 59."""
130
+ return self._minutes
131
+
132
+ @property
133
+ def month(self):
134
+ """Month (int): month of year, 1 through 12."""
135
+ return self._month
136
+
137
+ @property
138
+ def seconds(self):
139
+ """Seconds (int): seconds, 0 through 59."""
140
+ return self._seconds
141
+
142
+ @property
143
+ def year(self):
144
+ """Year (int): year, 1601 through 30827."""
145
+ return self._year
146
+
147
+ def _GetNormalizedTimestamp(self):
148
+ """Retrieves the normalized timestamp.
149
+
150
+ Returns:
151
+ decimal.Decimal: normalized timestamp, which contains the number of
152
+ seconds since January 1, 1970 00:00:00 and a fraction of second used
153
+ for increased precision, or None if the normalized timestamp cannot be
154
+ determined.
155
+ """
156
+ if self._normalized_timestamp is None:
157
+ if self._number_of_seconds is not None:
158
+ self._normalized_timestamp = (
159
+ decimal.Decimal(self._milliseconds)
160
+ / definitions.MILLISECONDS_PER_SECOND
161
+ )
162
+ self._normalized_timestamp += decimal.Decimal(self._number_of_seconds)
163
+
164
+ if self._time_zone_offset:
165
+ self._normalized_timestamp -= self._time_zone_offset * 60
166
+
167
+ return self._normalized_timestamp
168
+
169
+ def CopyFromDateTimeString(self, time_string):
170
+ """Copies a SYSTEMTIME structure from a date and time string.
171
+
172
+ Args:
173
+ time_string (str): date and time value formatted as:
174
+ YYYY-MM-DD hh:mm:ss.######[+-]##:##
175
+
176
+ Where # are numeric digits ranging from 0 to 9 and the seconds
177
+ fraction can be either 3, 6 or 9 digits. The time of day, seconds
178
+ fraction and time zone offset are optional. The default time zone
179
+ is UTC.
180
+
181
+ Raises:
182
+ ValueError: if the date string is invalid or not supported.
183
+ """
184
+ date_time_values = self._CopyDateTimeFromString(time_string)
185
+
186
+ year = date_time_values.get("year", 0)
187
+ month = date_time_values.get("month", 0)
188
+ day_of_month = date_time_values.get("day_of_month", 0)
189
+ hours = date_time_values.get("hours", 0)
190
+ minutes = date_time_values.get("minutes", 0)
191
+ seconds = date_time_values.get("seconds", 0)
192
+ nanoseconds = date_time_values.get("nanoseconds", 0)
193
+ time_zone_offset = date_time_values.get("time_zone_offset")
194
+
195
+ milliseconds, _ = divmod(nanoseconds, definitions.NANOSECONDS_PER_MILLISECOND)
196
+
197
+ if year < 1601 or year > 30827:
198
+ raise ValueError(f"Unsupported year value: {year:d}.")
199
+
200
+ self._normalized_timestamp = None
201
+ self._number_of_seconds = self._GetNumberOfSecondsFromElements(
202
+ year, month, day_of_month, hours, minutes, seconds
203
+ )
204
+ self._time_zone_offset = time_zone_offset
205
+
206
+ self._year = year
207
+ self._month = month
208
+ self._day_of_month = day_of_month
209
+ # TODO: calculate day of week on demand.
210
+ self._day_of_week = None
211
+ self._hours = hours
212
+ self._minutes = minutes
213
+ self._seconds = seconds
214
+ self._milliseconds = milliseconds
215
+
216
+ def CopyToDateTimeString(self):
217
+ """Copies the SYSTEMTIME structure to a date and time string.
218
+
219
+ Returns:
220
+ str: date and time value formatted as: "YYYY-MM-DD hh:mm:ss.###" or
221
+ None if the number of seconds is missing.
222
+ """
223
+ if self._number_of_seconds is None:
224
+ return None
225
+
226
+ return (
227
+ f"{self._year:04d}-{self._month:02d}-{self._day_of_month:02d} "
228
+ f"{self._hours:02d}:{self._minutes:02d}:{self._seconds:02d}"
229
+ f".{self._milliseconds:03d}"
230
+ )
231
+
232
+ def CopyToSerializableDict(self):
233
+ """Copies the date time value to a serializable dictionary.
234
+
235
+ Returns:
236
+ dict[str, object]: serializable dictionary.
237
+ """
238
+ serializable_dict = self._CreateSerializableDict()
239
+
240
+ serializable_dict["system_time_tuple"] = (
241
+ self._year,
242
+ self._month,
243
+ self._day_of_week,
244
+ self._day_of_month,
245
+ self._hours,
246
+ self._minutes,
247
+ self._seconds,
248
+ self._milliseconds,
249
+ )
250
+ return serializable_dict
251
+
252
+
253
+ factory.Factory.RegisterDateTimeValues(Systemtime)