persiantools 3.0.1__tar.gz → 4.0.2__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-3.0.1 → persiantools-4.0.2}/LICENSE +2 -2
- {persiantools-3.0.1/persiantools.egg-info → persiantools-4.0.2}/PKG-INFO +15 -16
- {persiantools-3.0.1 → persiantools-4.0.2}/README.md +10 -12
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools/__init__.py +2 -2
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools/digits.py +12 -6
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools/jdatetime.py +72 -63
- {persiantools-3.0.1 → persiantools-4.0.2/persiantools.egg-info}/PKG-INFO +15 -16
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools.egg-info/SOURCES.txt +7 -1
- persiantools-4.0.2/persiantools.egg-info/requires.txt +1 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/setup.py +5 -4
- persiantools-4.0.2/tests/test_characters.py +35 -0
- persiantools-4.0.2/tests/test_digits.py +64 -0
- persiantools-4.0.2/tests/test_jalalidate.py +331 -0
- persiantools-4.0.2/tests/test_jalalidatetime.py +326 -0
- persiantools-4.0.2/tests/test_utils.py +22 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/MANIFEST.in +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools/characters.py +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools/utils.py +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools.egg-info/dependency_links.txt +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools.egg-info/not-zip-safe +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/persiantools.egg-info/top_level.txt +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/pyproject.toml +0 -0
- {persiantools-3.0.1 → persiantools-4.0.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2016-
|
|
3
|
+
Copyright (c) 2016-2024 Majid Hajiloo
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: persiantools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.2
|
|
4
4
|
Summary: Jalali date and datetime with other tools
|
|
5
5
|
Home-page: https://github.com/majiidd/persiantools
|
|
6
6
|
Author: Majid Hajiloo
|
|
@@ -13,11 +13,11 @@ Classifier: Natural Language :: Persian
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.8
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
22
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
23
|
Classifier: Topic :: Software Development
|
|
@@ -25,9 +25,10 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
25
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
26
|
Classifier: Topic :: Software Development :: Localization
|
|
27
27
|
Classifier: Topic :: Utilities
|
|
28
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
|
+
Requires-Dist: pytz
|
|
31
32
|
|
|
32
33
|
# PersianTools
|
|
33
34
|
|
|
@@ -38,21 +39,19 @@ License-File: LICENSE
|
|
|
38
39
|
[](https://pypi.org/project/persiantools/)
|
|
39
40
|
[](https://pypi.org/project/persiantools/)
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Convert Arabic and Persian characters/digits to each other
|
|
48
|
-
- Convert numbers to words
|
|
42
|
+
Provides Jalali (also known as Shamsi or Persian) dates and datetimes functionalities, among other tools.
|
|
43
|
+
- It converts between Jalali and Gregorian dates and datetimes (based on python datetime's module).
|
|
44
|
+
- It supports operators like `+`, `-`, `==`, and `>=`.
|
|
45
|
+
- It includes timezone support.
|
|
46
|
+
- It converts between Arabic and Persian characters/digits.
|
|
47
|
+
- It turns numbers into Persian words.
|
|
49
48
|
|
|
50
49
|
## Install Package
|
|
51
|
-
|
|
50
|
+
You can install the package using pip with the following command:
|
|
52
51
|
```bash
|
|
53
52
|
python -m pip install persiantools
|
|
54
53
|
```
|
|
55
|
-
Persiantools supports Python 3.
|
|
54
|
+
Persiantools supports Python 3.8+. (_for python 2.7 and 3.5 use [1.5.x](https://github.com/majiidd/persiantools/tree/1.5.x) version_)
|
|
56
55
|
|
|
57
56
|
## How to use
|
|
58
57
|
|
|
@@ -149,7 +148,7 @@ Based on python `strftime()` behavior
|
|
|
149
148
|
```
|
|
150
149
|
|
|
151
150
|
### Operators
|
|
152
|
-
|
|
151
|
+
The package supports various operators for date and time manipulations. Here are some examples:
|
|
153
152
|
```python
|
|
154
153
|
>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime
|
|
155
154
|
>>> import datetime
|
|
@@ -157,7 +156,7 @@ Based on python `strftime()` behavior
|
|
|
157
156
|
>>> JalaliDate(1367, 2, 14) == JalaliDate(datetime.date(1988, 5, 4))
|
|
158
157
|
True
|
|
159
158
|
|
|
160
|
-
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(
|
|
159
|
+
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(1368, 2, 14, 1, 0)
|
|
161
160
|
False
|
|
162
161
|
|
|
163
162
|
>>> JalaliDate(1367, 2, 14) == datetime.date(1988, 5, 4)
|
|
@@ -7,21 +7,19 @@
|
|
|
7
7
|
[](https://pypi.org/project/persiantools/)
|
|
8
8
|
[](https://pypi.org/project/persiantools/)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- Convert Arabic and Persian characters/digits to each other
|
|
17
|
-
- Convert numbers to words
|
|
10
|
+
Provides Jalali (also known as Shamsi or Persian) dates and datetimes functionalities, among other tools.
|
|
11
|
+
- It converts between Jalali and Gregorian dates and datetimes (based on python datetime's module).
|
|
12
|
+
- It supports operators like `+`, `-`, `==`, and `>=`.
|
|
13
|
+
- It includes timezone support.
|
|
14
|
+
- It converts between Arabic and Persian characters/digits.
|
|
15
|
+
- It turns numbers into Persian words.
|
|
18
16
|
|
|
19
17
|
## Install Package
|
|
20
|
-
|
|
18
|
+
You can install the package using pip with the following command:
|
|
21
19
|
```bash
|
|
22
20
|
python -m pip install persiantools
|
|
23
21
|
```
|
|
24
|
-
Persiantools supports Python 3.
|
|
22
|
+
Persiantools supports Python 3.8+. (_for python 2.7 and 3.5 use [1.5.x](https://github.com/majiidd/persiantools/tree/1.5.x) version_)
|
|
25
23
|
|
|
26
24
|
## How to use
|
|
27
25
|
|
|
@@ -118,7 +116,7 @@ Based on python `strftime()` behavior
|
|
|
118
116
|
```
|
|
119
117
|
|
|
120
118
|
### Operators
|
|
121
|
-
|
|
119
|
+
The package supports various operators for date and time manipulations. Here are some examples:
|
|
122
120
|
```python
|
|
123
121
|
>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime
|
|
124
122
|
>>> import datetime
|
|
@@ -126,7 +124,7 @@ Based on python `strftime()` behavior
|
|
|
126
124
|
>>> JalaliDate(1367, 2, 14) == JalaliDate(datetime.date(1988, 5, 4))
|
|
127
125
|
True
|
|
128
126
|
|
|
129
|
-
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(
|
|
127
|
+
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(1368, 2, 14, 1, 0)
|
|
130
128
|
False
|
|
131
129
|
|
|
132
130
|
>>> JalaliDate(1367, 2, 14) == datetime.date(1988, 5, 4)
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
__title__ = "persiantools"
|
|
9
9
|
__url__ = "https://github.com/majiidd/persiantools"
|
|
10
|
-
__version__ = "
|
|
10
|
+
__version__ = "4.0.2"
|
|
11
11
|
__build__ = __version__
|
|
12
12
|
__author__ = "Majid Hajiloo"
|
|
13
13
|
__author_email__ = "majid.hajiloo@gmail.com"
|
|
14
14
|
__license__ = "MIT"
|
|
15
|
-
__copyright__ = "Copyright (c) 2016-
|
|
15
|
+
__copyright__ = "Copyright (c) 2016-2024 Majid Hajiloo"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import re
|
|
2
2
|
|
|
3
3
|
EN_TO_FA_MAP = {
|
|
4
4
|
"0": "۰",
|
|
@@ -48,6 +48,12 @@ FA_TO_AR_MAP = {
|
|
|
48
48
|
"۸": "٨",
|
|
49
49
|
"۹": "٩",
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
EN_TO_FA_REGEX = re.compile("|".join(EN_TO_FA_MAP.keys()))
|
|
53
|
+
AR_TO_FA_REGEX = re.compile("|".join(AR_TO_FA_MAP.keys()))
|
|
54
|
+
FA_TO_EN_REGEX = re.compile("|".join(FA_TO_EN_MAP.keys()))
|
|
55
|
+
FA_TO_AR_REGEX = re.compile("|".join(FA_TO_AR_MAP.keys()))
|
|
56
|
+
|
|
51
57
|
ONES = ("یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه")
|
|
52
58
|
TENS = ("بیست", "سی", "چهل", "پنجاه", "شصت", "هفتاد", "هشتاد", "نود")
|
|
53
59
|
HUNDREDS = ("یکصد", "دویست", "سیصد", "چهارصد", "پانصد", "ششصد", "هفتصد", "هشتصد", "نهصد")
|
|
@@ -80,7 +86,7 @@ DECISION = {
|
|
|
80
86
|
1000: lambda n, depth: HUNDREDS[n // 100 - 1] + _to_word(n % 100, True),
|
|
81
87
|
1000000: lambda n, depth: _to_word(n // 1000, depth) + BIG_RANGE[0] + _to_word(n % 1000, True),
|
|
82
88
|
1000000000: lambda n, depth: _to_word(n // 1000000, depth) + BIG_RANGE[1] + _to_word(n % 1000000, True),
|
|
83
|
-
1000000000000: lambda n, depth: _to_word(n //
|
|
89
|
+
1000000000000: lambda n, depth: _to_word(n // 1000000000, depth) + BIG_RANGE[2] + _to_word(n % 1000000000, True),
|
|
84
90
|
1000000000000000: lambda n, depth: _to_word(n // 1000000000000, depth)
|
|
85
91
|
+ BIG_RANGE[3]
|
|
86
92
|
+ _to_word(n % 1000000000000, True),
|
|
@@ -101,7 +107,7 @@ def en_to_fa(string: str) -> str:
|
|
|
101
107
|
:param string: A string, will be converted
|
|
102
108
|
:rtype: str
|
|
103
109
|
"""
|
|
104
|
-
return
|
|
110
|
+
return EN_TO_FA_REGEX.sub(lambda x: EN_TO_FA_MAP[x.group()], string)
|
|
105
111
|
|
|
106
112
|
|
|
107
113
|
def ar_to_fa(string: str) -> str:
|
|
@@ -114,7 +120,7 @@ def ar_to_fa(string: str) -> str:
|
|
|
114
120
|
:param string: A string, will be converted
|
|
115
121
|
:rtype: str
|
|
116
122
|
"""
|
|
117
|
-
return
|
|
123
|
+
return AR_TO_FA_REGEX.sub(lambda x: AR_TO_FA_MAP[x.group()], string)
|
|
118
124
|
|
|
119
125
|
|
|
120
126
|
def fa_to_en(string: str) -> str:
|
|
@@ -127,7 +133,7 @@ def fa_to_en(string: str) -> str:
|
|
|
127
133
|
:param string: A string, will be converted
|
|
128
134
|
:rtype: str
|
|
129
135
|
"""
|
|
130
|
-
return
|
|
136
|
+
return FA_TO_EN_REGEX.sub(lambda x: FA_TO_EN_MAP[x.group()], string)
|
|
131
137
|
|
|
132
138
|
|
|
133
139
|
def fa_to_ar(string: str) -> str:
|
|
@@ -140,7 +146,7 @@ def fa_to_ar(string: str) -> str:
|
|
|
140
146
|
:param string: A string, will be converted
|
|
141
147
|
:rtype: str
|
|
142
148
|
"""
|
|
143
|
-
return
|
|
149
|
+
return FA_TO_AR_REGEX.sub(lambda x: FA_TO_AR_MAP[x.group()], string)
|
|
144
150
|
|
|
145
151
|
|
|
146
152
|
def _to_word(number: int, depth: bool) -> str:
|
|
@@ -181,7 +181,7 @@ class JalaliDate:
|
|
|
181
181
|
return year, month, day, locale
|
|
182
182
|
|
|
183
183
|
@classmethod
|
|
184
|
-
def
|
|
184
|
+
def check_date(cls, year, month, day):
|
|
185
185
|
try:
|
|
186
186
|
cls._check_date_fields(year, month, day, "en")
|
|
187
187
|
except (ValueError, TypeError):
|
|
@@ -191,11 +191,19 @@ class JalaliDate:
|
|
|
191
191
|
|
|
192
192
|
@staticmethod
|
|
193
193
|
def is_leap(year):
|
|
194
|
-
|
|
194
|
+
"""
|
|
195
|
+
This function calculates whether a given year in the Persian calendar is a leap year.
|
|
195
196
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
It calculates `((year + 2346) * 683) % 2820`. This expression does a few things:
|
|
198
|
+
- It offsets the input year by 2346. This is done to align the Persian calendar with the astronomical solar year.
|
|
199
|
+
- It multiplies the result by 683, which is the number of leap years in a 2820-year cycle.
|
|
200
|
+
- It then takes the result modulo 2820 to get the position of the year within the current 2820-year cycle.
|
|
201
|
+
|
|
202
|
+
If the result of this calculation is less than 683, the year is a leap year in the Persian calendar.
|
|
203
|
+
This is because there are 683 leap years in each 2820-year cycle of the Persian calendar.
|
|
204
|
+
"""
|
|
205
|
+
assert MINYEAR <= year <= MAXYEAR
|
|
206
|
+
return ((year + 2346) * 683) % 2820 < 683
|
|
199
207
|
|
|
200
208
|
@classmethod
|
|
201
209
|
def days_in_month(cls, month, year):
|
|
@@ -220,88 +228,91 @@ class JalaliDate:
|
|
|
220
228
|
day = year.day
|
|
221
229
|
year = year.year
|
|
222
230
|
|
|
223
|
-
|
|
231
|
+
# Days in each month of the Gregorian calendar
|
|
232
|
+
gregorian_days_in_month = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
|
|
224
233
|
|
|
225
|
-
|
|
234
|
+
# Determine the Jalali year
|
|
235
|
+
jalali_year = 0 if year <= 1600 else 979
|
|
226
236
|
year -= 621 if year <= 1600 else 1600
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
237
|
+
|
|
238
|
+
# Determine if the year is a leap year
|
|
239
|
+
leap_year = year + 1 if month > 2 else year
|
|
240
|
+
|
|
241
|
+
# Calculate the number of days
|
|
242
|
+
days = (365 * year) + (leap_year + 3) // 4 - (leap_year + 99) // 100
|
|
243
|
+
days += (leap_year + 399) // 400 - 80 + day + gregorian_days_in_month[month - 1]
|
|
244
|
+
|
|
245
|
+
# Update the Jalali year
|
|
246
|
+
jalali_year += 33 * (days // 12053)
|
|
231
247
|
days %= 12053
|
|
232
|
-
|
|
248
|
+
jalali_year += 4 * (days // 1461)
|
|
233
249
|
days %= 1461
|
|
234
|
-
|
|
250
|
+
jalali_year += (days - 1) // 365
|
|
235
251
|
|
|
236
252
|
if days > 365:
|
|
237
253
|
days = (days - 1) % 365
|
|
238
254
|
|
|
255
|
+
# Determine the Jalali month and day
|
|
239
256
|
if days < 186:
|
|
240
|
-
|
|
241
|
-
|
|
257
|
+
jalali_month = 1 + days // 31
|
|
258
|
+
jalali_day = 1 + (days % 31)
|
|
242
259
|
else:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
260
|
+
days -= 186
|
|
261
|
+
jalali_month = 7 + days // 30
|
|
262
|
+
jalali_day = 1 + (days % 30)
|
|
246
263
|
|
|
247
|
-
return cls(
|
|
264
|
+
return cls(jalali_year, jalali_month, jalali_day)
|
|
248
265
|
|
|
249
266
|
def to_gregorian(self):
|
|
250
267
|
"""based on jdf.scr.ir"""
|
|
268
|
+
year = self.year + 1595
|
|
251
269
|
month = self.month
|
|
252
270
|
day = self.day
|
|
253
|
-
year = self.year
|
|
254
271
|
|
|
255
|
-
|
|
256
|
-
year
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
272
|
+
# Calculate the total number of days
|
|
273
|
+
days = -355668 + (365 * year) + ((year // 33) * 8) + (((year % 33) + 3) // 4) + day
|
|
274
|
+
if month < 7:
|
|
275
|
+
days += (month - 1) * 31
|
|
276
|
+
else:
|
|
277
|
+
days += ((month - 7) * 30) + 186
|
|
261
278
|
|
|
262
|
-
|
|
279
|
+
# Determine the Gregorian year
|
|
280
|
+
gregorian_year = 400 * (days // 146097)
|
|
263
281
|
days %= 146097
|
|
264
282
|
|
|
265
283
|
if days > 36524:
|
|
266
284
|
days -= 1
|
|
267
|
-
|
|
285
|
+
gregorian_year += 100 * (days // 36524)
|
|
268
286
|
days %= 36524
|
|
269
|
-
|
|
270
287
|
if days >= 365:
|
|
271
288
|
days += 1
|
|
272
289
|
|
|
273
|
-
|
|
290
|
+
gregorian_year += 4 * (days // 1461)
|
|
274
291
|
days %= 1461
|
|
275
|
-
gy += int((days - 1) / 365)
|
|
276
|
-
|
|
277
292
|
if days > 365:
|
|
293
|
+
gregorian_year += (days - 1) // 365
|
|
278
294
|
days = (days - 1) % 365
|
|
279
295
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
31,
|
|
291
|
-
31,
|
|
292
|
-
30,
|
|
293
|
-
31,
|
|
294
|
-
30,
|
|
295
|
-
31,
|
|
296
|
-
]
|
|
296
|
+
gregorian_day = days + 1
|
|
297
|
+
|
|
298
|
+
# Handle leap years for February day count adjustment
|
|
299
|
+
if (gregorian_year % 4 == 0 and gregorian_year % 100 != 0) or (gregorian_year % 400 == 0):
|
|
300
|
+
feb_days = 29
|
|
301
|
+
else:
|
|
302
|
+
feb_days = 28
|
|
303
|
+
|
|
304
|
+
# Days in each month of the Gregorian calendar
|
|
305
|
+
gregorian_days_in_month = [0, 31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
297
306
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
307
|
+
# Determine the Gregorian month
|
|
308
|
+
gregorian_month = 1
|
|
309
|
+
for days_in_month in gregorian_days_in_month[1:]:
|
|
310
|
+
if gregorian_day <= days_in_month:
|
|
301
311
|
break
|
|
302
|
-
|
|
312
|
+
gregorian_day -= days_in_month
|
|
313
|
+
gregorian_month += 1
|
|
303
314
|
|
|
304
|
-
return date(
|
|
315
|
+
return date(gregorian_year, gregorian_month, gregorian_day)
|
|
305
316
|
|
|
306
317
|
@classmethod
|
|
307
318
|
def today(cls):
|
|
@@ -958,7 +969,7 @@ class JalaliDateTime(JalaliDate):
|
|
|
958
969
|
"%B": cls.__seqToRE(cls, month_names, "B"),
|
|
959
970
|
"%H": r"(?P<H>2[0-3]|[0-1]\d|\d)",
|
|
960
971
|
"%I": r"(?P<I>1[0-2]|0[1-9]|[1-9])",
|
|
961
|
-
"%p":
|
|
972
|
+
"%p": cls.__seqToRE(cls, periods, "p"),
|
|
962
973
|
"%M": r"(?P<M>[0-5]\d|\d)",
|
|
963
974
|
"%S": r"(?P<S>6[0-1]|[0-5]\d|\d)",
|
|
964
975
|
"%f": r"(?P<f>\d{1,6})",
|
|
@@ -977,8 +988,8 @@ class JalaliDateTime(JalaliDate):
|
|
|
977
988
|
|
|
978
989
|
data_string_regex = utils.replace(fmt, directives_regex_pattern)
|
|
979
990
|
|
|
980
|
-
if re.match(data_string_regex, data_string):
|
|
981
|
-
directives = re.search(data_string_regex, data_string).groupdict()
|
|
991
|
+
if re.match(data_string_regex, data_string, re.IGNORECASE):
|
|
992
|
+
directives = re.search(data_string_regex, data_string, re.IGNORECASE).groupdict()
|
|
982
993
|
|
|
983
994
|
if "Y" in directives.keys() and len(directives.get("Y")) < 4:
|
|
984
995
|
raise ValueError("Year element must contain exactly 4 digits")
|
|
@@ -1100,7 +1111,7 @@ class JalaliDateTime(JalaliDate):
|
|
|
1100
1111
|
def __base_compare(self, other):
|
|
1101
1112
|
assert isinstance(other, JalaliDateTime)
|
|
1102
1113
|
|
|
1103
|
-
y,
|
|
1114
|
+
y, mo, d, h, m, s, ms = [
|
|
1104
1115
|
self._year,
|
|
1105
1116
|
self._month,
|
|
1106
1117
|
self._day,
|
|
@@ -1109,7 +1120,7 @@ class JalaliDateTime(JalaliDate):
|
|
|
1109
1120
|
self._second,
|
|
1110
1121
|
self._microsecond,
|
|
1111
1122
|
]
|
|
1112
|
-
y2,
|
|
1123
|
+
y2, mo2, d2, h2, m2, s2, ms2 = [
|
|
1113
1124
|
other.year,
|
|
1114
1125
|
other.month,
|
|
1115
1126
|
other.day,
|
|
@@ -1121,10 +1132,8 @@ class JalaliDateTime(JalaliDate):
|
|
|
1121
1132
|
|
|
1122
1133
|
return (
|
|
1123
1134
|
0
|
|
1124
|
-
if (y,
|
|
1125
|
-
else 1
|
|
1126
|
-
if (y, m, d, h, m, s, ms) > (y2, m2, d2, h2, m2, s2, ms2)
|
|
1127
|
-
else -1
|
|
1135
|
+
if (y, mo, d, h, m, s, ms) == (y2, mo2, d2, h2, m2, s2, ms2)
|
|
1136
|
+
else 1 if (y, mo, d, h, m, s, ms) > (y2, mo2, d2, h2, m2, s2, ms2) else -1
|
|
1128
1137
|
)
|
|
1129
1138
|
|
|
1130
1139
|
def _cmp(self, other, allow_mixed=False):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: persiantools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.2
|
|
4
4
|
Summary: Jalali date and datetime with other tools
|
|
5
5
|
Home-page: https://github.com/majiidd/persiantools
|
|
6
6
|
Author: Majid Hajiloo
|
|
@@ -13,11 +13,11 @@ Classifier: Natural Language :: Persian
|
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.8
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
22
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
23
|
Classifier: Topic :: Software Development
|
|
@@ -25,9 +25,10 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
25
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
26
|
Classifier: Topic :: Software Development :: Localization
|
|
27
27
|
Classifier: Topic :: Utilities
|
|
28
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
|
+
Requires-Dist: pytz
|
|
31
32
|
|
|
32
33
|
# PersianTools
|
|
33
34
|
|
|
@@ -38,21 +39,19 @@ License-File: LICENSE
|
|
|
38
39
|
[](https://pypi.org/project/persiantools/)
|
|
39
40
|
[](https://pypi.org/project/persiantools/)
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Convert Arabic and Persian characters/digits to each other
|
|
48
|
-
- Convert numbers to words
|
|
42
|
+
Provides Jalali (also known as Shamsi or Persian) dates and datetimes functionalities, among other tools.
|
|
43
|
+
- It converts between Jalali and Gregorian dates and datetimes (based on python datetime's module).
|
|
44
|
+
- It supports operators like `+`, `-`, `==`, and `>=`.
|
|
45
|
+
- It includes timezone support.
|
|
46
|
+
- It converts between Arabic and Persian characters/digits.
|
|
47
|
+
- It turns numbers into Persian words.
|
|
49
48
|
|
|
50
49
|
## Install Package
|
|
51
|
-
|
|
50
|
+
You can install the package using pip with the following command:
|
|
52
51
|
```bash
|
|
53
52
|
python -m pip install persiantools
|
|
54
53
|
```
|
|
55
|
-
Persiantools supports Python 3.
|
|
54
|
+
Persiantools supports Python 3.8+. (_for python 2.7 and 3.5 use [1.5.x](https://github.com/majiidd/persiantools/tree/1.5.x) version_)
|
|
56
55
|
|
|
57
56
|
## How to use
|
|
58
57
|
|
|
@@ -149,7 +148,7 @@ Based on python `strftime()` behavior
|
|
|
149
148
|
```
|
|
150
149
|
|
|
151
150
|
### Operators
|
|
152
|
-
|
|
151
|
+
The package supports various operators for date and time manipulations. Here are some examples:
|
|
153
152
|
```python
|
|
154
153
|
>>> from persiantools.jdatetime import JalaliDate, JalaliDateTime
|
|
155
154
|
>>> import datetime
|
|
@@ -157,7 +156,7 @@ Based on python `strftime()` behavior
|
|
|
157
156
|
>>> JalaliDate(1367, 2, 14) == JalaliDate(datetime.date(1988, 5, 4))
|
|
158
157
|
True
|
|
159
158
|
|
|
160
|
-
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(
|
|
159
|
+
>>> JalaliDateTime(1367, 2, 14, 4, 30) >= JalaliDateTime(1368, 2, 14, 1, 0)
|
|
161
160
|
False
|
|
162
161
|
|
|
163
162
|
>>> JalaliDate(1367, 2, 14) == datetime.date(1988, 5, 4)
|
|
@@ -12,4 +12,10 @@ persiantools.egg-info/PKG-INFO
|
|
|
12
12
|
persiantools.egg-info/SOURCES.txt
|
|
13
13
|
persiantools.egg-info/dependency_links.txt
|
|
14
14
|
persiantools.egg-info/not-zip-safe
|
|
15
|
-
persiantools.egg-info/
|
|
15
|
+
persiantools.egg-info/requires.txt
|
|
16
|
+
persiantools.egg-info/top_level.txt
|
|
17
|
+
tests/test_characters.py
|
|
18
|
+
tests/test_digits.py
|
|
19
|
+
tests/test_jalalidate.py
|
|
20
|
+
tests/test_jalalidatetime.py
|
|
21
|
+
tests/test_utils.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pytz
|
|
@@ -23,11 +23,11 @@ setup(
|
|
|
23
23
|
"Operating System :: OS Independent",
|
|
24
24
|
"Programming Language :: Python",
|
|
25
25
|
"Programming Language :: Python :: 3",
|
|
26
|
-
"Programming Language :: Python :: 3.6",
|
|
27
|
-
"Programming Language :: Python :: 3.7",
|
|
28
26
|
"Programming Language :: Python :: 3.8",
|
|
29
27
|
"Programming Language :: Python :: 3.9",
|
|
30
28
|
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
31
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
32
32
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
33
33
|
"Topic :: Software Development",
|
|
@@ -42,10 +42,11 @@ setup(
|
|
|
42
42
|
author="Majid Hajiloo",
|
|
43
43
|
author_email="majid.hajiloo@gmail.com",
|
|
44
44
|
license="MIT",
|
|
45
|
+
license_files=("LICENSE",),
|
|
45
46
|
packages=["persiantools"],
|
|
46
|
-
python_requires=">=3.
|
|
47
|
+
python_requires=">=3.8",
|
|
47
48
|
tests_require=["pytest", "pytest-cov"],
|
|
48
|
-
install_requires=[],
|
|
49
|
+
install_requires=["pytz"],
|
|
49
50
|
include_package_data=True,
|
|
50
51
|
zip_safe=False,
|
|
51
52
|
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from persiantools import characters, digits
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestDigits(TestCase):
|
|
9
|
+
def test_ar_to_fa(self):
|
|
10
|
+
self.assertEqual(characters.ar_to_fa("السلام عليكم"), "السلام علیکم")
|
|
11
|
+
self.assertEqual(characters.ar_to_fa("HI ي"), "HI ی")
|
|
12
|
+
self.assertEqual(characters.ar_to_fa("دِ بِ زِ ذِ شِ سِ ى ي ك"), "د ب ز ذ ش س ی ی ک")
|
|
13
|
+
self.assertEqual(characters.ar_to_fa("دِ بِ زِ ذِ شِ سِ ى ي ك"), "د ب ز ذ ش س ی ی ک")
|
|
14
|
+
self.assertEqual(
|
|
15
|
+
characters.ar_to_fa("ظ ط ذ د ز ر و ، . ش س ي ب ل ا ت ن م ك ض ص ث ق ف غ ع ه خ ح ؟"),
|
|
16
|
+
"ظ ط ذ د ز ر و ، . ش س ی ب ل ا ت ن م ک ض ص ث ق ف غ ع ه خ ح ؟",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
with pytest.raises(TypeError):
|
|
20
|
+
characters.ar_to_fa(12345)
|
|
21
|
+
|
|
22
|
+
orig = "السلام عليكم ٠١٢٣٤٥٦٧٨٩"
|
|
23
|
+
converted = characters.ar_to_fa(orig)
|
|
24
|
+
converted = digits.ar_to_fa(converted)
|
|
25
|
+
self.assertEqual(converted, "السلام علیکم ۰۱۲۳۴۵۶۷۸۹")
|
|
26
|
+
|
|
27
|
+
def test_fa_to_fa(self):
|
|
28
|
+
self.assertEqual(characters.ar_to_fa("السلام علیکم"), "السلام علیکم")
|
|
29
|
+
self.assertEqual(characters.ar_to_fa("السلام علیکم"), "السلام علیکم")
|
|
30
|
+
|
|
31
|
+
def test_fa_to_ar(self):
|
|
32
|
+
self.assertEqual(characters.fa_to_ar("کیک"), "كيك")
|
|
33
|
+
|
|
34
|
+
with pytest.raises(TypeError):
|
|
35
|
+
characters.ar_to_fa(12345)
|