persiantools 5.3.0__tar.gz → 5.5.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.
Files changed (25) hide show
  1. {persiantools-5.3.0/persiantools.egg-info → persiantools-5.5.0}/PKG-INFO +23 -30
  2. {persiantools-5.3.0 → persiantools-5.5.0}/README.md +14 -12
  3. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools/__init__.py +1 -1
  4. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools/jdatetime.py +41 -9
  5. {persiantools-5.3.0 → persiantools-5.5.0/persiantools.egg-info}/PKG-INFO +23 -30
  6. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools.egg-info/SOURCES.txt +0 -2
  7. persiantools-5.5.0/persiantools.egg-info/requires.txt +3 -0
  8. persiantools-5.5.0/pyproject.toml +104 -0
  9. {persiantools-5.3.0 → persiantools-5.5.0}/tests/test_jalalidate.py +1 -0
  10. {persiantools-5.3.0 → persiantools-5.5.0}/tests/test_jalalidatetime.py +50 -27
  11. persiantools-5.3.0/persiantools.egg-info/not-zip-safe +0 -1
  12. persiantools-5.3.0/persiantools.egg-info/requires.txt +0 -1
  13. persiantools-5.3.0/pyproject.toml +0 -27
  14. persiantools-5.3.0/setup.py +0 -51
  15. {persiantools-5.3.0 → persiantools-5.5.0}/LICENSE +0 -0
  16. {persiantools-5.3.0 → persiantools-5.5.0}/MANIFEST.in +0 -0
  17. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools/characters.py +0 -0
  18. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools/digits.py +0 -0
  19. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools/utils.py +0 -0
  20. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools.egg-info/dependency_links.txt +0 -0
  21. {persiantools-5.3.0 → persiantools-5.5.0}/persiantools.egg-info/top_level.txt +0 -0
  22. {persiantools-5.3.0 → persiantools-5.5.0}/setup.cfg +0 -0
  23. {persiantools-5.3.0 → persiantools-5.5.0}/tests/test_characters.py +0 -0
  24. {persiantools-5.3.0 → persiantools-5.5.0}/tests/test_digits.py +0 -0
  25. {persiantools-5.3.0 → persiantools-5.5.0}/tests/test_utils.py +0 -0
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: persiantools
3
- Version: 5.3.0
3
+ Version: 5.5.0
4
4
  Summary: Jalali date and datetime with other tools
5
- Home-page: https://github.com/majiidd/persiantools
6
- Author: Majid Hajiloo
7
- Author-email: majid.hajiloo@gmail.com
8
- License: MIT
9
- Keywords: jalali shamsi persian digits characters converter jalalidate jalalidatetime date datetime jdate jdatetime farsi
5
+ Author-email: Majid Hajiloo <majid.hajiloo@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/majiidd/persiantools
8
+ Project-URL: Source, https://github.com/majiidd/persiantools
9
+ Project-URL: Issues, https://github.com/majiidd/persiantools/issues
10
+ Keywords: jalali,shamsi,persian,digits,characters,converter,jalalidate,jalalidatetime,date,datetime,jdate,jdatetime,farsi
10
11
  Classifier: Intended Audience :: Developers
11
12
  Classifier: Natural Language :: Persian
12
13
  Classifier: Operating System :: OS Independent
@@ -17,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
17
18
  Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
20
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
21
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
22
24
  Classifier: Topic :: Software Development
@@ -27,19 +29,8 @@ Classifier: Topic :: Utilities
27
29
  Requires-Python: >=3.9
28
30
  Description-Content-Type: text/markdown
29
31
  License-File: LICENSE
30
- Requires-Dist: pytz
31
- Dynamic: author
32
- Dynamic: author-email
33
- Dynamic: classifier
34
- Dynamic: description
35
- Dynamic: description-content-type
36
- Dynamic: home-page
37
- Dynamic: keywords
38
- Dynamic: license
32
+ Requires-Dist: tzdata; platform_system == "Windows"
39
33
  Dynamic: license-file
40
- Dynamic: requires-dist
41
- Dynamic: requires-python
42
- Dynamic: summary
43
34
 
44
35
  # PersianTools
45
36
 
@@ -147,15 +138,15 @@ The `JalaliDateTime` object represents a date and time in the Jalali calendar.
147
138
 
148
139
  ```python
149
140
  >>> from persiantools.jdatetime import JalaliDateTime
150
- >>> import datetime, pytz
141
+ >>> import datetime
151
142
 
152
143
  # Current Jalali datetime
153
144
  >>> JalaliDateTime.now()
154
145
  JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909)
155
146
 
156
- # Current Jalali datetime (timezone-aware)
157
- >>> JalaliDateTime.now(pytz.timezone("Asia/Tehran"))
158
- JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
147
+ >>> from zoneinfo import ZoneInfo
148
+ >>> JalaliDateTime.now(ZoneInfo("Asia/Tehran"))
149
+ JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
159
150
 
160
151
  # Current UTC Jalali datetime
161
152
  >>> JalaliDateTime.utcnow()
@@ -175,20 +166,21 @@ JalaliDateTime(1367, 2, 14, 14, 30, 15)
175
166
  JalaliDateTime(1400, 1, 1, 15, 30, 0, 10)
176
167
 
177
168
  # Timezone conversion
178
- >>> tehran_tz = pytz.timezone("Asia/Tehran")
179
- >>> utc_tz = pytz.utc
169
+ >>> from zoneinfo import ZoneInfo
170
+ >>> tehran_tz = ZoneInfo("Asia/Tehran")
171
+ >>> utc_tz = datetime.timezone.utc
180
172
  >>> dt_utc = JalaliDateTime.now(utc_tz)
181
173
  >>> dt_tehran = dt_utc.astimezone(tehran_tz)
182
174
  >>> dt_utc
183
- JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=<UTC>)
175
+ JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=datetime.timezone.utc)
184
176
  >>> dt_tehran
185
- JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
177
+ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
186
178
  ```
