rm-date-parser 0.1.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.
@@ -0,0 +1,13 @@
1
+ """Public package interface for dateparserpython."""
2
+
3
+ from .parser import Parser
4
+ from .models import DateElement, LocalDateModel
5
+
6
+ __version__ = "0.1.0"
7
+
8
+ __all__ = [
9
+ "Parser",
10
+ "LocalDateModel",
11
+ "DateElement",
12
+ "__version__",
13
+ ]
@@ -0,0 +1,449 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import List
4
+
5
+ try:
6
+ from .display import DisplayObject, TreeChar
7
+ from .prediction import PredictionModelNode
8
+ except ImportError: # pragma: no cover - fallback for direct module execution
9
+ from dateparserpython.display import DisplayObject, TreeChar
10
+ from dateparserpython.prediction import PredictionModelNode
11
+
12
+ monthPredictionTree = PredictionModelNode()
13
+ weekPredictionTree = PredictionModelNode()
14
+ patternPredictionTree = PredictionModelNode()
15
+ timePredictionTree = PredictionModelNode()
16
+
17
+ WEEKDAY_FULL: List[str] = [
18
+ "sunday",
19
+ "monday",
20
+ "tuesday",
21
+ "wednesday",
22
+ "thursday",
23
+ "friday",
24
+ "saturday",
25
+ ]
26
+
27
+ WEEKDAY_SHORT: List[str] = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]
28
+
29
+ MONTH_FULL: List[str] = [
30
+ "january",
31
+ "february",
32
+ "march",
33
+ "april",
34
+ "may",
35
+ "june",
36
+ "july",
37
+ "august",
38
+ "september",
39
+ "october",
40
+ "november",
41
+ "december",
42
+ ]
43
+
44
+ MONTH_SHORT: List[str] = [
45
+ "jan",
46
+ "feb",
47
+ "mar",
48
+ "apr",
49
+ "may",
50
+ "jun",
51
+ "jul",
52
+ "aug",
53
+ "sep",
54
+ "oct",
55
+ "nov",
56
+ "dec",
57
+ ]
58
+
59
+ PATTERN: List[str] = [
60
+ "DDDD*DD*DD",
61
+ "DDDD*D*DD",
62
+ "DDDD*DD*D",
63
+ "DDDD*D*D",
64
+ "DD*DD*DD",
65
+ "DD*D*DD",
66
+ "DD*DD*D",
67
+ "DD*D*D",
68
+ "DD*DD*DDDD",
69
+ "D*DD*DDDD",
70
+ "DD*D*DDDD",
71
+ "D*D*DDDD",
72
+ "DD*DD*DD",
73
+ "D*DD*DD",
74
+ "DD*D*DD",
75
+ "D*D*DD",
76
+ "DDDD*M*DD",
77
+ "DDDD*M*D",
78
+ "DD*M*DD",
79
+ "DD*M*D",
80
+ "DD*M*DDDD",
81
+ "D*M*DDDD",
82
+ "DD*M*DD",
83
+ "D*M*DD",
84
+ "M*DD*DDDD",
85
+ "M*D*DDDD",
86
+ "M*DD*DD",
87
+ "M*D*DD",
88
+ "M*DD**DDDD",
89
+ "M*D**DDDD",
90
+ "M*DD**DD",
91
+ "M*D**DD",
92
+ ]
93
+
94
+ TIME_PATTERN: List[str] = [
95
+ "DD:DD:DD",
96
+ "DD:DD:DD ",
97
+ "DD:DD:DD.DDD",
98
+ "DD:DD:DD.DDD ",
99
+ "DD:DD:DD,DDD",
100
+ "DD:DD:DD,DDD ",
101
+ "D:DD:DD",
102
+ "D:DD:DD ",
103
+ "D:DD:DD.DDD",
104
+ "D:DD:DD.DDD ",
105
+ "D:DD:DD,DDD",
106
+ "D:DD:DD,DDD ",
107
+ ]
108
+
109
+
110
+ MONTH_LITERAL = 1
111
+ WEEKDAY_LITERAL = 2
112
+ DIGIT_LITERAL = 3
113
+ THREE_DIGIT_LITERAL = 4
114
+ FOUR_DIGIT_LITERAL = 5
115
+ DATE_PHRASE = 6
116
+ NOT_DATE_LITERAL = -1
117
+
118
+ HOROZONTAL_PRINT_GAP = 3
119
+ VERTICAL_PRINT_GAP = 2
120
+ TERMINATION_SYMBOL = "^"
121
+
122
+
123
+ def buildTree(item_list: List[str], parent_node: PredictionModelNode) -> None:
124
+ for item in item_list:
125
+ parent = parent_node
126
+ parent_node.charcter = "\x00"
127
+ for idx, char in enumerate(item):
128
+ node = parent.get_child(char)
129
+ if node is None:
130
+ child = PredictionModelNode()
131
+ child.charcter = char
132
+ if idx + 1 == len(item):
133
+ child.explict_date_fragment = True
134
+ parent.add_child(child)
135
+ parent = child
136
+ else:
137
+ if idx + 1 == len(item):
138
+ node.explict_date_fragment = True
139
+ parent = node
140
+
141
+
142
+ def getProbables(tree: PredictionModelNode) -> str:
143
+ if tree is None:
144
+ return ""
145
+ kids = tree.childern
146
+ pattern = f"{tree.charcter} -->"
147
+ for kid in kids:
148
+ pattern = f"{pattern} {kid.charcter}"
149
+ return pattern
150
+
151
+
152
+ def printTree(tree: PredictionModelNode) -> None:
153
+ tree = sortTree(tree)
154
+ display_object = displayBuilder(DisplayObject(), tree)
155
+ print_buffer: List[str] = []
156
+ line = getBlankLine(display_object.width)
157
+ prev_level = 0
158
+ for tc in display_object.displayBuffer:
159
+ if prev_level == tc.level:
160
+ line = line[: tc.leftSpace] + tc.symbol + line[tc.leftSpace + len(tc.symbol) :]
161
+ else:
162
+ line = line.rstrip() + "\n"
163
+ print_buffer.append(line)
164
+ line = getBlankLine(display_object.width)
165
+ line = line[: tc.leftSpace] + tc.symbol + line[tc.leftSpace + len(tc.symbol) :]
166
+ prev_level = tc.level
167
+ print_buffer.append(line)
168
+ print("".join(print_buffer))
169
+
170
+
171
+ def displayBuilder(display: DisplayObject, tree: PredictionModelNode) -> DisplayObject:
172
+ if isFamilyUnit(tree):
173
+ return familyDisplayBuilder(tree)
174
+
175
+ horizontal_display = DisplayObject()
176
+ for kid in tree.childern:
177
+ recursive_display = displayBuilder(horizontal_display, kid)
178
+ horizontal_display = adjustHorizontalDisplay(horizontal_display, recursive_display)
179
+
180
+ horizontal_display.displayBuffer.sort()
181
+
182
+ vertical_display = DisplayObject()
183
+ dad_joints = [0] * tree.children_count()
184
+
185
+ j = 0
186
+ for tc in horizontal_display.displayBuffer:
187
+ if tc.level > 0 or j >= len(dad_joints):
188
+ break
189
+ if tc.symbol not in {"/", "\\", "_", "|"} and tc.symbol.strip():
190
+ dad_joints[j] = tc.leftSpace
191
+ j += 1
192
+
193
+ if tree.children_count() == 0:
194
+ return horizontal_display
195
+ if tree.children_count() == 1:
196
+ symbol = f"{tree.charcter}{TERMINATION_SYMBOL}" if tree.explict_date_fragment else f"{tree.charcter}"
197
+ tc = TreeChar(symbol, dad_joints[0], 0)
198
+ vertical_display.displayBuffer.append(tc)
199
+ else:
200
+ dad_joints.sort()
201
+ symbol = "_"
202
+ if len(dad_joints) % 2 == 0:
203
+ papa_position = 1 + (dad_joints[-1] + dad_joints[0]) // 2
204
+ else:
205
+ papa_position = dad_joints[len(dad_joints) // 2] + 1
206
+ papa_position -= 1
207
+ for k in range(dad_joints[0] + 1, dad_joints[-1] + 1 - 2 + 1):
208
+ if k == papa_position:
209
+ s = f"{tree.charcter or '$'}"
210
+ if tree.explict_date_fragment:
211
+ s = f"{s}{TERMINATION_SYMBOL}"
212
+ tc = TreeChar(s, k, 0)
213
+ else:
214
+ tc = TreeChar(symbol, k, 0)
215
+ vertical_display.displayBuffer.append(tc)
216
+
217
+ for joint in dad_joints:
218
+ for m in range(VERTICAL_PRINT_GAP):
219
+ vertical_display.displayBuffer.append(TreeChar("|", joint, m + 1))
220
+
221
+ display = adjustVerticalDisplay(horizontal_display, vertical_display)
222
+ return display
223
+
224
+
225
+ def adjustVerticalDisplay(horizontal_display: DisplayObject, vertical_display: DisplayObject) -> DisplayObject:
226
+ if not horizontal_display.displayBuffer:
227
+ return vertical_display
228
+ vertical_display.displayBuffer.sort()
229
+ for tc in horizontal_display.displayBuffer:
230
+ tc.level += VERTICAL_PRINT_GAP + 1
231
+ vertical_display.displayBuffer.append(tc)
232
+ vertical_display.width = horizontal_display.width
233
+ return vertical_display
234
+
235
+
236
+ def adjustHorizontalDisplay(display: DisplayObject, kid_display: DisplayObject) -> DisplayObject:
237
+ if not display.displayBuffer:
238
+ return kid_display
239
+
240
+ left_pos = display.width
241
+ for tc in kid_display.displayBuffer:
242
+ tc.leftSpace += left_pos + HOROZONTAL_PRINT_GAP
243
+ inserted = False
244
+ for index, display_tc in enumerate(display.displayBuffer):
245
+ if display_tc.level <= tc.level:
246
+ continue
247
+ display.displayBuffer.insert(max(0, index - 1), tc)
248
+ inserted = True
249
+ break
250
+ if not inserted:
251
+ display.displayBuffer.append(tc)
252
+ display.height = max(display.height, kid_display.height)
253
+ display.width = display.width + kid_display.width + HOROZONTAL_PRINT_GAP
254
+ return display
255
+
256
+
257
+ def familyDisplayBuilder(tree: PredictionModelNode) -> DisplayObject:
258
+ display_object = DisplayObject()
259
+ kids = tree.children_count()
260
+ char_val = f"{tree.charcter}"
261
+ if tree.explict_date_fragment:
262
+ char_val = f"{char_val}{TERMINATION_SYMBOL}"
263
+ if kids == 1:
264
+ display_object.displayBuffer.append(TreeChar(char_val, 0, 0))
265
+ display_object.displayBuffer.append(TreeChar("|", 0, 1))
266
+ kid_char = f"{tree.childern[0].charcter}"
267
+ display_object.displayBuffer.append(TreeChar(kid_char, 0, 2))
268
+ display_object.width = 1
269
+ display_object.height = 3
270
+ elif kids % 2 == 0:
271
+ display_object = evenKidCountTree(display_object, tree)
272
+ else:
273
+ display_object = oddKidCountTree(display_object, tree)
274
+ return display_object
275
+
276
+
277
+ def evenKidCountTree(display_object: DisplayObject, tree: PredictionModelNode) -> DisplayObject:
278
+ kids = tree.children_count()
279
+ papa_position = kids // 2
280
+ char_val = f"{tree.charcter}"
281
+ if tree.explict_date_fragment:
282
+ char_val = f"{char_val}{TERMINATION_SYMBOL}"
283
+ display_object.displayBuffer.append(TreeChar(char_val, papa_position, 0))
284
+ display_object.height = papa_position + 2
285
+ display_object.width = kids + 1
286
+ for i in range(kids // 2):
287
+ markers = (i + 1) * 2
288
+ coeff = 1
289
+ for j in range(markers):
290
+ if coeff == markers // 2 + 1:
291
+ coeff = 1
292
+ if j < markers // 2:
293
+ symbol = "|"
294
+ left_pos = papa_position - coeff
295
+ coeff += 1
296
+ if j == markers // 2 - 1:
297
+ symbol = "/"
298
+ display_object.displayBuffer.append(TreeChar(symbol, left_pos, i + 1))
299
+ else:
300
+ right_pos = papa_position + coeff
301
+ coeff += 1
302
+ symbol = "|"
303
+ if (j == markers - 1 and i != 0) or markers < 3:
304
+ symbol = "\\"
305
+ display_object.displayBuffer.append(TreeChar(symbol, right_pos, i + 1))
306
+ for i in range(kids):
307
+ kid_val = f"{tree.childern[i].charcter}"
308
+ if i < kids // 2:
309
+ display_object.displayBuffer.append(TreeChar(kid_val, i, kids // 2 + 1))
310
+ else:
311
+ display_object.displayBuffer.append(TreeChar(kid_val, i + 1, kids // 2 + 1))
312
+ return display_object
313
+
314
+
315
+ def oddKidCountTree(display_object: DisplayObject, tree: PredictionModelNode) -> DisplayObject:
316
+ kids = tree.children_count()
317
+ papa_position = (kids - 1) // 2
318
+ char_val = f"{tree.charcter}"
319
+ if tree.explict_date_fragment:
320
+ char_val = f"{char_val}{TERMINATION_SYMBOL}"
321
+ display_object.displayBuffer.append(TreeChar(char_val, papa_position, 0))
322
+ display_object.height = papa_position + 2
323
+ display_object.width = kids
324
+ for i in range((kids - 1) // 2):
325
+ markers = 2 * i + 3
326
+ coeff = 1
327
+ for j in range(markers):
328
+ if coeff == markers // 2 + 1:
329
+ coeff = 1
330
+ if j < markers // 2:
331
+ symbol = "|"
332
+ left_pos = papa_position - coeff
333
+ coeff += 1
334
+ if j == markers // 2 - 1 and markers > 2:
335
+ symbol = "/"
336
+ display_object.displayBuffer.append(TreeChar(symbol, left_pos, i + 1))
337
+ elif j == markers // 2:
338
+ display_object.displayBuffer.append(TreeChar("|", papa_position, i + 1))
339
+ else:
340
+ right_pos = papa_position + coeff
341
+ coeff += 1
342
+ symbol = "|"
343
+ if j == markers - 1 and markers > 2:
344
+ symbol = "\\"
345
+ display_object.displayBuffer.append(TreeChar(symbol, right_pos, i + 1))
346
+ for i in range(kids):
347
+ kid_val = f"{tree.childern[i].charcter}"
348
+ display_object.displayBuffer.append(TreeChar(kid_val, i, kids // 2 + 1))
349
+ return display_object
350
+
351
+
352
+ def getMaxTreeHeight(tree: PredictionModelNode) -> int:
353
+ if tree.has_childern():
354
+ heights = [getMaxTreeHeight(child) for child in tree.childern]
355
+ return max(heights) + 1
356
+ return 0
357
+
358
+
359
+ def sortTree(tree: PredictionModelNode) -> PredictionModelNode:
360
+ if tree.has_childern():
361
+ for idx, child in enumerate(tree.childern):
362
+ tree.childern[idx] = sortTree(child)
363
+ swapped = True
364
+ if tree.children_count() <= 1:
365
+ return tree
366
+ while swapped:
367
+ swapped = False
368
+ for i in range(tree.children_count() - 1):
369
+ this_height = getMaxTreeHeight(tree.childern[i])
370
+ next_height = getMaxTreeHeight(tree.childern[i + 1])
371
+ if this_height < next_height:
372
+ swapped = True
373
+ tree.childern[i], tree.childern[i + 1] = tree.childern[i + 1], tree.childern[i]
374
+ return tree
375
+
376
+
377
+ def isFamilyUnit(tree: PredictionModelNode) -> bool:
378
+ if tree.has_childern():
379
+ return all(not node.has_childern() for node in tree.childern)
380
+ return True
381
+
382
+
383
+ def getBlankLine(length: int) -> str:
384
+ result = " "
385
+ for _ in range(length):
386
+ result = f" {result}"
387
+ return result
388
+
389
+
390
+ def getRegexPattern(tree_elements: List[str]) -> str:
391
+ tree = PredictionModelNode()
392
+ buildTree(tree_elements, tree)
393
+ tree = sortTree(tree)
394
+ return _getRegexPattern(tree)
395
+
396
+
397
+ def _getRegexPattern(tree: PredictionModelNode) -> str:
398
+ if isFamilyUnit(tree):
399
+ return getFamilyUnitPattern(tree)
400
+ if tree.has_childern():
401
+ buffer = []
402
+ buffer.append(tree.charcter)
403
+ if tree.children_count() == 1:
404
+ buffer.append(_getRegexPattern(tree.childern[0]))
405
+ return "".join(buffer)
406
+ buffer.append("(")
407
+ for idx, kid in enumerate(tree.childern):
408
+ buffer.append(_getRegexPattern(kid))
409
+ if idx + 1 < tree.children_count():
410
+ buffer.append("|")
411
+ buffer.append(")")
412
+ return "".join(buffer)
413
+ return str(tree.charcter)
414
+
415
+
416
+ def getFamilyUnitPattern(tree: PredictionModelNode) -> str:
417
+ buffer: List[str] = []
418
+ if not tree.childern:
419
+ return ""
420
+ buffer.append(str(tree.charcter))
421
+ if len(tree.childern) == 1:
422
+ buffer.append(str(tree.childern[0].charcter))
423
+ return "".join(buffer)
424
+ buffer.append("([")
425
+ for kid in tree.childern:
426
+ buffer.append(str(kid.charcter))
427
+ buffer.append("])")
428
+ return "".join(buffer)
429
+
430
+
431
+ def _initialize_trees() -> None:
432
+ monthPredictionTree.level = 0
433
+ monthPredictionTree.charcter = "0"
434
+ patternPredictionTree.level = 0
435
+ patternPredictionTree.charcter = "0"
436
+ timePredictionTree.level = 0
437
+ timePredictionTree.charcter = "0"
438
+ weekPredictionTree.level = 0
439
+ weekPredictionTree.charcter = "0"
440
+
441
+ buildTree(MONTH_FULL, monthPredictionTree)
442
+ buildTree(MONTH_SHORT, monthPredictionTree)
443
+ buildTree(WEEKDAY_FULL, weekPredictionTree)
444
+ buildTree(WEEKDAY_SHORT, weekPredictionTree)
445
+ buildTree(PATTERN, patternPredictionTree)
446
+ buildTree(TIME_PATTERN, timePredictionTree)
447
+
448
+
449
+ _initialize_trees()
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import List
5
+
6
+
7
+ @dataclass
8
+ class TreeChar:
9
+ symbol: str = ""
10
+ leftSpace: int = 0
11
+ level: int = 0
12
+
13
+ def __lt__(self, other: "TreeChar") -> bool:
14
+ return self.level < other.level
15
+
16
+
17
+ @dataclass
18
+ class DisplayObject:
19
+ displayBuffer: List[TreeChar] = field(default_factory=list)
20
+ height: int = 0
21
+ width: int = 0
22
+
@@ -0,0 +1,169 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ from typing import List
5
+
6
+ try:
7
+ from . import dictionary as Dictionary
8
+ except ImportError: # pragma: no cover - fallback for direct module execution
9
+ from dateparserpython import dictionary as Dictionary
10
+
11
+
12
+ def isDateLieral(token: str) -> int:
13
+ """
14
+ Port of Helper.isDateLieral from Java. Returns Dictionary constants that
15
+ describe the literal type for quick scanning.
16
+ """
17
+
18
+ s = token.lower()
19
+ if len(token) > 9:
20
+ return Dictionary.NOT_DATE_LITERAL
21
+ if len(s) <= 2 and isDigit(s):
22
+ return Dictionary.DIGIT_LITERAL
23
+ if len(s) == 3 and isDigit(s):
24
+ return Dictionary.THREE_DIGIT_LITERAL
25
+ if len(s) == 4 and isDigit(s):
26
+ return Dictionary.FOUR_DIGIT_LITERAL
27
+ if len(s) <= 2:
28
+ return Dictionary.NOT_DATE_LITERAL
29
+ if any(char in s for char in "kqxz"):
30
+ return Dictionary.NOT_DATE_LITERAL
31
+ if isWeekDayLiteral(s):
32
+ return Dictionary.WEEKDAY_LITERAL
33
+ if isMonthLiteral(s):
34
+ return Dictionary.MONTH_LITERAL
35
+ return Dictionary.NOT_DATE_LITERAL
36
+
37
+
38
+ def isMonthLiteral(s: str) -> bool:
39
+ if "w" in s:
40
+ return False
41
+ if len(s) == 3 and ("h" in s or "i" in s):
42
+ return False
43
+ if s in Dictionary.MONTH_SHORT:
44
+ return True
45
+ if s in Dictionary.MONTH_FULL:
46
+ return True
47
+ return False
48
+
49
+
50
+ def hasFullMonthLiteral(s: str) -> bool:
51
+ s = s.lower()
52
+ return any(month in s for month in Dictionary.MONTH_FULL)
53
+
54
+
55
+ def isWeekDayLiteral(s: str) -> bool:
56
+ if any(char in s for char in "bcgjlpv"):
57
+ return False
58
+ if s in Dictionary.WEEKDAY_SHORT:
59
+ return True
60
+ if s in Dictionary.WEEKDAY_FULL:
61
+ return True
62
+ return False
63
+
64
+
65
+ def isDigit(value) -> bool:
66
+ s = str(value)
67
+ if not s:
68
+ return False
69
+ return all("0" <= c <= "9" for c in s)
70
+
71
+
72
+ def isDelimeter(c: str) -> bool:
73
+ return c in "\\/ -.,:_"
74
+
75
+
76
+ def isTimeSeprator(c: str) -> bool:
77
+ return c in " _-T"
78
+
79
+
80
+ def testDataForDateFormats() -> List[str]:
81
+ date_patterns = []
82
+ for pattern in Dictionary.PATTERN:
83
+ test_data = "".join(getTestDataForChar(char) for char in pattern)
84
+ date_patterns.append(test_data)
85
+ time_patterns = []
86
+ for pattern in Dictionary.TIME_PATTERN:
87
+ test_data = "".join(getTestDataForChar(char) for char in pattern)
88
+ time_patterns.append(test_data)
89
+ combined = []
90
+ for date_fragment in date_patterns:
91
+ for time_fragment in time_patterns:
92
+ combined.append(f"{date_fragment} {time_fragment}")
93
+ date_patterns.extend(combined)
94
+ return date_patterns
95
+
96
+
97
+ def getTestDataForChar(c: str) -> str:
98
+ if c == "D":
99
+ return str(random.randint(0, 9))
100
+ if c == "*":
101
+ return getTestCaseDelimeter(random.randint(1, 6))
102
+ if c == "M":
103
+ return getTestMonth(random.randint(1, 24))
104
+ return c
105
+
106
+
107
+ def getTestCaseDelimeter(i: int) -> str:
108
+ mapping = {
109
+ 1: "\\",
110
+ 2: "/",
111
+ 3: "-",
112
+ 4: " ",
113
+ 5: ".",
114
+ 6: ",",
115
+ }
116
+ return mapping.get(i, "~")
117
+
118
+
119
+ def getTestMonth(i: int) -> str:
120
+ months = {
121
+ 1: "january",
122
+ 2: "february",
123
+ 3: "march",
124
+ 4: "april",
125
+ 5: "may",
126
+ 6: "june",
127
+ 7: "july",
128
+ 8: "august",
129
+ 9: "september",
130
+ 10: "october",
131
+ 11: "november",
132
+ 12: "december",
133
+ 13: "jan",
134
+ 14: "feb",
135
+ 15: "mar",
136
+ 16: "apr",
137
+ 17: "may",
138
+ 18: "jun",
139
+ 19: "jul",
140
+ 20: "aug",
141
+ 21: "sep",
142
+ 22: "oct",
143
+ 23: "nov",
144
+ 24: "dec",
145
+ }
146
+ return months.get(i, "")
147
+
148
+
149
+ def isFullMonth(s: str) -> bool:
150
+ s = s.lower()
151
+ return any(month in s for month in Dictionary.MONTH_FULL)
152
+
153
+
154
+ def getDaysinMonth(month: int, year: int) -> int:
155
+ if month > 12:
156
+ return -1
157
+ if month == 2:
158
+ if month % 4 == 0:
159
+ return 29
160
+ return 28
161
+ if month == 8:
162
+ return 31
163
+ if month < 8 and month % 2 == 1:
164
+ return 31
165
+ if month < 8 and month % 2 == 0:
166
+ return 30
167
+ if month % 2 == 1:
168
+ return 30
169
+ return 31
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+
7
+ @dataclass
8
+ class LocalDateModel:
9
+ original_text: Optional[str] = None
10
+ date_time_string: Optional[str] = None
11
+ con_date_format: Optional[str] = None
12
+ identified_date_format: Optional[str] = None
13
+ start: Optional[int] = None
14
+ end: Optional[int] = None
15
+
16
+ def __str__(self) -> str:
17
+ return (
18
+ "LocalDateModel("
19
+ f"original_text={self.original_text}, "
20
+ f"date_time_string={self.date_time_string}, "
21
+ f"con_date_format={self.con_date_format}, "
22
+ f"identified_date_format={self.identified_date_format}, "
23
+ f"start={self.start}, end={self.end})"
24
+ )
25
+
26
+
27
+ @dataclass
28
+ class DateElement:
29
+ data: str
30
+ tokenNum: int = 0
31
+ fragments: int = 0
32
+ isAlphaNumeric: bool = False
33
+ aphaNumericType: int = 0
34
+ startPos: int = 0
35
+ endPos: int = 0
36
+ hasAmPm: bool = False
37
+ timeFragment: Optional[str] = None
38
+ dateFragment: Optional[str] = None
39
+ dateTimeSeprator: str = " "
40
+
41
+ def getDateFragment(self) -> str:
42
+ if self.timeFragment is None:
43
+ return self.data
44
+ return self.dateFragment or ""
45
+
46
+ def __str__(self) -> str:
47
+ return (
48
+ "DateElement("
49
+ f"data={self.data}, tokenNum={self.tokenNum}, fragments={self.fragments}, "
50
+ f"isAlphaNumeric={self.isAlphaNumeric}, aphaNumericType={self.aphaNumericType}, "
51
+ f"startPos={self.startPos}, endPos={self.endPos}, hasAmPm={self.hasAmPm}, "
52
+ f"timeFragment={self.timeFragment}, dateFragment={self.dateFragment}, "
53
+ f"dateTimeSeprator={self.dateTimeSeprator})"
54
+ )
55
+