dcicutils 8.8.3.1b14__py3-none-any.whl → 8.8.3.1b15__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.
- dcicutils/datetime_utils.py +110 -25
- {dcicutils-8.8.3.1b14.dist-info → dcicutils-8.8.3.1b15.dist-info}/METADATA +1 -1
- {dcicutils-8.8.3.1b14.dist-info → dcicutils-8.8.3.1b15.dist-info}/RECORD +6 -6
- {dcicutils-8.8.3.1b14.dist-info → dcicutils-8.8.3.1b15.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.3.1b14.dist-info → dcicutils-8.8.3.1b15.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.3.1b14.dist-info → dcicutils-8.8.3.1b15.dist-info}/entry_points.txt +0 -0
dcicutils/datetime_utils.py
CHANGED
@@ -3,6 +3,22 @@ from datetime import datetime, timedelta, timezone
|
|
3
3
|
from dateutil import parser as datetime_parser
|
4
4
|
from typing import Optional, Tuple, Union
|
5
5
|
|
6
|
+
TIMEZONE_LOCAL = datetime.now().astimezone().tzinfo # type: datetime.timezone
|
7
|
+
TIMEZONE_LOCAL_NAME = TIMEZONE_LOCAL.tzname(None) # type: str
|
8
|
+
TIMEZONE_LOCAL_OFFSET = TIMEZONE_LOCAL.utcoffset(None) # type: datetime.timedelta
|
9
|
+
TIMEZONE_LOCAL_OFFSET_TOTAL_MINUTES = int(TIMEZONE_LOCAL_OFFSET.total_seconds()) // 60 # type: int
|
10
|
+
TIMEZONE_LOCAL_OFFSET_HOURS = TIMEZONE_LOCAL_OFFSET_TOTAL_MINUTES // 60 # type: int
|
11
|
+
TIMEZONE_LOCAL_OFFSET_MINUTES = TIMEZONE_LOCAL_OFFSET_TOTAL_MINUTES % 60 # type: int
|
12
|
+
TIMEZONE_LOCAL_SUFFIX = f"{TIMEZONE_LOCAL_OFFSET_HOURS:+03d}:{TIMEZONE_LOCAL_OFFSET_MINUTES:02d}" # type: str
|
13
|
+
|
14
|
+
TIMEZONE_UTC = timezone.utc # type: datetime.timezone
|
15
|
+
TIMEZONE_UTC_NAME = TIMEZONE_UTC.tzname(None) # type: str
|
16
|
+
TIMEZONE_UTC_OFFSET = timedelta(0) # type: datetime.timedelta
|
17
|
+
TIMEZONE_UTC_OFFSET_TOTAL_MINUTES = 0 # type: int
|
18
|
+
TIMEZONE_UTC_OFFSET_HOURS = 0 # type: int
|
19
|
+
TIMEZONE_UTC_OFFSET_MINUTES = 0 # type: int
|
20
|
+
TIMEZONE_UTC_SUFFIX = "Z" # type: str
|
21
|
+
|
6
22
|
|
7
23
|
def parse_datetime_string(value: str) -> Optional[datetime]:
|
8
24
|
"""
|
@@ -83,46 +99,60 @@ def normalize_date_string(value: str) -> Optional[str]:
|
|
83
99
|
return d.strftime("%Y-%m-%d") if d else None
|
84
100
|
|
85
101
|
|
86
|
-
def get_timezone(
|
102
|
+
def get_timezone(hours_or_timedelta: Union[int, timedelta], minutes: Optional[int] = None) -> timezone:
|
103
|
+
try:
|
104
|
+
if isinstance(hours_or_timedelta, timedelta):
|
105
|
+
return timezone(hours_or_timedelta)
|
106
|
+
return timezone(timedelta(hours=hours_or_timedelta, minutes=minutes or 0))
|
107
|
+
except Exception:
|
108
|
+
return TIMEZONE_LOCAL
|
109
|
+
|
110
|
+
|
111
|
+
def get_timezone_offset(tz: timezone) -> timedelta:
|
87
112
|
try:
|
88
|
-
return
|
113
|
+
return tz.utcoffset(None)
|
89
114
|
except Exception:
|
90
|
-
return
|
115
|
+
return TIMEZONE_LOCAL_OFFSET
|
91
116
|
|
92
117
|
|
93
118
|
def get_timezone_hours_minutes(tz: timezone) -> Tuple[int, int]:
|
94
119
|
"""
|
95
120
|
Returns a tuple with the integer hours and minutes offset for the given timezone.
|
121
|
+
If negative then only the hours is negative; the mintutes is always positive;
|
122
|
+
this is okay because there are no timezones less than one hour from UTC.
|
96
123
|
"""
|
97
|
-
|
98
|
-
|
124
|
+
tz_offset = get_timezone_offset(tz)
|
125
|
+
tz_offset_total_minutes = int(tz_offset.total_seconds()) // 60
|
126
|
+
tz_offset_hours = tz_offset_total_minutes // 60
|
127
|
+
tz_offset_minutes = abs(tz_offset_total_minutes % 60)
|
128
|
+
return tz_offset_hours, tz_offset_minutes
|
99
129
|
|
100
130
|
|
101
131
|
def get_utc_timezone() -> timezone:
|
102
|
-
return
|
132
|
+
return TIMEZONE_UTC
|
103
133
|
|
104
134
|
|
105
135
|
def get_local_timezone() -> timezone:
|
106
136
|
"""
|
107
137
|
Returns current/local timezone as a datetime.timezone object.
|
108
138
|
"""
|
109
|
-
return
|
139
|
+
return TIMEZONE_LOCAL
|
110
140
|
|
111
141
|
|
112
142
|
def get_local_timezone_string() -> str:
|
113
143
|
"""
|
114
144
|
Returns current/local timezone in format like: "-05:00".
|
115
145
|
"""
|
116
|
-
|
117
|
-
return f"{tz_hours:+03d}:{tz_minutes:02d}"
|
146
|
+
return TIMEZONE_LOCAL_SUFFIX
|
118
147
|
|
119
148
|
|
120
149
|
def get_local_timezone_hours_minutes() -> Tuple[int, int]:
|
121
150
|
"""
|
122
151
|
Returns a tuple with the integer hours and minutes offset for the current/local timezone.
|
152
|
+
If negative then only the hours is negative; the mintutes is always positive;
|
153
|
+
this is okay because there are no timezones less than one hour from UTC.
|
123
154
|
"""
|
124
|
-
|
125
|
-
return int(tz_minutes // 60), int(abs(tz_minutes % 60))
|
155
|
+
return TIMEZONE_LOCAL_OFFSET_HOURS, TIMEZONE_LOCAL_OFFSET_MINUTES
|
126
156
|
|
127
157
|
|
128
158
|
def parse_datetime(value: str, utc: bool = False, tz: Optional[timezone] = None) -> Optional[datetime]:
|
@@ -154,14 +184,16 @@ def parse_datetime(value: str, utc: bool = False, tz: Optional[timezone] = None)
|
|
154
184
|
|
155
185
|
def format_datetime(value: datetime,
|
156
186
|
utc: bool = False,
|
157
|
-
iso: bool = False,
|
158
|
-
ms: bool = False,
|
159
187
|
tz: Optional[Union[timezone, bool]] = None,
|
188
|
+
iso: bool = False,
|
160
189
|
notz: bool = False,
|
161
190
|
noseconds: bool = False,
|
191
|
+
ms: bool = False,
|
162
192
|
verbose: bool = False,
|
163
193
|
noseparator: bool = False,
|
164
|
-
noday: bool = False
|
194
|
+
noday: bool = False,
|
195
|
+
nodate: bool = False,
|
196
|
+
notime: bool = False) -> str:
|
165
197
|
"""
|
166
198
|
Returns the given datetime as a string in "YYYY:MM:DD hh:mm:ss tz" format, for
|
167
199
|
example "2024-04-17 15:42:26 EDT". If the given notz argument is True then omits
|
@@ -173,9 +205,11 @@ def format_datetime(value: datetime,
|
|
173
205
|
one; if the given utc argument is True then it will be UTC; or if the given tz
|
174
206
|
argument is a datetime.timezone it will be in that timezone.
|
175
207
|
"""
|
208
|
+
if nodate is True and notime is True:
|
209
|
+
return ""
|
176
210
|
if not isinstance(value, datetime):
|
177
211
|
if not isinstance(value, str) or not (value := parse_datetime(value)):
|
178
|
-
return
|
212
|
+
return ""
|
179
213
|
try:
|
180
214
|
if utc is True:
|
181
215
|
tz = timezone.utc
|
@@ -195,19 +229,70 @@ def format_datetime(value: datetime,
|
|
195
229
|
value = value.replace(microsecond=0)
|
196
230
|
if noseconds is True:
|
197
231
|
if notz is True:
|
198
|
-
|
232
|
+
if nodate is True:
|
233
|
+
return value.strftime(f"%H:%M")
|
234
|
+
elif notime is True:
|
235
|
+
return value.strftime(f"%Y-%m-%d")
|
236
|
+
else:
|
237
|
+
return value.strftime(f"%Y-%m-%dT%H:%M")
|
199
238
|
tz = value.strftime("%z")
|
200
239
|
tz = tz[:3] + ":" + tz[3:]
|
201
|
-
|
202
|
-
|
240
|
+
if nodate is True:
|
241
|
+
return value.strftime(f"%H:%M") + tz
|
242
|
+
elif notime is True:
|
243
|
+
return value.strftime(f"%Y-%m-%d") + tz
|
244
|
+
else:
|
245
|
+
return value.strftime(f"%Y-%m-%dT%H:%M") + tz
|
246
|
+
if nodate is True:
|
247
|
+
return value.strftime(f"%H:%M:%S{f'.%f' if ms is True else ''}")
|
248
|
+
elif notime is True:
|
249
|
+
return value.strftime(f"%Y-%m-%d")
|
250
|
+
else:
|
251
|
+
return value.isoformat()
|
203
252
|
if verbose:
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
253
|
+
if nodate is True:
|
254
|
+
return value.strftime(
|
255
|
+
f"%-I:%M{'' if noseconds is True else ':%S'}"
|
256
|
+
f"{f'.%f' if ms is True else ''} %p{'' if notz is True else ' %Z'}")
|
257
|
+
elif notime is True:
|
258
|
+
return value.strftime(f"{'' if noday is True else '%A, '}%B %-d, %Y")
|
259
|
+
else:
|
260
|
+
return value.strftime(
|
261
|
+
f"{'' if noday is True else '%A, '}%B %-d, %Y{'' if noseparator is True else ' |'}"
|
262
|
+
f" %-I:%M{'' if noseconds is True else ':%S'}"
|
263
|
+
f"{f'.%f' if ms is True else ''} %p{'' if notz is True else ' %Z'}")
|
208
264
|
else:
|
209
|
-
|
210
|
-
|
211
|
-
|
265
|
+
if nodate is True:
|
266
|
+
return value.strftime(
|
267
|
+
f"%H:%M{'' if noseconds is True else ':%S'}"
|
268
|
+
f"{f'.%f' if ms is True else ''}{'' if notz is True else ' %Z'}")
|
269
|
+
elif notime is True:
|
270
|
+
return value.strftime(f"%Y-%m-%d")
|
271
|
+
else:
|
272
|
+
return value.strftime(
|
273
|
+
f"%Y-%m-%d %H:%M{'' if noseconds is True else ':%S'}"
|
274
|
+
f"{f'.%f' if ms is True else ''}{'' if notz is True else ' %Z'}")
|
212
275
|
except Exception:
|
213
276
|
return None
|
277
|
+
|
278
|
+
|
279
|
+
def format_date(value: datetime,
|
280
|
+
utc: bool = False,
|
281
|
+
iso: bool = False,
|
282
|
+
tz: Optional[Union[timezone, bool]] = None,
|
283
|
+
verbose: bool = False,
|
284
|
+
noday: bool = False) -> str:
|
285
|
+
return format_datetime(value, utc=utc, iso=iso, tz=tz, verbose=verbose, noday=noday, notime=True)
|
286
|
+
|
287
|
+
|
288
|
+
def format_time(value: datetime,
|
289
|
+
utc: bool = False,
|
290
|
+
iso: bool = False,
|
291
|
+
ms: bool = False,
|
292
|
+
tz: Optional[Union[timezone, bool]] = None,
|
293
|
+
notz: bool = False,
|
294
|
+
noseconds: bool = False,
|
295
|
+
verbose: bool = False,
|
296
|
+
noday: bool = False) -> str:
|
297
|
+
return format_datetime(value, utc=utc, iso=iso, ms=ms, tz=tz, notz=notz,
|
298
|
+
noseconds=noseconds, verbose=verbose, nodate=True)
|
@@ -12,7 +12,7 @@ dcicutils/contribution_utils.py,sha256=vYLS1JUB3sKd24BUxZ29qUBqYeQBLK9cwo8x3k64u
|
|
12
12
|
dcicutils/creds_utils.py,sha256=xrLekD49Ex0GOpL9n7LlJA4gvNcY7txTVFOSYD7LvEU,11113
|
13
13
|
dcicutils/data_readers.py,sha256=6EMrY7TjDE8H7bA_TCWtpLQP7slJ0YTL77_dNh6e7sg,7626
|
14
14
|
dcicutils/data_utils.py,sha256=k2OxOlsx7AJ6jF-YNlMyGus_JqSUBe4_n1s65Mv1gQQ,3098
|
15
|
-
dcicutils/datetime_utils.py,sha256=
|
15
|
+
dcicutils/datetime_utils.py,sha256=STFFakdCIwtuRLA1PCbieeXniTPY8Rchg5Psv1CUJ84,13342
|
16
16
|
dcicutils/deployment_utils.py,sha256=sKv8Jb-_Zw2aH3OAywRlsre-Cqm3a7fEGG3_1PT-r-s,69908
|
17
17
|
dcicutils/diff_utils.py,sha256=sQx-yz56DHAcQWOChYbAG3clXu7TbiZKlw-GggeveO0,8118
|
18
18
|
dcicutils/docker_utils.py,sha256=30gUiqz7X9rJwSPXTPn4ewjQibUgoSJqhP9o9vn5X-A,1747
|
@@ -72,8 +72,8 @@ dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
|
|
72
72
|
dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
|
73
73
|
dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
|
74
74
|
dcicutils/zip_utils.py,sha256=rnjNv_k6L9jT2SjDSgVXp4BEJYLtz9XN6Cl2Fy-tqnM,2027
|
75
|
-
dcicutils-8.8.3.
|
76
|
-
dcicutils-8.8.3.
|
77
|
-
dcicutils-8.8.3.
|
78
|
-
dcicutils-8.8.3.
|
79
|
-
dcicutils-8.8.3.
|
75
|
+
dcicutils-8.8.3.1b15.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
76
|
+
dcicutils-8.8.3.1b15.dist-info/METADATA,sha256=JY0PlcvcINCPnQ0qQ6u5flnCWSw1237wWPTfmlg43T4,3357
|
77
|
+
dcicutils-8.8.3.1b15.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
78
|
+
dcicutils-8.8.3.1b15.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
79
|
+
dcicutils-8.8.3.1b15.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|