187
179
 
188
180
  #### Attributes and Methods
189
181
 
190
182
  ```python
191
- >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=pytz.utc)
183
+ >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=datetime.timezone.utc)
192
184
 
193
185
  >>> dt_obj.year
194
186
  1367
@@ -205,7 +197,7 @@ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0
205
197
  >>> dt_obj.microsecond
206
198
  123
207
199
  >>> dt_obj.tzinfo
208
- <UTC>
200
+ datetime.timezone.utc
209
201
 
210
202
  # Date part as datetime.date (Gregorian)
211
203
  >>> dt_obj.date()
@@ -226,9 +218,9 @@ Based on python `strftime()` behavior
226
218
 
227
219
  ```python
228
220
  >>> from persiantools.jdatetime import JalaliDateTime
229
- >>> import pytz
221
+ >>> from zoneinfo import ZoneInfo
230
222
 
231
- >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=pytz.timezone("Asia/Tehran"))
223
+ >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=ZoneInfo("Asia/Tehran"))
232
224
 
233
225
  >>> dt.strftime("%Y/%m/%d %H:%M:%S")
234
226
  '1367/02/14 14:30:00'
@@ -345,6 +337,7 @@ JalaliDate(1367, 2, 14, Chaharshanbeh)
345
337
  If you find this project helpful and would like to support its continued development, please consider donating.
346
338
 
347
339
  * **Bitcoin (BTC):** `bc1qg5rp7ymznc98wmhltzvpwl2dvfuvjr33m4hy77`
340
+ * **Ethereum (ETH):** `0xC7D6bf306E456632764D0aD111C8dBBb43a3B9ad`
348
341
  * **Tron (TRX):** `TDd63bVWZDBHmwVNFgJ6T2WdWmk9z7PBLg`
349
342
  * **Stellar (XLM):** `GDSFPPLY34QSAOTOP4DQDXAI2YDRNRIADZHTN3HCGMQXRLIGPYOEH7L5`
350
343
  * **Solana (SOL):** `CXHKgCBqBYy1hbZKGqaSmMzQoTC4Wx2v8QfL9Z7JBo3A`
@@ -104,15 +104,15 @@ The `JalaliDateTime` object represents a date and time in the Jalali calendar.
104
104
 
105
105
  ```python
106
106
  >>> from persiantools.jdatetime import JalaliDateTime
107
- >>> import datetime, pytz
107
+ >>> import datetime
108
108
 
109
109
  # Current Jalali datetime
110
110
  >>> JalaliDateTime.now()
111
111
  JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909)
112
112
 
113
- # Current Jalali datetime (timezone-aware)
114
- >>> JalaliDateTime.now(pytz.timezone("Asia/Tehran"))
115
- JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
113
+ >>> from zoneinfo import ZoneInfo
114
+ >>> JalaliDateTime.now(ZoneInfo("Asia/Tehran"))
115
+ JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
116
116
 
117
117
  # Current UTC Jalali datetime
118
118
  >>> JalaliDateTime.utcnow()
@@ -132,20 +132,21 @@ JalaliDateTime(1367, 2, 14, 14, 30, 15)
132
132
  JalaliDateTime(1400, 1, 1, 15, 30, 0, 10)
133
133
 
134
134
  # Timezone conversion
135
- >>> tehran_tz = pytz.timezone("Asia/Tehran")
136
- >>> utc_tz = pytz.utc
135
+ >>> from zoneinfo import ZoneInfo
136
+ >>> tehran_tz = ZoneInfo("Asia/Tehran")
137
+ >>> utc_tz = datetime.timezone.utc
137
138
  >>> dt_utc = JalaliDateTime.now(utc_tz)
138
139
  >>> dt_tehran = dt_utc.astimezone(tehran_tz)
139
140
  >>> dt_utc
140
- JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=<UTC>)
141
+ JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=datetime.timezone.utc)
141
142
  >>> dt_tehran
142
- JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
143
+ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
143
144
  ```
144
145
 
145
146
  #### Attributes and Methods
146
147
 
147
148
  ```python
148
- >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=pytz.utc)
149
+ >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=datetime.timezone.utc)
149
150
 
150
151
  >>> dt_obj.year
151
152
  1367
@@ -162,7 +163,7 @@ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0
162
163
  >>> dt_obj.microsecond
163
164
  123
164
165
  >>> dt_obj.tzinfo
165
- <UTC>
166
+ datetime.timezone.utc
166
167
 
167
168
  # Date part as datetime.date (Gregorian)
168
169
  >>> dt_obj.date()
@@ -183,9 +184,9 @@ Based on python `strftime()` behavior
183
184
 
184
185
  ```python
185
186
  >>> from persiantools.jdatetime import JalaliDateTime
186
- >>> import pytz
187
+ >>> from zoneinfo import ZoneInfo
187
188
 
