stdl 0.5.6__tar.gz → 0.6.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: stdl
3
- Version: 0.5.6
3
+ Version: 0.6.1
4
4
  Summary: Extended Python Standard Library
5
5
  Author-email: Žiga Ivanšek <ziga.ivansek@gmail.com>
6
6
  Project-URL: Repository, https://github.com/zigai/stdl
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stdl"
3
- version = "0.5.6"
3
+ version = "0.6.1"
4
4
  description = "Extended Python Standard Library"
5
5
  authors = [{ name = "Žiga Ivanšek", email = "ziga.ivansek@gmail.com" }]
6
6
  license = { file = "LICENSE.txt" }
@@ -67,7 +67,7 @@ def timer(
67
67
 
68
68
  def retry(attempts: int, delay: float = 0):
69
69
  if attempts < 1:
70
- raise ValueError("attempts must be greater than 0")
70
+ raise ValueError("Attempts must be greater than 0")
71
71
 
72
72
  def decorator(func):
73
73
  @wraps(func)
@@ -98,7 +98,8 @@ def datetime_fmt(
98
98
  ms: bool = False,
99
99
  utc: bool = True,
100
100
  ) -> str:
101
- """Format date and time
101
+ """
102
+ Format date and time
102
103
 
103
104
  Args:
104
105
  d (str | float | None | datetime, optional): Input datetime. Defaults to current date and time.
@@ -261,6 +262,90 @@ def sleep(lo: float, hi: float | None = None) -> float:
261
262
  return t
262
263
 
263
264
 
265
+ def seconds_to_hms(time: int | float, ms: bool = False) -> str:
266
+ """
267
+ Converts time in seconds to a string in the format HH:MM:SS[.mmm]
268
+
269
+ Example:
270
+ >>> seconds_to_hms(123.456)
271
+ '00:02:03'
272
+ >>> seconds_to_hms(123.456, ms=True)
273
+ '00:02:03.456'
274
+ >>> seconds_to_hms(-123.456, ms=True)
275
+ '-00:02:03.456'
276
+ """
277
+ sign = "-" if time < 0 else ""
278
+ time = abs(time)
279
+
280
+ s = int(time % 60)
281
+ m = int((time // 60) % 60)
282
+ h = int(time // 3600)
283
+ time_str = f"{sign}{h:02d}:{m:02d}:{s:02d}"
284
+
285
+ if ms:
286
+ milis = int(round((time - int(time)) * 1000))
287
+ time_str += f".{milis:03d}"
288
+ return time_str
289
+
290
+
291
+ def hms_to_seconds(time: str, ms: bool = False) -> float | None:
292
+ """
293
+ Converts a string in the format HH:MM:SS[.mmm] or h:m:s or m:s to time in seconds.
294
+
295
+ Example:
296
+ >>> hms_to_seconds('00:02:03')
297
+ 123.0
298
+ >>> hms_to_seconds('00:02:03.456', ms=True)
299
+ 123.456
300
+ """
301
+ if time is None:
302
+ return None
303
+
304
+ negative = False
305
+ time = time.strip()
306
+ if time.startswith("-"):
307
+ negative = True
308
+ time = time[1:]
309
+
310
+ parts = time.split(":")
311
+ if len(parts) == 1:
312
+ return float(parts[0])
313
+ time_milis = 0.0
314
+
315
+ if ms:
316
+ if "." in parts[-1]:
317
+ dot_split = parts[-1].split(".", 1)
318
+ parts[-1], millis_str = dot_split
319
+ if not millis_str.isdigit():
320
+ raise ValueError(f"Invalid milliseconds in time: '{time}'")
321
+ millis = int(millis_str.ljust(3, "0"))
322
+ time_milis = millis / 1000
323
+
324
+ try:
325
+ if len(parts) == 2:
326
+ minute_part, second_part = parts
327
+ m = int(minute_part)
328
+ s = int(second_part)
329
+ if s >= 60:
330
+ raise ValueError(f"Seconds ({s}) must be < 60.")
331
+ total = m * 60 + s
332
+ elif len(parts) == 3:
333
+ hour_part, minute_part, second_part = parts
334
+ h = int(hour_part)
335
+ m = int(minute_part)
336
+ s = int(second_part)
337
+ if m >= 60 or s >= 60:
338
+ raise ValueError(f"Minutes ({m}) or seconds ({s}) must be < 60.")
339
+ total = h * 3600 + m * 60 + s
340
+ else:
341
+ raise ValueError("Invalid number of time segments.")
342
+ except ValueError as e:
343
+ raise ValueError(f"Invalid time format: '{time}'") from e
344
+
345
+ result = total + time_milis
346
+ return -result if negative else result
347
+
348
+
264
349
  __all__ = [
265
350
  "Timer",
266
351
  "parse_datetime_str",