persiantools 5.1.1__tar.gz → 5.2.0__tar.gz
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.
- {persiantools-5.1.1 → persiantools-5.2.0}/LICENSE +1 -1
- {persiantools-5.1.1/persiantools.egg-info → persiantools-5.2.0}/PKG-INFO +1 -1
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools/__init__.py +1 -1
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools/characters.py +6 -3
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools/jdatetime.py +130 -101
- {persiantools-5.1.1 → persiantools-5.2.0/persiantools.egg-info}/PKG-INFO +1 -1
- {persiantools-5.1.1 → persiantools-5.2.0}/tests/test_characters.py +10 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/tests/test_digits.py +3 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/tests/test_jalalidate.py +44 -8
- {persiantools-5.1.1 → persiantools-5.2.0}/MANIFEST.in +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/README.md +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools/digits.py +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools/utils.py +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools.egg-info/SOURCES.txt +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools.egg-info/dependency_links.txt +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools.egg-info/not-zip-safe +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools.egg-info/requires.txt +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/persiantools.egg-info/top_level.txt +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/pyproject.toml +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/setup.cfg +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/setup.py +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/tests/test_jalalidatetime.py +0 -0
- {persiantools-5.1.1 → persiantools-5.2.0}/tests/test_utils.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import re
|
|
2
2
|
|
|
3
3
|
CHARACTER_MAP_AR_TO_FA = {
|
|
4
4
|
"دِ": "د",
|
|
@@ -14,6 +14,9 @@ CHARACTER_MAP_AR_TO_FA = {
|
|
|
14
14
|
|
|
15
15
|
CHARACTER_MAP_FA_TO_AR = {"ی": "ي", "ک": "ك"}
|
|
16
16
|
|
|
17
|
+
AR_TO_FA_PATTERN = re.compile("|".join(map(re.escape, CHARACTER_MAP_AR_TO_FA.keys())))
|
|
18
|
+
FA_TO_AR_PATTERN = re.compile("|".join(map(re.escape, CHARACTER_MAP_FA_TO_AR.keys())))
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
def ar_to_fa(string: str) -> str:
|
|
19
22
|
"""
|
|
@@ -35,7 +38,7 @@ def ar_to_fa(string: str) -> str:
|
|
|
35
38
|
if not isinstance(string, str):
|
|
36
39
|
raise TypeError("Input must be of type str")
|
|
37
40
|
|
|
38
|
-
return
|
|
41
|
+
return AR_TO_FA_PATTERN.sub(lambda match: CHARACTER_MAP_AR_TO_FA[match.group(0)], string)
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def fa_to_ar(string: str) -> str:
|
|
@@ -58,4 +61,4 @@ def fa_to_ar(string: str) -> str:
|
|
|
58
61
|
if not isinstance(string, str):
|
|
59
62
|
raise TypeError("Input must be of type str")
|
|
60
63
|
|
|
61
|
-
return
|
|
64
|
+
return FA_TO_AR_PATTERN.sub(lambda match: CHARACTER_MAP_FA_TO_AR[match.group(0)], string)
|
|
@@ -132,90 +132,21 @@ _MONTH_COUNT = [
|
|
|
132
132
|
_FRACTION_CORRECTION = [100000, 10000, 1000, 100, 10]
|
|
133
133
|
|
|
134
134
|
# List of years that are exceptions to the 33-year leap year rule
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
2030,
|
|
151
|
-
2059,
|
|
152
|
-
2063,
|
|
153
|
-
2096,
|
|
154
|
-
2129,
|
|
155
|
-
2158,
|
|
156
|
-
2162,
|
|
157
|
-
2191,
|
|
158
|
-
2195,
|
|
159
|
-
2224,
|
|
160
|
-
2228,
|
|
161
|
-
2257,
|
|
162
|
-
2261,
|
|
163
|
-
2290,
|
|
164
|
-
2294,
|
|
165
|
-
2323,
|
|
166
|
-
2327,
|
|
167
|
-
2356,
|
|
168
|
-
2360,
|
|
169
|
-
2389,
|
|
170
|
-
2393,
|
|
171
|
-
2422,
|
|
172
|
-
2426,
|
|
173
|
-
2455,
|
|
174
|
-
2459,
|
|
175
|
-
2488,
|
|
176
|
-
2492,
|
|
177
|
-
2521,
|
|
178
|
-
2525,
|
|
179
|
-
2554,
|
|
180
|
-
2558,
|
|
181
|
-
2587,
|
|
182
|
-
2591,
|
|
183
|
-
2620,
|
|
184
|
-
2624,
|
|
185
|
-
2653,
|
|
186
|
-
2657,
|
|
187
|
-
2686,
|
|
188
|
-
2690,
|
|
189
|
-
2719,
|
|
190
|
-
2723,
|
|
191
|
-
2748,
|
|
192
|
-
2752,
|
|
193
|
-
2756,
|
|
194
|
-
2781,
|
|
195
|
-
2785,
|
|
196
|
-
2789,
|
|
197
|
-
2818,
|
|
198
|
-
2822,
|
|
199
|
-
2847,
|
|
200
|
-
2851,
|
|
201
|
-
2855,
|
|
202
|
-
2880,
|
|
203
|
-
2884,
|
|
204
|
-
2888,
|
|
205
|
-
2913,
|
|
206
|
-
2917,
|
|
207
|
-
2921,
|
|
208
|
-
2946,
|
|
209
|
-
2950,
|
|
210
|
-
2954,
|
|
211
|
-
2979,
|
|
212
|
-
2983,
|
|
213
|
-
2987,
|
|
214
|
-
]
|
|
215
|
-
|
|
216
|
-
NON_LEAP_CORRECTION_SET = frozenset(NON_LEAP_CORRECTION)
|
|
217
|
-
|
|
218
|
-
MIN_NON_LEAP_CORRECTION = NON_LEAP_CORRECTION[0]
|
|
135
|
+
# fmt: off
|
|
136
|
+
NON_LEAP_CORRECTION_SET = frozenset(
|
|
137
|
+
[
|
|
138
|
+
1502, 1601, 1634, 1667, 1700, 1733, 1766, 1799, 1832, 1865, 1898, 1931,
|
|
139
|
+
1964, 1997, 2030, 2059, 2063, 2096, 2129, 2158, 2162, 2191, 2195, 2224,
|
|
140
|
+
2228, 2257, 2261, 2290, 2294, 2323, 2327, 2356, 2360, 2389, 2393, 2422,
|
|
141
|
+
2426, 2455, 2459, 2488, 2492, 2521, 2525, 2554, 2558, 2587, 2591, 2620,
|
|
142
|
+
2624, 2653, 2657, 2686, 2690, 2719, 2723, 2748, 2752, 2756, 2781, 2785,
|
|
143
|
+
2789, 2818, 2822, 2847, 2851, 2855, 2880, 2884, 2888, 2913, 2917, 2921,
|
|
144
|
+
2946, 2950, 2954, 2979, 2983, 2987,
|
|
145
|
+
]
|
|
146
|
+
)
|
|
147
|
+
# fmt: on
|
|
148
|
+
|
|
149
|
+
MIN_NON_LEAP_CORRECTION = 1502
|
|
219
150
|
|
|
220
151
|
|
|
221
152
|
def _is_ascii_digit(c: str) -> bool:
|
|
@@ -270,10 +201,7 @@ class JalaliDate:
|
|
|
270
201
|
raise ValueError("locale must be 'en' or 'fa'")
|
|
271
202
|
|
|
272
203
|
if isinstance(year, JalaliDate) and month is None:
|
|
273
|
-
month = year.month
|
|
274
|
-
day = year.day
|
|
275
|
-
locale = year.locale
|
|
276
|
-
year = year.year
|
|
204
|
+
year, month, day, locale = year.year, year.month, year.day, year.locale
|
|
277
205
|
|
|
278
206
|
elif isinstance(year, date):
|
|
279
207
|
jdate = self.to_jalali(year)
|
|
@@ -284,32 +212,49 @@ class JalaliDate:
|
|
|
284
212
|
):
|
|
285
213
|
self.__setstate__(year)
|
|
286
214
|
|
|
287
|
-
year = self._year
|
|
288
|
-
month = self._month
|
|
289
|
-
day = self._day
|
|
290
|
-
|
|
291
|
-
year, month, day, locale = self._check_date_fields(year, month, day, locale)
|
|
215
|
+
year, month, day = self._year, self._month, self._day
|
|
292
216
|
|
|
293
|
-
self._year = year
|
|
294
|
-
self._month = month
|
|
295
|
-
self._day = day
|
|
296
|
-
self._locale = locale
|
|
217
|
+
self._year, self._month, self._day, self._locale = self._check_date_fields(year, month, day, locale)
|
|
297
218
|
self._hashcode = -1
|
|
298
219
|
|
|
299
220
|
@property
|
|
300
221
|
def year(self) -> int:
|
|
222
|
+
"""
|
|
223
|
+
Get the year component of the date.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
int: The year as an integer.
|
|
227
|
+
"""
|
|
301
228
|
return self._year
|
|
302
229
|
|
|
303
230
|
@property
|
|
304
231
|
def month(self) -> int:
|
|
232
|
+
"""
|
|
233
|
+
Get the month component of the date.
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
int: The month as an integer.
|
|
237
|
+
"""
|
|
305
238
|
return self._month
|
|
306
239
|
|
|
307
240
|
@property
|
|
308
241
|
def day(self) -> int:
|
|
242
|
+
"""
|
|
243
|
+
Get the day of the month.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
int: The day of the month.
|
|
247
|
+
"""
|
|
309
248
|
return self._day
|
|
310
249
|
|
|
311
250
|
@property
|
|
312
251
|
def locale(self):
|
|
252
|
+
"""
|
|
253
|
+
Get the locale setting for the current instance.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
str: The locale setting.
|
|
257
|
+
"""
|
|
313
258
|
return self._locale
|
|
314
259
|
|
|
315
260
|
@locale.setter
|
|
@@ -394,7 +339,7 @@ class JalaliDate:
|
|
|
394
339
|
Returns:
|
|
395
340
|
bool: True if the year is a leap year, False otherwise.
|
|
396
341
|
"""
|
|
397
|
-
if not MINYEAR <= year <= MAXYEAR:
|
|
342
|
+
if not (MINYEAR <= year <= MAXYEAR):
|
|
398
343
|
raise ValueError(f"Year must be between {MINYEAR} and {MAXYEAR}")
|
|
399
344
|
|
|
400
345
|
if year < MIN_NON_LEAP_CORRECTION:
|
|
@@ -653,7 +598,19 @@ class JalaliDate:
|
|
|
653
598
|
|
|
654
599
|
@classmethod
|
|
655
600
|
def fromisoformat(cls, date_string: str):
|
|
656
|
-
"""
|
|
601
|
+
"""
|
|
602
|
+
Construct a JalaliDate from an ISO 8601 formatted date string.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
date_string (str): The date string in ISO 8601 format.
|
|
606
|
+
|
|
607
|
+
Returns:
|
|
608
|
+
JalaliDate: A JalaliDate object corresponding to the given date string.
|
|
609
|
+
|
|
610
|
+
Raises:
|
|
611
|
+
TypeError: If the provided argument is not a string.
|
|
612
|
+
ValueError: If the provided string is not a valid ISO 8601 formatted date.
|
|
613
|
+
"""
|
|
657
614
|
if not isinstance(date_string, str):
|
|
658
615
|
raise TypeError("fromisoformat: argument must be str")
|
|
659
616
|
|
|
@@ -751,6 +708,21 @@ class JalaliDate:
|
|
|
751
708
|
return cls(date.fromtimestamp(timestamp))
|
|
752
709
|
|
|
753
710
|
def weekday(self) -> int:
|
|
711
|
+
"""
|
|
712
|
+
Returns the day of the week as an integer.
|
|
713
|
+
|
|
714
|
+
The days of the week are represented as follows:
|
|
715
|
+
0 - Shanbeh
|
|
716
|
+
1 - Yekshanbeh
|
|
717
|
+
2 - Doshanbeh
|
|
718
|
+
3 - Seshanbeh
|
|
719
|
+
4 - Chaharshanbeh
|
|
720
|
+
5 - Panjshanbeh
|
|
721
|
+
6 - Jomeh
|
|
722
|
+
|
|
723
|
+
Returns:
|
|
724
|
+
int: An integer representing the day of the week.
|
|
725
|
+
"""
|
|
754
726
|
return (self.toordinal() + 4) % 7
|
|
755
727
|
|
|
756
728
|
def __format__(self, fmt: str):
|
|
@@ -762,9 +734,23 @@ class JalaliDate:
|
|
|
762
734
|
return str(self)
|
|
763
735
|
|
|
764
736
|
def isoweekday(self) -> int:
|
|
737
|
+
"""
|
|
738
|
+
Return the ISO weekday.
|
|
739
|
+
|
|
740
|
+
The ISO weekday is a number representing the day of the week, where Shanbeh is 1 and Jomeh is 7.
|
|
741
|
+
|
|
742
|
+
Returns:
|
|
743
|
+
int: An integer representing the ISO weekday.
|
|
744
|
+
"""
|
|
765
745
|
return self.weekday() + 1
|
|
766
746
|
|
|
767
747
|
def week_of_year(self) -> int:
|
|
748
|
+
"""
|
|
749
|
+
Calculate the week number of the year for the current Jalali date.
|
|
750
|
+
|
|
751
|
+
Returns:
|
|
752
|
+
int: The week number of the year, starting from 1.
|
|
753
|
+
"""
|
|
768
754
|
o = JalaliDate(self._year, 1, 1).weekday()
|
|
769
755
|
days = self.days_before_month(self._month) + self._day + o
|
|
770
756
|
|
|
@@ -776,10 +762,24 @@ class JalaliDate:
|
|
|
776
762
|
return week_no
|
|
777
763
|
|
|
778
764
|
def isocalendar(self):
|
|
779
|
-
"""
|
|
765
|
+
"""
|
|
766
|
+
Return a 3-tuple containing ISO year, week number, and weekday.
|
|
767
|
+
|
|
768
|
+
Returns:
|
|
769
|
+
tuple: A tuple containing the ISO year, ISO week number, and ISO weekday.
|
|
770
|
+
"""
|
|
780
771
|
return self.year, self.week_of_year(), self.isoweekday()
|
|
781
772
|
|
|
782
773
|
def ctime(self) -> str:
|
|
774
|
+
"""
|
|
775
|
+
Return a string representing the date and time in a locale’s appropriate format.
|
|
776
|
+
|
|
777
|
+
This method uses the strftime() function with the format code "%c" to generate
|
|
778
|
+
a string representation of the date and time.
|
|
779
|
+
|
|
780
|
+
Returns:
|
|
781
|
+
str: A string representing the date and time.
|
|
782
|
+
"""
|
|
783
783
|
return self.strftime("%c")
|
|
784
784
|
|
|
785
785
|
def strftime(self, fmt: str, locale=None) -> str:
|
|
@@ -923,7 +923,6 @@ class JalaliDate:
|
|
|
923
923
|
__radd__ = __add__
|
|
924
924
|
|
|
925
925
|
def __sub__(self, other):
|
|
926
|
-
"""Subtract two JalaliDates/dates, or a JalaliDate/date and a timedelta."""
|
|
927
926
|
if isinstance(other, timedelta):
|
|
928
927
|
return self + timedelta(-other.days)
|
|
929
928
|
|
|
@@ -1030,22 +1029,52 @@ class JalaliDateTime(JalaliDate):
|
|
|
1030
1029
|
|
|
1031
1030
|
@property
|
|
1032
1031
|
def hour(self) -> int:
|
|
1032
|
+
"""
|
|
1033
|
+
Get the hour component of the datetime.
|
|
1034
|
+
|
|
1035
|
+
Returns:
|
|
1036
|
+
int: The hour component of the datetime.
|
|
1037
|
+
"""
|
|
1033
1038
|
return self._hour
|
|
1034
1039
|
|
|
1035
1040
|
@property
|
|
1036
1041
|
def minute(self) -> int:
|
|
1042
|
+
"""
|
|
1043
|
+
Get the minute component of the datetime.
|
|
1044
|
+
|
|
1045
|
+
Returns:
|
|
1046
|
+
int: The minute component of the datetime.
|
|
1047
|
+
"""
|
|
1037
1048
|
return self._minute
|
|
1038
1049
|
|
|
1039
1050
|
@property
|
|
1040
1051
|
def second(self) -> int:
|
|
1052
|
+
"""
|
|
1053
|
+
Get the second component of the time.
|
|
1054
|
+
|
|
1055
|
+
Returns:
|
|
1056
|
+
int: The second component of the time.
|
|
1057
|
+
"""
|
|
1041
1058
|
return self._second
|
|
1042
1059
|
|
|
1043
1060
|
@property
|
|
1044
1061
|
def microsecond(self) -> int:
|
|
1062
|
+
"""
|
|
1063
|
+
Returns the microsecond component of the datetime.
|
|
1064
|
+
|
|
1065
|
+
Returns:
|
|
1066
|
+
int: The microsecond component of the datetime.
|
|
1067
|
+
"""
|
|
1045
1068
|
return self._microsecond
|
|
1046
1069
|
|
|
1047
1070
|
@property
|
|
1048
1071
|
def tzinfo(self):
|
|
1072
|
+
"""
|
|
1073
|
+
Returns the time zone information associated with this datetime object.
|
|
1074
|
+
|
|
1075
|
+
:return: The time zone information.
|
|
1076
|
+
:rtype: tzinfo
|
|
1077
|
+
"""
|
|
1049
1078
|
return self._tzinfo
|
|
1050
1079
|
|
|
1051
1080
|
@classmethod
|
|
@@ -24,11 +24,18 @@ class TestDigits(TestCase):
|
|
|
24
24
|
with pytest.raises(TypeError):
|
|
25
25
|
characters.ar_to_fa(12345)
|
|
26
26
|
|
|
27
|
+
with self.assertRaises(TypeError):
|
|
28
|
+
characters.ar_to_fa(None)
|
|
29
|
+
|
|
27
30
|
orig = "السلام عليكم ٠١٢٣٤٥٦٧٨٩"
|
|
28
31
|
converted = characters.ar_to_fa(orig)
|
|
29
32
|
converted = digits.ar_to_fa(converted)
|
|
30
33
|
self.assertEqual(converted, "السلام علیکم ۰۱۲۳۴۵۶۷۸۹")
|
|
31
34
|
|
|
35
|
+
input_string = "يياكشيسِ"
|
|
36
|
+
expected_output = "ییاکشیس"
|
|
37
|
+
self.assertEqual(characters.ar_to_fa(input_string), expected_output)
|
|
38
|
+
|
|
32
39
|
def test_fa_to_fa(self):
|
|
33
40
|
self.assertEqual(characters.ar_to_fa("السلام علیکم"), "السلام علیکم")
|
|
34
41
|
self.assertEqual(characters.ar_to_fa("کیک"), "کیک")
|
|
@@ -48,3 +55,6 @@ class TestDigits(TestCase):
|
|
|
48
55
|
|
|
49
56
|
with pytest.raises(TypeError):
|
|
50
57
|
characters.fa_to_ar(12345)
|
|
58
|
+
|
|
59
|
+
with self.assertRaises(TypeError):
|
|
60
|
+
characters.fa_to_ar(None)
|
|
@@ -85,5 +85,8 @@ class TestDigits(TestCase):
|
|
|
85
85
|
with pytest.raises(digits.OutOfRangeException):
|
|
86
86
|
digits.to_word(1000000000000001)
|
|
87
87
|
|
|
88
|
+
with pytest.raises(digits.OutOfRangeException):
|
|
89
|
+
digits.to_word(0.123456789012345)
|
|
90
|
+
|
|
88
91
|
with pytest.raises(TypeError):
|
|
89
92
|
digits.to_word("123")
|
|
@@ -12,9 +12,7 @@ from persiantools.jdatetime import MAXYEAR, MINYEAR, JalaliDate
|
|
|
12
12
|
class TestJalaliDate(TestCase):
|
|
13
13
|
def test_shamsi_to_gregorian(self):
|
|
14
14
|
cases = [
|
|
15
|
-
(JalaliDate(
|
|
16
|
-
(JalaliDate(1210, 12, 30), date(1832, 3, 20)),
|
|
17
|
-
(JalaliDate(1211, 1, 1), date(1832, 3, 21)),
|
|
15
|
+
(JalaliDate(1100, 1, 1), date(1721, 3, 21)),
|
|
18
16
|
(JalaliDate(1367, 2, 14), date(1988, 5, 4)),
|
|
19
17
|
(JalaliDate(1395, 3, 21), date(2016, 6, 10)),
|
|
20
18
|
(JalaliDate(1395, 12, 9), date(2017, 2, 27)),
|
|
@@ -33,6 +31,7 @@ class TestJalaliDate(TestCase):
|
|
|
33
31
|
(JalaliDate(1403, 4, 8), date(2024, 6, 28)),
|
|
34
32
|
(JalaliDate(1403, 8, 18), date(2024, 11, 8)),
|
|
35
33
|
(JalaliDate(1403, 10, 27), date(2025, 1, 16)),
|
|
34
|
+
(JalaliDate(1210, 12, 29), date(1832, 3, 19)),
|
|
36
35
|
(JalaliDate(1367, 12, 29), date(1989, 3, 20)),
|
|
37
36
|
(JalaliDate(1392, 12, 29), date(2014, 3, 20)),
|
|
38
37
|
(JalaliDate(1398, 12, 29), date(2020, 3, 19)),
|
|
@@ -40,6 +39,8 @@ class TestJalaliDate(TestCase):
|
|
|
40
39
|
(JalaliDate(1400, 12, 29), date(2022, 3, 20)),
|
|
41
40
|
(JalaliDate(1402, 12, 29), date(2024, 3, 19)),
|
|
42
41
|
(JalaliDate(1403, 12, 29), date(2025, 3, 19)),
|
|
42
|
+
(JalaliDate(1504, 12, 29), date(2126, 3, 20)),
|
|
43
|
+
(JalaliDate(1210, 12, 30), date(1832, 3, 20)),
|
|
43
44
|
(JalaliDate(1391, 12, 30), date(2013, 3, 20)),
|
|
44
45
|
(JalaliDate(1395, 12, 30), date(2017, 3, 20)),
|
|
45
46
|
(JalaliDate(1399, 12, 30), date(2021, 3, 20)),
|
|
@@ -55,6 +56,7 @@ class TestJalaliDate(TestCase):
|
|
|
55
56
|
(JalaliDate(1400, 10, 11), date(2022, 1, 1)),
|
|
56
57
|
(JalaliDate(1402, 10, 11), date(2024, 1, 1)),
|
|
57
58
|
(JalaliDate(1403, 10, 12), date(2025, 1, 1)),
|
|
59
|
+
(JalaliDate(1211, 1, 1), date(1832, 3, 21)),
|
|
58
60
|
(JalaliDate(1367, 1, 1), date(1988, 3, 21)),
|
|
59
61
|
(JalaliDate(1388, 1, 1), date(2009, 3, 21)),
|
|
60
62
|
(JalaliDate(1396, 1, 1), date(2017, 3, 21)),
|
|
@@ -64,6 +66,7 @@ class TestJalaliDate(TestCase):
|
|
|
64
66
|
(JalaliDate(1402, 1, 1), date(2023, 3, 21)),
|
|
65
67
|
(JalaliDate(1403, 1, 1), date(2024, 3, 20)),
|
|
66
68
|
(JalaliDate(1404, 1, 1), date(2025, 3, 21)),
|
|
69
|
+
(JalaliDate(1505, 1, 1), date(2126, 3, 21)),
|
|
67
70
|
(JalaliDate.today(), date.today()),
|
|
68
71
|
]
|
|
69
72
|
for jdate, gdate in cases:
|
|
@@ -71,9 +74,6 @@ class TestJalaliDate(TestCase):
|
|
|
71
74
|
|
|
72
75
|
def test_gregorian_to_shamsi(self):
|
|
73
76
|
cases = [
|
|
74
|
-
(date(1832, 3, 19), JalaliDate(1210, 12, 29)),
|
|
75
|
-
(date(1832, 3, 20), JalaliDate(1210, 12, 30)),
|
|
76
|
-
(date(1832, 3, 21), JalaliDate(1211, 1, 1)),
|
|
77
77
|
(date(1988, 5, 4), JalaliDate(1367, 2, 14)),
|
|
78
78
|
(date(2122, 1, 31), JalaliDate(1500, 11, 11)),
|
|
79
79
|
(date(2017, 10, 19), JalaliDate(1396, 7, 27)),
|
|
@@ -90,9 +90,12 @@ class TestJalaliDate(TestCase):
|
|
|
90
90
|
(date(2000, 12, 31), JalaliDate(1379, 10, 11)),
|
|
91
91
|
(date(2023, 12, 31), JalaliDate(1402, 10, 10)),
|
|
92
92
|
(date(2024, 12, 31), JalaliDate(1403, 10, 11)),
|
|
93
|
+
(date(1832, 3, 19), JalaliDate(1210, 12, 29)),
|
|
94
|
+
(date(1832, 3, 20), JalaliDate(1210, 12, 30)),
|
|
93
95
|
(date(2017, 3, 20), JalaliDate(1395, 12, 30)),
|
|
94
96
|
(date(2021, 3, 20), JalaliDate(1399, 12, 30)),
|
|
95
97
|
(date(2025, 3, 20), JalaliDate(1403, 12, 30)),
|
|
98
|
+
(date(1832, 3, 21), JalaliDate(1211, 1, 1)),
|
|
96
99
|
(date(2000, 1, 1), JalaliDate(1378, 10, 11)),
|
|
97
100
|
(date(2012, 1, 1), JalaliDate(1390, 10, 11)),
|
|
98
101
|
(date(2013, 1, 1), JalaliDate(1391, 10, 12)),
|
|
@@ -107,6 +110,12 @@ class TestJalaliDate(TestCase):
|
|
|
107
110
|
(date(2023, 3, 21), JalaliDate(1402, 1, 1)),
|
|
108
111
|
(date(2024, 3, 20), JalaliDate(1403, 1, 1)),
|
|
109
112
|
(date(2025, 3, 21), JalaliDate(1404, 1, 1)),
|
|
113
|
+
(date(1827, 3, 22), JalaliDate(1206, 1, 1)),
|
|
114
|
+
(date(1828, 3, 21), JalaliDate(1207, 1, 1)),
|
|
115
|
+
(date(1839, 3, 21), JalaliDate(1218, 1, 1)),
|
|
116
|
+
(date(1864, 3, 20), JalaliDate(1243, 1, 1)),
|
|
117
|
+
(date(2118, 3, 21), JalaliDate(1497, 1, 1)),
|
|
118
|
+
(date(2119, 3, 21), JalaliDate(1498, 1, 1)),
|
|
110
119
|
(date.today(), JalaliDate.today()),
|
|
111
120
|
]
|
|
112
121
|
for gdate, jdate in cases:
|
|
@@ -279,6 +288,8 @@ class TestJalaliDate(TestCase):
|
|
|
279
288
|
# Known non-leap years
|
|
280
289
|
(1206, False),
|
|
281
290
|
(1207, False),
|
|
291
|
+
(1208, False),
|
|
292
|
+
(1209, False),
|
|
282
293
|
(1211, False),
|
|
283
294
|
(1215, False),
|
|
284
295
|
(1216, False),
|
|
@@ -302,6 +313,10 @@ class TestJalaliDate(TestCase):
|
|
|
302
313
|
(1409, False),
|
|
303
314
|
(1410, False),
|
|
304
315
|
(1411, False),
|
|
316
|
+
(1493, False),
|
|
317
|
+
(1495, False),
|
|
318
|
+
(1496, False),
|
|
319
|
+
(1497, False),
|
|
305
320
|
]
|
|
306
321
|
for year, is_leap in cases:
|
|
307
322
|
self.assertEqual(JalaliDate.is_leap(year), is_leap)
|
|
@@ -413,6 +428,7 @@ class TestJalaliDate(TestCase):
|
|
|
413
428
|
self.assertEqual(JalaliDate(1399, 1, 2).week_of_year(), 2)
|
|
414
429
|
self.assertEqual(JalaliDate(1403, 1, 5).week_of_year(), 2)
|
|
415
430
|
self.assertEqual(JalaliDate(1403, 4, 3).week_of_year(), 15)
|
|
431
|
+
self.assertEqual(JalaliDate(1403, 10, 28).week_of_year(), 44)
|
|
416
432
|
|
|
417
433
|
self.assertEqual(JalaliDate(1367, 2, 14).weekday(), 4)
|
|
418
434
|
self.assertEqual(JalaliDate(1393, 1, 1).weekday(), 6)
|
|
@@ -425,10 +441,13 @@ class TestJalaliDate(TestCase):
|
|
|
425
441
|
self.assertEqual(JalaliDate(1397, 1, 1).weekday(), 4)
|
|
426
442
|
self.assertEqual(JalaliDate(1397, 11, 29).weekday(), 2)
|
|
427
443
|
self.assertEqual(JalaliDate(1400, 1, 1).weekday(), 1)
|
|
444
|
+
self.assertEqual(JalaliDate(1403, 10, 28).weekday(), 6)
|
|
445
|
+
|
|
428
446
|
self.assertEqual(JalaliDate(1403, 4, 3).isoweekday(), 2)
|
|
429
447
|
self.assertEqual(JalaliDate(1400, 1, 1).isoweekday(), 2)
|
|
430
448
|
self.assertEqual(JalaliDate(1396, 7, 27).isoweekday(), 6)
|
|
431
449
|
self.assertEqual(JalaliDate(1397, 11, 29).isoweekday(), 3)
|
|
450
|
+
self.assertEqual(JalaliDate(1403, 10, 28).isoweekday(), 7)
|
|
432
451
|
|
|
433
452
|
def test_operators(self):
|
|
434
453
|
self.assertTrue(JalaliDate(1367, 2, 14) == JalaliDate(date(1988, 5, 4)))
|
|
@@ -481,6 +500,8 @@ class TestJalaliDate(TestCase):
|
|
|
481
500
|
self.assertEqual(JalaliDate(1395, 3, 21) + timedelta(days=-38), JalaliDate(1395, 2, 14))
|
|
482
501
|
self.assertEqual(JalaliDate(1395, 3, 21) - timedelta(days=38), JalaliDate(1395, 2, 14))
|
|
483
502
|
self.assertEqual(JalaliDate(1397, 11, 29) + timedelta(days=2), JalaliDate(1397, 12, 1))
|
|
503
|
+
self.assertEqual(JalaliDate(1403, 12, 29) + timedelta(days=2), JalaliDate(1404, 1, 1))
|
|
504
|
+
self.assertEqual(JalaliDate(1403, 12, 29) + timedelta(days=365), JalaliDate(1404, 12, 28))
|
|
484
505
|
|
|
485
506
|
self.assertEqual(JalaliDate(1395, 3, 21) - JalaliDate(1395, 2, 14), timedelta(days=38))
|
|
486
507
|
self.assertEqual(JalaliDate(1397, 12, 1) - JalaliDate(1397, 11, 29), timedelta(hours=48))
|
|
@@ -492,6 +513,7 @@ class TestJalaliDate(TestCase):
|
|
|
492
513
|
self.assertEqual(JalaliDate(1400, 1, 1) - JalaliDate(1399, 12, 29), timedelta(days=2))
|
|
493
514
|
self.assertEqual(JalaliDate(1403, 1, 1) - JalaliDate(1402, 12, 29), timedelta(days=1))
|
|
494
515
|
self.assertEqual(JalaliDate(1404, 1, 1) - JalaliDate(1403, 12, 29), timedelta(days=2))
|
|
516
|
+
self.assertEqual(JalaliDate(1404, 1, 1) - JalaliDate(1403, 12, 30), timedelta(days=1))
|
|
495
517
|
|
|
496
518
|
def test_pickle(self):
|
|
497
519
|
file = open("save.p", "wb")
|
|
@@ -513,7 +535,7 @@ class TestJalaliDate(TestCase):
|
|
|
513
535
|
|
|
514
536
|
self.assertEqual(
|
|
515
537
|
{j1: "today", j2: "majid1", j3: "majid2"},
|
|
516
|
-
{JalaliDate.today(): "today", JalaliDate(1367, 2, 14): "majid2"},
|
|
538
|
+
{JalaliDate.today(): "today", JalaliDate(date(1988, 5, 4)): "majid1", JalaliDate(1367, 2, 14): "majid2"},
|
|
517
539
|
)
|
|
518
540
|
|
|
519
541
|
def test_invalid_dates(self):
|
|
@@ -537,7 +559,7 @@ class TestJalaliDate(TestCase):
|
|
|
537
559
|
self.assertEqual(str(JalaliDate(1403, 4, 7)), "1403-04-07")
|
|
538
560
|
self.assertEqual(repr(JalaliDate(1403, 4, 7)), "JalaliDate(1403, 4, 7, Panjshanbeh)")
|
|
539
561
|
|
|
540
|
-
def
|
|
562
|
+
def test_strptime(self):
|
|
541
563
|
with self.assertRaises(NotImplementedError):
|
|
542
564
|
JalaliDate.strptime("1400-01-01", "%Y-%m-%d")
|
|
543
565
|
|
|
@@ -546,3 +568,17 @@ class TestJalaliDate(TestCase):
|
|
|
546
568
|
|
|
547
569
|
with pytest.raises(ValueError, match="locale must be 'en' or 'fa'"):
|
|
548
570
|
jdate.locale = "de"
|
|
571
|
+
|
|
572
|
+
def test_setstate(self):
|
|
573
|
+
jdate = JalaliDate(1400, 1, 1)
|
|
574
|
+
state = bytes([5, 87, 2, 14])
|
|
575
|
+
jdate.__setstate__(state)
|
|
576
|
+
|
|
577
|
+
self.assertEqual(jdate.year, 1367)
|
|
578
|
+
self.assertEqual(jdate.month, 2)
|
|
579
|
+
self.assertEqual(jdate.day, 14)
|
|
580
|
+
|
|
581
|
+
jdate = JalaliDate(1400, 1, 1)
|
|
582
|
+
state = bytes([5, 112, 1]) # Invalid length
|
|
583
|
+
with pytest.raises(TypeError, match="not enough arguments"):
|
|
584
|
+
jdate.__setstate__(state)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|