188
- >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=pytz.timezone("Asia/Tehran"))
189
+ >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=ZoneInfo("Asia/Tehran"))
189
190
 
190
191
  >>> dt.strftime("%Y/%m/%d %H:%M:%S")
191
192
  '1367/02/14 14:30:00'
@@ -302,6 +303,7 @@ JalaliDate(1367, 2, 14, Chaharshanbeh)
302
303
  If you find this project helpful and would like to support its continued development, please consider donating.
303
304
 
304
305
  * **Bitcoin (BTC):** `bc1qg5rp7ymznc98wmhltzvpwl2dvfuvjr33m4hy77`
306
+ * **Ethereum (ETH):** `0xC7D6bf306E456632764D0aD111C8dBBb43a3B9ad`
305
307
  * **Tron (TRX):** `TDd63bVWZDBHmwVNFgJ6T2WdWmk9z7PBLg`
306
308
  * **Stellar (XLM):** `GDSFPPLY34QSAOTOP4DQDXAI2YDRNRIADZHTN3HCGMQXRLIGPYOEH7L5`
307
309
  * **Solana (SOL):** `CXHKgCBqBYy1hbZKGqaSmMzQoTC4Wx2v8QfL9Z7JBo3A`
@@ -7,7 +7,7 @@
7
7
 
8
8
  __title__ = "persiantools"
9
9
  __url__ = "https://github.com/majiidd/persiantools"
10
- __version__ = "5.3.0"
10
+ __version__ = "5.5.0"
11
11
  __build__ = __version__
12
12
  __author__ = "Majid Hajiloo"
13
13
  __author_email__ = "majid.hajiloo@gmail.com"
@@ -5,8 +5,7 @@ from datetime import datetime as dt
5
5
  from datetime import time as _time
6
6
  from datetime import timedelta, timezone, tzinfo
7
7
  from re import escape as re_escape
8
-
9
- import pytz
8
+ from zoneinfo import ZoneInfo
10
9
 
11
10
  from persiantools import digits, utils
12
11
 
@@ -1567,28 +1566,58 @@ class JalaliDateTime(JalaliDate):
1567
1566
  if self._tzinfo is None:
1568
1567
  return None
1569
1568
 
1570
- offset = self._tzinfo.utcoffset(self.to_gregorian())
1569
+ g = self.to_gregorian()
1570
+ if g.tzinfo is None:
1571
+ g = g.replace(tzinfo=self._tzinfo)
1572
+ try:
1573
+ offset = self._tzinfo.utcoffset(g)
1574
+ except Exception:
1575
+ offset = self._tzinfo.utcoffset(None)
1571
1576
 
1577
+ self.check_utc_offset("utcoffset", offset)
1572
1578
  return offset
1573
1579
 
1574
1580
  def tzname(self):
1575
1581
  if self._tzinfo is None:
1576
1582
  return None
1577
1583
 
1578
- name = self._tzinfo.tzname(self.to_gregorian())
1584
+ g = self.to_gregorian()
1585
+ if g.tzinfo is None:
1586
+ g = g.replace(tzinfo=self._tzinfo)
1587
+ try:
1588
+ name = self._tzinfo.tzname(g)
1589
+ except Exception:
1590
+ name = self._tzinfo.tzname(None)
1579
1591
 
1580
1592
  if name is not None and not isinstance(name, str):
1581
- raise TypeError("tzinfo.tzname() must return None or string, " "not '%s'" % type(name))
1593
+ raise TypeError("tzinfo.tzname() must return None or string, not '%s'" % type(name))
1582
1594
 
1583
1595
  return name
1584
1596
 
1585
1597
  def dst(self):
1598
+ """Return DST offset as timedelta or None.
1599
+
1600
+ For stdlib fixed-offset timezones (datetime.timezone, including UTC) this must be timedelta(0).
1601
+ """
1586
1602
  if self._tzinfo is None:
1587
1603
  return None
1588
1604
 
1589
- offset = self._tzinfo.dst(self.to_gregorian())
1590
- self.check_utc_offset("dst", offset)
1605
+ from datetime import timedelta as _td
1606
+ from datetime import timezone as _tz
1607
+
1608
+ # datetime.timezone instances (including timezone.utc) never have DST
1609
+ if self._tzinfo is _tz.utc or isinstance(self._tzinfo, type(_tz.utc)):
1610
+ return _td(0)
1591
1611
 
1612
+ g = self.to_gregorian()
1613
+ if g.tzinfo is None:
1614
+ g = g.replace(tzinfo=self._tzinfo)
1615
+ try:
1616
+ offset = self._tzinfo.dst(g)
1617
+ except Exception:
1618
+ offset = self._tzinfo.dst(None)
1619
+
1620
+ self.check_utc_offset("dst", offset)
1592
1621
  return offset
1593
1622
 
1594
1623
  @staticmethod
@@ -1738,7 +1767,7 @@ class JalaliDateTime(JalaliDate):
1738
1767
  r"(?:[:]?(?P<zS>[0-5]\d))?"
1739
1768
  r"(?:\.(?P<zf>\d{1,6}))?)"
1740
1769
  ),
1741
- "%Z": cls._seqToRE(pytz.all_timezones, "Z"),
1770
+ "%Z": r"(?P<Z>[A-Za-z_/\-]+)",
1742
1771
  }
1743
1772
 
1744
1773
  fmt = utils.replace(
@@ -1787,7 +1816,10 @@ class JalaliDateTime(JalaliDate):
1787
1816
  )
