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.
@@ -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(hours: int, minutes: Optional[int] = None) -> 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 timezone(timedelta(hours=hours, minutes=minutes or 0))
113
+ return tz.utcoffset(None)
89
114
  except Exception:
90
- return timezone.utc
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
- tz_minutes = datetime.now(tz).utcoffset().total_seconds() / 60
98
- return int(tz_minutes // 60), int(abs(tz_minutes % 60))
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 timezone.utc
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 datetime.now().astimezone().tzinfo
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
- tz_hours, tz_minutes = get_local_timezone_hours_minutes()
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
- tz_minutes = datetime.now(timezone.utc).astimezone().utcoffset().total_seconds() / 60
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) -> Optional[str]:
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 None
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
- return value.strftime(f"%Y-%m-%dT%H:%M")
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
- return value.strftime(f"%Y-%m-%dT%H:%M") + tz
202
- return value.isoformat()
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
- return value.strftime(
205
- f"{'' if noday is True else '%A, '}%B %-d, %Y{'' if noseparator is True else ' |'}"
206
- f" %-I:%M{'' if noseconds is True else ':%S'}"
207
- f"{f'.%f' if ms is True else ''} %p{'' if notz is True else ' %Z'}")
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
- return value.strftime(
210
- f"%Y-%m-%d %H:%M{'' if noseconds is True else ':%S'}"
211
- f"{f'.%f' if ms is True else ''}{'' if notz is True else ' %Z'}")
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.8.3.1b14
3
+ Version: 8.8.3.1b15
4
4
  Summary: Utility package for interacting with the 4DN Data Portal and other 4DN resources
5
5
  Home-page: https://github.com/4dn-dcic/utils
6
6
  License: MIT
@@ -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=S3SCmpqv_Z0CS8_yqZsoN4aL1Epu8jwKs6DDYs96OdM,9427
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.1b14.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
76
- dcicutils-8.8.3.1b14.dist-info/METADATA,sha256=Od4jg67J1tt_7cxv1n04p8PGmpjbnlfi9-EKsMS-GKk,3357
77
- dcicutils-8.8.3.1b14.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
78
- dcicutils-8.8.3.1b14.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
79
- dcicutils-8.8.3.1b14.dist-info/RECORD,,
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,,