1788
1817
  tz = timezone(delta)
1789
1818
  elif "Z" in directives.keys():
1790
- tz = pytz.timezone(directives.get("Z"))
1819
+ try:
1820
+ tz = ZoneInfo(directives.get("Z"))
1821
+ except Exception:
1822
+ raise ValueError(f"Unknown time zone name: {directives.get('Z')}")
1791
1823
 
1792
1824
  cls_attrs = {
1793
1825
  "year": directives.get("Y", 1),
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: persiantools
3
- Version: 5.3.0
3
+ Version: 5.5.0
4
4
  Summary: Jalali date and datetime with other tools
5
- Home-page: https://github.com/majiidd/persiantools
6
- Author: Majid Hajiloo
7
- Author-email: majid.hajiloo@gmail.com
8
- License: MIT
9
- Keywords: jalali shamsi persian digits characters converter jalalidate jalalidatetime date datetime jdate jdatetime farsi
5
+ Author-email: Majid Hajiloo <majid.hajiloo@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/majiidd/persiantools
8
+ Project-URL: Source, https://github.com/majiidd/persiantools
9
+ Project-URL: Issues, https://github.com/majiidd/persiantools/issues
10
+ Keywords: jalali,shamsi,persian,digits,characters,converter,jalalidate,jalalidatetime,date,datetime,jdate,jdatetime,farsi
10
11
  Classifier: Intended Audience :: Developers
11
12
  Classifier: Natural Language :: Persian
12
13
  Classifier: Operating System :: OS Independent
@@ -17,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
17
18
  Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
20
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
21
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
22
24
  Classifier: Topic :: Software Development
@@ -27,19 +29,8 @@ Classifier: Topic :: Utilities
27
29
  Requires-Python: >=3.9
28
30
  Description-Content-Type: text/markdown
29
31
  License-File: LICENSE
30
- Requires-Dist: pytz
31
- Dynamic: author
32
- Dynamic: author-email
33
- Dynamic: classifier
34
- Dynamic: description
35
- Dynamic: description-content-type
36
- Dynamic: home-page
37
- Dynamic: keywords
38
- Dynamic: license
32
+ Requires-Dist: tzdata; platform_system == "Windows"
39
33
  Dynamic: license-file
40
- Dynamic: requires-dist
41
- Dynamic: requires-python
42
- Dynamic: summary
43
34
 
44
35
  # PersianTools
45
36
 
@@ -147,15 +138,15 @@ The `JalaliDateTime` object represents a date and time in the Jalali calendar.
147
138
 
148
139
  ```python
149
140
  >>> from persiantools.jdatetime import JalaliDateTime
150
- >>> import datetime, pytz
141
+ >>> import datetime
151
142
 
152
143
  # Current Jalali datetime
153
144
  >>> JalaliDateTime.now()
154
145
  JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909)
155
146
 
156
- # Current Jalali datetime (timezone-aware)
157
- >>> JalaliDateTime.now(pytz.timezone("Asia/Tehran"))
158
- JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
147
+ >>> from zoneinfo import ZoneInfo
148
+ >>> JalaliDateTime.now(ZoneInfo("Asia/Tehran"))
149
+ JalaliDateTime(1404, 3, 16, 2, 17, 14, 907909, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
159
150
 
160
151
  # Current UTC Jalali datetime
161
152
  >>> JalaliDateTime.utcnow()
@@ -175,20 +166,21 @@ JalaliDateTime(1367, 2, 14, 14, 30, 15)
175
166
  JalaliDateTime(1400, 1, 1, 15, 30, 0, 10)
176
167
 
177
168
  # Timezone conversion
178
- >>> tehran_tz = pytz.timezone("Asia/Tehran")
179
- >>> utc_tz = pytz.utc
169
+ >>> from zoneinfo import ZoneInfo
170
+ >>> tehran_tz = ZoneInfo("Asia/Tehran")
171
+ >>> utc_tz = datetime.timezone.utc
180
172
  >>> dt_utc = JalaliDateTime.now(utc_tz)
181
173
  >>> dt_tehran = dt_utc.astimezone(tehran_tz)
182
174
  >>> dt_utc
183
- JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=<UTC>)
175
+ JalaliDateTime(1404, 3, 15, 22, 54, 8, 835877, tzinfo=datetime.timezone.utc)
184
176
  >>> dt_tehran
185
- JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0330+3:30:00 STD>)
177
+ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tehran'))
186
178
  ```
187
179
 
188
180
  #### Attributes and Methods
189
181
 
190
182
  ```python
191
- >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=pytz.utc)
183
+ >>> dt_obj = JalaliDateTime(1367, 2, 14, 14, 30, 15, 123, tzinfo=datetime.timezone.utc)
192
184
 
193
185
  >>> dt_obj.year
194
186
  1367
@@ -205,7 +197,7 @@ JalaliDateTime(1404, 3, 16, 2, 24, 8, 835877, tzinfo=<DstTzInfo 'Asia/Tehran' +0
205
197
  >>> dt_obj.microsecond
206
198
  123
207
199
  >>> dt_obj.tzinfo
208
- <UTC>
200
+ datetime.timezone.utc
209
201
 
210
202
  # Date part as datetime.date (Gregorian)
211
203
  >>> dt_obj.date()
@@ -226,9 +218,9 @@ Based on python `strftime()` behavior
226
218
 
227
219
  ```python
228
220
  >>> from persiantools.jdatetime import JalaliDateTime
229
- >>> import pytz
221
+ >>> from zoneinfo import ZoneInfo
230
222
 
231
- >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=pytz.timezone("Asia/Tehran"))
223
+ >>> dt = JalaliDateTime(1367, 2, 14, 14, 30, 0, tzinfo=ZoneInfo("Asia/Tehran"))
232
224
 
233
225
  >>> dt.strftime("%Y/%m/%d %H:%M:%S")
234
226
  '1367/02/14 14:30:00'
@@ -345,6 +337,7 @@ JalaliDate(1367, 2, 14, Chaharshanbeh)
345
337
  If you find this project helpful and would like to support its continued development, please consider donating.
346
338
 
347
339
  * **Bitcoin (BTC):** `bc1qg5rp7ymznc98wmhltzvpwl2dvfuvjr33m4hy77`
340
+ * **Ethereum (ETH):** `0xC7D6bf306E456632764D0aD111C8dBBb43a3B9ad`
348
341
  * **Tron (TRX):** `TDd63bVWZDBHmwVNFgJ6T2WdWmk9z7PBLg`
349
342
  * **Stellar (XLM):** `GDSFPPLY34QSAOTOP4DQDXAI2YDRNRIADZHTN3HCGMQXRLIGPYOEH7L5`
350
343
  * **Solana (SOL):** `CXHKgCBqBYy1hbZKGqaSmMzQoTC4Wx2v8QfL9Z7JBo3A`
@@ -2,7 +2,6 @@ LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
4
  pyproject.toml
5
- setup.py
6
5
  persiantools/__init__.py
7
6
  persiantools/characters.py
8
7
  persiantools/digits.py
@@ -11,7 +10,6 @@ persiantools/utils.py
11
10
  persiantools.egg-info/PKG-INFO
12
11
  persiantools.egg-info/SOURCES.txt
13
12
  persiantools.egg-info/dependency_links.txt
14
- persiantools.egg-info/not-zip-safe
15
13
  persiantools.egg-info/requires.txt
16
14
  persiantools.egg-info/top_level.txt
17
15
  tests/test_characters.py
@@ -0,0 +1,3 @@
1
+
2
+ [:platform_system == "Windows"]
3
+ tzdata
@@ -0,0 +1,104 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "persiantools"
7
+ dynamic = ["version"]
8
+ description = "Jalali date and datetime with other tools"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ { name = "Majid Hajiloo", email = "majid.hajiloo@gmail.com" }
14
+ ]
15
+ keywords = [
16
+ "jalali",
17
+ "shamsi",
18
+ "persian",
19
+ "digits",
20
+ "characters",
21
+ "converter",
22
+ "jalalidate",
23
+ "jalalidatetime",
24
+ "date",
25
+ "datetime",
26
+ "jdate",
27
+ "jdatetime",
28
+ "farsi",
29
+ ]
30
+ classifiers = [
31
+ "Intended Audience :: Developers",
32
+ "Natural Language :: Persian",
33
+ "Operating System :: OS Independent",
34
+ "Programming Language :: Python",
35
+ "Programming Language :: Python :: 3",
36
+ "Programming Language :: Python :: 3.9",
37
+ "Programming Language :: Python :: 3.10",
38
+ "Programming Language :: Python :: 3.11",
39
+ "Programming Language :: Python :: 3.12",
40
+ "Programming Language :: Python :: 3.13",
41
+ "Programming Language :: Python :: 3.14",
42
+ "Programming Language :: Python :: Implementation :: CPython",
43
+ "Programming Language :: Python :: Implementation :: PyPy",
44
+ "Topic :: Software Development",
45
+ "Topic :: Software Development :: Libraries",
46
+ "Topic :: Software Development :: Libraries :: Python Modules",
47
+ "Topic :: Software Development :: Localization",
48
+ "Topic :: Utilities",
49
+ ]
50
+
51
+ dependencies = [
52
+ "tzdata; platform_system == 'Windows'",
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/majiidd/persiantools"
57
+ Source = "https://github.com/majiidd/persiantools"
58
+ Issues = "https://github.com/majiidd/persiantools/issues"
59
+
60
+ [tool.setuptools.dynamic]
61
+ version = { attr = "persiantools.__version__" }
62
+
63
+ [tool.setuptools.packages.find]
64
+ include = ["persiantools*"]
65
+
66
+ [tool.black]
67
+ line-length = 120
68
+ target-version = ["py39", "py310", "py311", "py312", "py313", "py314"]
69
+ include = '\.pyi?$'
70
+ exclude = '''
71
+ (
72
+ /(
73
+ \.eggs
74
+ | \.git
75
+ | \.hg
76
+ | \.mypy_cache
77
+ | \.tox
78
+ | \.venv
79
+ | _build
80
+ | buck-out
81
+ | build
82
+ | dist
83
+ )/
84
+ )
85
+ '''
86
+
87
+ [tool.isort]
88
+ profile = "black"
89
+ line_length = 120
90
+
91
+ [tool.pytest.ini_options]
92
+ addopts = "-ra"
93
+ testpaths = ["tests"]
94
+ python_files = ["test_*.py"]
95
+ python_functions = ["test_*"]
96
+
97
+ [tool.mypy]
98
+ python_version = "3.9"
99
+ warn_unused_ignores = true
100
+ warn_redundant_casts = true
101
+ disallow_incomplete_defs = false
102
+ no_implicit_optional = true
103
+ check_untyped_defs = false
104
+ ignore_missing_imports = false
@@ -33,6 +33,7 @@ class TestJalaliDate(TestCase):
33
33
  (JalaliDate(1403, 8, 18), date(2024, 11, 8)),
34
34
  (JalaliDate(1404, 3, 16), date(2025, 6, 6)),
35
35
  (JalaliDate(1403, 10, 27), date(2025, 1, 16)),
36
+ (JalaliDate(1404, 7, 4), date(2025, 9, 26)),
36
37
  (JalaliDate(1210, 12, 29), date(1832, 3, 19)),
37
38
  (JalaliDate(1367, 12, 29), date(1989, 3, 20)),
38
39
  (JalaliDate(1392, 12, 29), date(2014, 3, 20)),
@@ -5,9 +5,9 @@ from datetime import date, datetime
5
5
  from datetime import time as _time
6
6
  from datetime import timedelta, timezone
7
7
  from unittest import TestCase
8
+ from zoneinfo import ZoneInfo
8
9
 
9
10
  import pytest
10
- import pytz
11
11
 
12
12
  from persiantools.jdatetime import JalaliDate, JalaliDateTime, _is_ascii_digit
13
13
 
@@ -46,7 +46,7 @@ class TestJalaliDateTime(TestCase):
46
46
  g = JalaliDateTime.now()
47
47
  self.assertEqual(g.time(), _time(g.hour, g.minute, g.second, g.microsecond))
48
48
 
49
- g = g.replace(tzinfo=pytz.timezone("America/Los_Angeles"))
49
+ g = g.replace(tzinfo=ZoneInfo("America/Los_Angeles"))
50
50
  self.assertEqual(
51
51
  g.timetz(),
52
52
  _time(
@@ -54,13 +54,13 @@ class TestJalaliDateTime(TestCase):
54
54
  g.minute,
55
55
  g.second,
56
56
  g.microsecond,
57
- pytz.timezone("America/Los_Angeles"),
57
+ ZoneInfo("America/Los_Angeles"),
58
58
  ),
59
59
  )
60
60
 
61
61
  self.assertEqual(
62
- JalaliDateTime.fromtimestamp(578723400, pytz.utc),
63
- JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, pytz.utc),
62
+ JalaliDateTime.fromtimestamp(578723400, timezone.utc),
63
+ JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, timezone.utc),
64
64
  )
65
65
  self.assertEqual(
66
66
  JalaliDateTime.utcfromtimestamp(578723400),
@@ -111,27 +111,27 @@ class TestJalaliDateTime(TestCase):
111
111
 
112
112
  def test_others(self):
113
113
  self.assertTrue(JalaliDateTime.fromtimestamp(time.time() - 10) <= JalaliDateTime.now())
114
- self.assertEqual(JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, pytz.utc).timestamp(), 578723400)
114
+ self.assertEqual(JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, timezone.utc).timestamp(), 578723400)
115
115
  self.assertEqual(
116
- JalaliDateTime.fromtimestamp(578723400, pytz.utc),
117
- JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, pytz.utc),
116
+ JalaliDateTime.fromtimestamp(578723400, timezone.utc),
117
+ JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, timezone.utc),
118
118
  )
119
119
  self.assertEqual(JalaliDateTime(1367, 2, 14, 4, 30, 4, 4444).jdate(), JalaliDate(1367, 2, 14))
120
120
  self.assertEqual(JalaliDateTime(1367, 2, 14, 4, 30, 4, 4444).date(), date(1988, 5, 4))
121
121
  self.assertEqual(
122
- JalaliDateTime(1367, 2, 14, 4, 30, 0, 0).replace(tzinfo=pytz.utc).__repr__(),
123
- "JalaliDateTime(1367, 2, 14, 4, 30, tzinfo=<UTC>)",
122
+ JalaliDateTime(1367, 2, 14, 4, 30, 0, 0).replace(tzinfo=timezone.utc).__repr__(),
123
+ "JalaliDateTime(1367, 2, 14, 4, 30, tzinfo=datetime.timezone.utc)",
124
124
  )
125
125
  self.assertEqual(
126
126
  JalaliDateTime(1367, 2, 14, 4, 30, 4, 4444).replace(year=1395, day=3, minute=59),
127
127
  JalaliDateTime(1395, 2, 3, 4, 59, 4, 4444),
128
128
  )
129
129
 
130
- self.assertEqual(JalaliDateTime.now(pytz.utc).tzname(), "UTC")
130
+ self.assertEqual(JalaliDateTime.now(timezone.utc).tzname(), "UTC")
131
131
  self.assertIsNone(JalaliDateTime.today().tzname())
132
132
  self.assertIsNone(JalaliDateTime.today().dst())
133
133
 
134
- dt = JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, pytz.utc)
134
+ dt = JalaliDateTime(1367, 2, 14, 4, 30, 0, 0, timezone.utc)
135
135
  self.assertEqual(dt.dst(), timedelta(0))
136
136
 
137
137
  self.assertEqual(
@@ -152,14 +152,37 @@ class TestJalaliDateTime(TestCase):
152
152
  )
153
153
 
154
154
  self.assertEqual(
155
- JalaliDateTime(1367, 2, 14, 4, 30, 0, 1, pytz.utc).isoformat(),
155
+ JalaliDateTime(1367, 2, 14, 4, 30, 0, 1, timezone.utc).isoformat(),
156
156
  "1367-02-14T04:30:00.000001+00:00",
157
157
  )
158
158
  self.assertEqual(
159
- JalaliDateTime(1367, 2, 14, 4, 30, 0, 1, pytz.utc).__str__(),
159
+ JalaliDateTime(1367, 2, 14, 4, 30, 0, 1, timezone.utc).__str__(),
160
160
  "1367-02-14 04:30:00.000001+00:00",
161
161
  )
162
162
 
163
+ def test_dst_fixed_offset_zero(self):
164
+ jdt = JalaliDateTime(1400, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=3)))
165
+ assert jdt.dst() == timedelta(0)
166
+
167
+ def test_tzname_fixed_offset(self):
168
+ jdt = JalaliDateTime(1400, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=-4, minutes=-45)))
169
+ # stdlib datetime.timezone tzname format is "UTC±HH:MM"
170
+ assert jdt.tzname() == "UTC-04:45"
171
+
172
+ def test_strptime_Z_with_zoneinfo(self):
173
+ # 1402-01-01 (2023-03-21) after Iran removed DST; Asia/Tehran is fixed +03:30
174
+ s = "1402-01-01 12:00:00 Asia/Tehran"
175
+ fmt = "%Y-%m-%d %H:%M:%S %Z"
176
+ jdt = JalaliDateTime.strptime(s, fmt)
177
+ assert isinstance(jdt.tzinfo, ZoneInfo)
178
+ assert jdt.utcoffset() == timedelta(hours=3, minutes=30)
179
+
180
+ def test_strptime_Z_invalid_name(self):
181
+ s = "1400-01-01 12:00:00 Mars/Phobos"
182
+ fmt = "%Y-%m-%d %H:%M:%S %Z"
183
+ with pytest.raises(ValueError):
184
+ JalaliDateTime.strptime(s, fmt)
185
+
163
186
  def test_operators(self):
164
187
  self.assertEqual(
165
188
  JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) + timedelta(days=30, seconds=15, milliseconds=1),
@@ -201,13 +224,13 @@ class TestJalaliDateTime(TestCase):
201
224
  self.assertTrue(JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) >= datetime(1988, 5, 4, 0, 0, 0, 0))
202
225
  self.assertTrue(JalaliDateTime(1395, 4, 15, 20, 13, 59, 0) == JalaliDateTime(1395, 4, 15, 20, 13, 59, 0))
203
226
  self.assertTrue(
204
- JalaliDateTime(1395, 4, 15, 20, 13, 59, 0, pytz.utc) != JalaliDateTime(1395, 4, 15, 20, 13, 59, 0)
227
+ JalaliDateTime(1395, 4, 15, 20, 13, 59, 0, timezone.utc) != JalaliDateTime(1395, 4, 15, 20, 13, 59, 0)
205
228
  )
206
229
 
207
230
  self.assertEqual(
208
- JalaliDateTime(1395, 4, 16, 20, 14, 30, 0, pytz.utc)
209
- - JalaliDateTime(1395, 4, 16, 20, 14, 30, 0, pytz.timezone("Asia/Tehran")),
210
- pytz.timezone("Asia/Tehran")._utcoffset,
231
+ JalaliDateTime(1395, 4, 16, 20, 14, 30, 0, timezone.utc)
232
+ - JalaliDateTime(1395, 4, 16, 20, 14, 30, 0, ZoneInfo("Asia/Tehran")),
233
+ timedelta(hours=4, minutes=30),
211
234
  )
212
235
 
213
236
  self.assertFalse(JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) == {"year": 1367})
@@ -233,7 +256,7 @@ class TestJalaliDateTime(TestCase):
233
256
  assert JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) > date(1988, 4, 5)
234
257
 
235
258
  with pytest.raises(NotImplementedError):
236
- assert JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) >= pytz.utc
259
+ assert JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) >= timezone.utc
237
260
 
238
261
  with pytest.raises(TypeError):
239
262
  assert JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) >= JalaliDate(1392, 4, 5)
@@ -245,7 +268,7 @@ class TestJalaliDateTime(TestCase):
245
268
  assert JalaliDateTime(1367, 2, 14, 4, 30, 0, 0) - []
246
269
 
247
270
  def test_hash(self):
248
- j1 = JalaliDateTime.today().replace(tzinfo=pytz.utc)
271
+ j1 = JalaliDateTime.today().replace(tzinfo=timezone.utc)
249
272
  j2 = JalaliDateTime(1369, 7, 1, 0, 0, 0, 0)
250
273
  j3 = JalaliDateTime(datetime(1990, 9, 23, 0, 0, 0, 0))
251
274
 
@@ -268,7 +291,7 @@ class TestJalaliDateTime(TestCase):
268
291
 
269
292
  def test_pickle(self):
270
293
  file = open("save.p", "wb")
271
- now = JalaliDateTime.now().replace(tzinfo=pytz.timezone("Asia/Tehran"))
294
+ now = JalaliDateTime.now().replace(tzinfo=ZoneInfo("Asia/Tehran"))
272
295
  pickle.dump(now, file)
273
296
  file.close()
274
297
 
@@ -282,27 +305,27 @@ class TestJalaliDateTime(TestCase):
282
305
 
283
306
  def test_format(self):
284
307
  self.assertEqual(
285
- JalaliDateTime(1369, 7, 1, 14, 0, 10, 0, pytz.utc).strftime("%X %p %z %Z"),
308
+ JalaliDateTime(1369, 7, 1, 14, 0, 10, 0, timezone.utc).strftime("%X %p %z %Z"),
286
309
  "14:00:10 PM +0000 UTC",
287
310
  )
288
311
 
289
312
  self.assertEqual(
290
- JalaliDateTime(1367, 2, 14, 14, 0, 10, 0, pytz.utc).strftime("%c"),
313
+ JalaliDateTime(1367, 2, 14, 14, 0, 10, 0, timezone.utc).strftime("%c"),
291
314
  "Chaharshanbeh 14 Ordibehesht 1367 14:00:10",
292
315
  )
293
316
 
294
317
  self.assertEqual(
295
- JalaliDateTime(1397, 11, 30, 14, 0, 10, 0, pytz.utc).strftime("%c"),
318
+ JalaliDateTime(1397, 11, 30, 14, 0, 10, 0, timezone.utc).strftime("%c"),
296
319
  "Seshanbeh 30 Bahman 1397 14:00:10",
297
320
  )
298
321
 
299
322
  self.assertEqual(
300
- JalaliDateTime(1367, 2, 14, 11, 0, 10, 553, pytz.utc).strftime("%I:%M:%S.%f %p"),
323
+ JalaliDateTime(1367, 2, 14, 11, 0, 10, 553, timezone.utc).strftime("%I:%M:%S.%f %p"),
301
324
  "11:00:10.000553 AM",
302
325
  )
303
326
 
304
327
  self.assertEqual(
305
- JalaliDateTime(1367, 2, 14, 14, 0, 10, 553, pytz.utc).strftime("%I:%M:%S.%f %p"),
328
+ JalaliDateTime(1367, 2, 14, 14, 0, 10, 553, timezone.utc).strftime("%I:%M:%S.%f %p"),
306
329
  "02:00:10.000553 PM",
307
330
  )
308
331
 
@@ -346,7 +369,7 @@ class TestJalaliDateTime(TestCase):
346
369
  JalaliDateTime.strptime("1400-01-01 02:00:10.000553 PM", "%Y-%m-%d %I:%M:%S.%f %p"),
347
370
  )
348
371
 
349
- jdt = JalaliDateTime(1374, 4, 8, 16, 28, 3, 227, pytz.utc)
372
+ jdt = JalaliDateTime(1374, 4, 8, 16, 28, 3, 227, timezone.utc)
350
373
  self.assertEqual(jdt, JalaliDateTime.strptime(jdt.strftime("%c %f %z %Z"), "%c %f %z %Z"))
351
374
 
352
375
  jdt_utc_combined = JalaliDateTime(1374, 4, 8, 16, 28, 3, 227, timezone.utc)
@@ -1,27 +0,0 @@
1
- [tool.black]
2
- line-length = 120
3
- include = '\.pyi?$'
4
- exclude = '''
5
- (
6
- /(
7
- \.eggs
8
- | \.git
9
- | \.hg
10
- | \.mypy_cache
11
- | \.tox
12
- | \.venv
13
- | _build
14
- | buck-out
15
- | build
16
- | dist
17
- )/
18
- )
19
- '''
20
-
21
- [tool.isort]
22
- multi_line_output = 3
23
- include_trailing_comma = true
24
- force_grid_wrap = 0
25
- use_parentheses = true
26
- ensure_newline_before_comments = true
27
- line_length = 120
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- from setuptools import setup
4
-
5
- import persiantools
6
-
7
-
8
- def readme():
9
- with open("README.md", encoding="utf-8") as f:
10
- return f.read()
11
-
12
-
13
- setup(
14
- name="persiantools",
15
- version=persiantools.__version__,
16
- description="Jalali date and datetime with other tools",
17
- long_description=readme(),
18
- long_description_content_type="text/markdown",
19
- classifiers=[
20
- "Intended Audience :: Developers",
21
- "Natural Language :: Persian",
22
- "Operating System :: OS Independent",
23
- "Programming Language :: Python",
24
- "Programming Language :: Python :: 3",
25
- "Programming Language :: Python :: 3.9",
26
- "Programming Language :: Python :: 3.10",
27
- "Programming Language :: Python :: 3.11",
28
- "Programming Language :: Python :: 3.12",
29
- "Programming Language :: Python :: 3.13",
30
- "Programming Language :: Python :: Implementation :: CPython",
31
- "Programming Language :: Python :: Implementation :: PyPy",
32
- "Topic :: Software Development",
33
- "Topic :: Software Development :: Libraries",
34
- "Topic :: Software Development :: Libraries :: Python Modules",
35
- "Topic :: Software Development :: Localization",
36
- "Topic :: Utilities",
37
- ],
38
- keywords="jalali shamsi persian digits characters converter jalalidate "
39
- "jalalidatetime date datetime jdate jdatetime farsi",
40
- url="https://github.com/majiidd/persiantools",
41
- author="Majid Hajiloo",
42
- author_email="majid.hajiloo@gmail.com",
43
- license="MIT",
44
- license_files=("LICENSE",),
45
- packages=["persiantools"],
46
- python_requires=">=3.9",
47
- tests_require=["pytest", "pytest-cov"],
48
- install_requires=["pytz"],
49
- include_package_data=True,
50
- zip_safe=False,
51
- )
File without changes
File without changes
File without changes