dycw-utilities 0.162.10__py3-none-any.whl → 0.163.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.162.10
3
+ Version: 0.163.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=zMHLpjqodpgnTGNFe5Cy0RGeYyGmr28KYyvHxSnrObY,61
1
+ utilities/__init__.py,sha256=CLO_sr-qLd7WdgPYexoc3HRpgT0MLBKc5zxy7MRUwSE,60
2
2
  utilities/aeventkit.py,sha256=ddoleSwW9zdc2tjX5Ge0pMKtYwV_JMxhHYOxnWX2AGM,12609
3
3
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
4
4
  utilities/asyncio.py,sha256=PUedzQ5deqlSECQ33sam9cRzI9TnygHz3FdOqWJWPTM,15288
@@ -15,14 +15,14 @@ utilities/dataclasses.py,sha256=wGfQtopYZCwvUxNxLOlVNFlhK8Q0_aQbKJ0rWfT-fEc,3248
15
15
  utilities/enum.py,sha256=5l6pwZD1cjSlVW4ss-zBPspWvrbrYrdtJWcg6f5_J5w,5781
16
16
  utilities/errors.py,sha256=mFlDGSM0LI1jZ1pbqwLAH3ttLZ2JVIxyZLojw8tGVZU,1479
17
17
  utilities/fastapi.py,sha256=TqyKvBjiMS594sXPjrz-KRTLMb3l3D3rZ1zAYV7GfOk,1454
18
- utilities/fpdf2.py,sha256=HgM8JSvoioDXrjC0UR3HVLjnMnnb_mML7nL2EmkTwGI,1854
18
+ utilities/fpdf2.py,sha256=dSiYz0FJTD2sQuxpxqFWwwIe2-p6Y7oTB9Tv0Jajit0,1866
19
19
  utilities/functions.py,sha256=RNVAoLeT_sl-gXaBv2VI_U_EB-d-nSVosYR4gTeeojE,28261
20
20
  utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
21
21
  utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
22
22
  utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
23
23
  utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
24
24
  utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
25
- utilities/hypothesis.py,sha256=1_rYNFUAkqRhZUrMM4h_eoRv1_ZCtyD6R87SeJbZpOQ,44758
25
+ utilities/hypothesis.py,sha256=eoFAFnM2SdvzH6DWD5oCs8cH57LsEEXsRy8vMZDW6i8,44874
26
26
  utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
27
27
  utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
28
28
  utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
@@ -31,7 +31,7 @@ utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
31
31
  utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
32
32
  utilities/libcst.py,sha256=TKgKN4bNmtBNEE-TUfhTyd1BrTncfsl_7tTuhpesGYY,5585
33
33
  utilities/lightweight_charts.py,sha256=YM3ojBvJxuCSUBu_KrhFBmaMCvRPvupKC3qkm-UVZq4,2751
34
- utilities/logging.py,sha256=ihbfQJgjc7t3Pds0oPvF_J1eigiqFKzxNOijzoee8U4,18064
34
+ utilities/logging.py,sha256=uJ-hhtkrx4xnLUzZmE1soV4O8wQzNPUB1f_YJJe6I30,18089
35
35
  utilities/math.py,sha256=cevB-YyEYAzJTWtkAr7qeeu-hbxorDI3gMznXlmNQkw,26897
36
36
  utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,853
37
37
  utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
@@ -52,7 +52,7 @@ utilities/pottery.py,sha256=ggMN72Y7wx7Js8VN6eyNyodpm8TIYqZHGghkDPXIVWk,3949
52
52
  utilities/pqdm.py,sha256=idv2seRVP2f6NeSfpeEnT5A-tQezaHZKDyeu16g2-0E,3091
53
53
  utilities/psutil.py,sha256=KUlu4lrUw9Zg1V7ZGetpWpGb9DB8l_SSDWGbANFNCPU,2104
54
54
  utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- utilities/pyinstrument.py,sha256=NZCZz2nBo0BLJ9DTf7H_Q_KGxvsf2S2M3h0qYoYh2kw,804
55
+ utilities/pyinstrument.py,sha256=hnXaL-4HE7wWBI5JKaPfYTpsrXe68YiuZKahHV0VJn8,841
56
56
  utilities/pytest.py,sha256=M-Om6b3hpF9W_bEB7UFY2IzBCubSxzVQleGrgRXHtxY,7741
57
57
  utilities/pytest_regressions.py,sha256=ocjHTtfOeiGfQAKIei8pKNd61sxN9dawrJJ9gPt2wzA,4097
58
58
  utilities/random.py,sha256=hZlH4gnAtoaofWswuJYjcygejrY8db4CzP-z_adO2Mo,4165
@@ -70,10 +70,10 @@ utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
70
70
  utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
71
71
  utilities/tempfile.py,sha256=HxB2BF28CcecDJLQ3Bx2Ej-Pb6RJc6W9ngSpB9CnP4k,2018
72
72
  utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
73
- utilities/text.py,sha256=oMARu9HA3lY-NNRxPsz0Ld7L1ki7VKO_hmWYARYt0xY,13476
73
+ utilities/text.py,sha256=NVPywVHGnHzyjs1N1U8J4YIqKCU3v-794y6c3px1wYo,13667
74
74
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
75
75
  utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
76
- utilities/traceback.py,sha256=1k5JgumSMaqAGLd0dZ36CtPS0EGaglxTr29r2Dz4D60,9457
76
+ utilities/traceback.py,sha256=N8A0OgdIEsSWmmK7IxQZahA3iVxQ_shk7jy5-01hMKg,9454
77
77
  utilities/typed_settings.py,sha256=SFWqS3lAzV7IfNRwqFcTk0YynTcQ7BmrcW2mr_KUnos,4466
78
78
  utilities/types.py,sha256=oeH-hEC3-67Eja4nLz-Nj9WvK6Z9-3T1zobO_XJpuVg,18735
79
79
  utilities/typing.py,sha256=7ZgCNZwA6oaiwpSJIS9Rj3i3MbRBYHMqbC3jMe5KiNg,13992
@@ -82,14 +82,14 @@ utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
82
82
  utilities/uuid.py,sha256=nQZs6tFX4mqtc2Ku3KqjloYCqwpTKeTj8eKwQwh3FQI,1572
83
83
  utilities/version.py,sha256=ipBj5-WYY_nelp2uwFlApfWWCzTLzPwpovUi9x_OBMs,5085
84
84
  utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
85
- utilities/whenever.py,sha256=qLwdjCb-me5FXWBcZ4M7IT66guqhz5EbX2VRAWRNVvI,57541
85
+ utilities/whenever.py,sha256=8jQZkE3_8E4A10oQM-OYIJpWtvBBtYTf-WIv3cVxL9w,57555
86
86
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
87
87
  utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
88
88
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
89
89
  utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
90
90
  utilities/pytest_plugins/pytest_regressions.py,sha256=9v8kAXDM2ycIXJBimoiF4EgrwbUvxTycFWJiGR_GHhM,1466
91
- dycw_utilities-0.162.10.dist-info/METADATA,sha256=4ojoO-imA90W_htmRYNlCbG_yL8aLPxFwy5loWOSnkM,1697
92
- dycw_utilities-0.162.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.162.10.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
- dycw_utilities-0.162.10.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.162.10.dist-info/RECORD,,
91
+ dycw_utilities-0.163.0.dist-info/METADATA,sha256=l4s6zILCQ1BgA5UNVaeqXOaAgn3eyGtF1XAff--dfFI,1696
92
+ dycw_utilities-0.163.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.163.0.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
+ dycw_utilities-0.163.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.163.0.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.162.10"
3
+ __version__ = "0.163.0"
utilities/fpdf2.py CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, override
6
6
  from fpdf import FPDF
7
7
  from fpdf.enums import XPos, YPos
8
8
 
9
- from utilities.whenever import get_now, to_local_plain
9
+ from utilities.whenever import format_compact, get_now_local
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from collections.abc import Iterator
@@ -47,7 +47,7 @@ def yield_pdf(*, header: str | None = None) -> Iterator[_BasePDF]:
47
47
  def footer(self) -> None:
48
48
  self.set_y(-15)
49
49
  self.set_font(family="Helvetica", style="I", size=8)
50
- page_no, now = (self.page_no(), to_local_plain(get_now()))
50
+ page_no, now = (self.page_no(), format_compact(get_now_local()))
51
51
  text = f"page {page_no}/{{}}; {now}"
52
52
  _ = self.cell(
53
53
  w=0,
utilities/hypothesis.py CHANGED
@@ -115,7 +115,7 @@ if TYPE_CHECKING:
115
115
  from sqlalchemy import URL
116
116
 
117
117
  from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
118
- from utilities.types import Number, TimeZoneLike
118
+ from utilities.types import Number, TimeZone, TimeZoneLike
119
119
 
120
120
 
121
121
  type MaybeSearchStrategy[_T] = _T | SearchStrategy[_T]
@@ -1484,12 +1484,17 @@ def zone_infos(draw: DrawFn, /) -> ZoneInfo:
1484
1484
  """Strategy for generating time-zones."""
1485
1485
  time_zone = draw(timezones())
1486
1486
  if IS_LINUX: # skipif-not-linux
1487
- _ = assume(time_zone.key not in {"Etc/UTC", "localtime"})
1487
+ _ = assume(time_zone.key not in _LINUX_DISALLOW_TIME_ZONES)
1488
1488
  with assume_does_not_raise(TimeZoneNotFoundError):
1489
1489
  _ = get_now(time_zone)
1490
1490
  return time_zone
1491
1491
 
1492
1492
 
1493
+ _LINUX_DISALLOW_TIME_ZONES: set[TimeZone | Literal["localtime"]] = {
1494
+ "Etc/UTC",
1495
+ "localtime",
1496
+ }
1497
+
1493
1498
  ##
1494
1499
 
1495
1500
 
utilities/logging.py CHANGED
@@ -47,9 +47,9 @@ from utilities.re import (
47
47
  from utilities.sentinel import Sentinel, sentinel
48
48
  from utilities.whenever import (
49
49
  WheneverLogRecord,
50
+ format_compact,
50
51
  get_now_local,
51
- parse_plain_local,
52
- to_local_plain,
52
+ to_zoned_date_time,
53
53
  )
54
54
 
55
55
  if TYPE_CHECKING:
@@ -397,8 +397,8 @@ class SizeAndTimeRotatingFileHandler(BaseRotatingHandler):
397
397
  def _compute_rollover_patterns(stem: str, suffix: str, /) -> _RolloverPatterns:
398
398
  return _RolloverPatterns(
399
399
  pattern1=re.compile(rf"^{stem}\.(\d+){suffix}$"),
400
- pattern2=re.compile(rf"^{stem}\.(\d+)__([\dT]+?){suffix}$"),
401
- pattern3=re.compile(rf"^{stem}\.(\d+)__([\dT]+?)__([\dT]+?){suffix}$"),
400
+ pattern2=re.compile(rf"^{stem}\.(\d+)__(.+?){suffix}$"),
401
+ pattern3=re.compile(rf"^{stem}\.(\d+)__(.+?)__(.+?){suffix}$"),
402
402
  )
403
403
 
404
404
 
@@ -498,8 +498,8 @@ class _RotatingLogFile:
498
498
  stem=stem,
499
499
  suffix=suffix,
500
500
  index=int(index),
501
- start=parse_plain_local(start),
502
- end=parse_plain_local(end),
501
+ start=to_zoned_date_time(start),
502
+ end=to_zoned_date_time(end),
503
503
  )
504
504
  try:
505
505
  index, end = extract_groups(patterns.pattern2, path.name)
@@ -511,7 +511,7 @@ class _RotatingLogFile:
511
511
  stem=stem,
512
512
  suffix=suffix,
513
513
  index=int(index),
514
- end=parse_plain_local(end),
514
+ end=to_zoned_date_time(end),
515
515
  )
516
516
  try:
517
517
  index = extract_group(patterns.pattern1, path.name)
@@ -532,9 +532,9 @@ class _RotatingLogFile:
532
532
  case int() as index, None, None:
533
533
  tail = str(index)
534
534
  case int() as index, None, ZonedDateTime() as end:
535
- tail = f"{index}__{to_local_plain(end)}"
535
+ tail = f"{index}__{format_compact(end, path=True)}"
536
536
  case int() as index, ZonedDateTime() as start, ZonedDateTime() as end:
537
- tail = f"{index}__{to_local_plain(start)}__{to_local_plain(end)}"
537
+ tail = f"{index}__{format_compact(start, path=True)}__{format_compact(end, path=True)}"
538
538
  case _: # pragma: no cover
539
539
  raise ImpossibleCaseError(
540
540
  case=[f"{self.index=}", f"{self.start=}", f"{self.end=}"]
utilities/pyinstrument.py CHANGED
@@ -8,7 +8,7 @@ from pyinstrument.profiler import Profiler
8
8
 
9
9
  from utilities.atomicwrites import writer
10
10
  from utilities.pathlib import to_path
11
- from utilities.whenever import get_now, to_local_plain
11
+ from utilities.whenever import format_compact, get_now_local
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from collections.abc import Iterator
@@ -21,7 +21,9 @@ def profile(path: MaybeCallablePathLike = Path.cwd, /) -> Iterator[None]:
21
21
  """Profile the contents of a block."""
22
22
  with Profiler() as profiler:
23
23
  yield
24
- filename = to_path(path).joinpath(f"profile__{to_local_plain(get_now())}.html")
24
+ filename = to_path(path).joinpath(
25
+ f"profile__{format_compact(get_now_local(), path=True)}.html"
26
+ )
25
27
  with writer(filename) as temp:
26
28
  _ = temp.write_text(profiler.output_html())
27
29
 
utilities/text.py CHANGED
@@ -92,6 +92,14 @@ def _pascal_case_one(text: str, /) -> str:
92
92
  ##
93
93
 
94
94
 
95
+ def prompt_bool(prompt: object = "", /, *, confirm: bool = False) -> bool:
96
+ """Prompt for a boolean."""
97
+ return True if confirm else parse_bool(input(prompt))
98
+
99
+
100
+ ##
101
+
102
+
95
103
  def repr_encode(obj: Any, /) -> bytes:
96
104
  """Return the representation of the object encoded as bytes."""
97
105
  return repr(obj).encode()
@@ -518,6 +526,7 @@ __all__ = [
518
526
  "parse_bool",
519
527
  "parse_none",
520
528
  "pascal_case",
529
+ "prompt_bool",
521
530
  "repr_encode",
522
531
  "secret_str",
523
532
  "snake_case",
utilities/traceback.py CHANGED
@@ -33,8 +33,6 @@ from utilities.whenever import (
33
33
  format_compact,
34
34
  get_now,
35
35
  get_now_local,
36
- parse_plain_local,
37
- to_local_plain,
38
36
  to_zoned_date_time,
39
37
  )
40
38
 
@@ -258,7 +256,9 @@ def _make_except_hook_inner(
258
256
  _ = sys.stderr.write(f"{slim}\n") # don't 'from sys import stderr'
259
257
  if path is not None:
260
258
  path = to_path(path)
261
- path_log = path.joinpath(to_local_plain(get_now())).with_suffix(".txt")
259
+ path_log = path.joinpath(
260
+ format_compact(get_now_local(), path=True)
261
+ ).with_suffix(".txt")
262
262
  full = format_exception_stack(
263
263
  exc_val,
264
264
  header=True,
@@ -294,7 +294,7 @@ def _make_except_hook_purge(path: PathLike, max_age: Delta, /) -> None:
294
294
  paths = {
295
295
  p
296
296
  for p in Path(path).iterdir()
297
- if p.is_file() and (parse_plain_local(p.stem) <= threshold)
297
+ if p.is_file() and (to_zoned_date_time(p.stem) <= threshold)
298
298
  }
299
299
  for p in paths:
300
300
  p.unlink(missing_ok=True)
utilities/whenever.py CHANGED
@@ -310,7 +310,11 @@ def diff_year_month(
310
310
 
311
311
 
312
312
  def format_compact(
313
- obj: Date | Time | PlainDateTime | ZonedDateTime, /, *, fmt: str | None = None
313
+ obj: Date | Time | PlainDateTime | ZonedDateTime,
314
+ /,
315
+ *,
316
+ fmt: str | None = None,
317
+ path: bool = False,
314
318
  ) -> str:
315
319
  """Format the date/datetime in a compact fashion."""
316
320
  match obj:
@@ -320,11 +324,15 @@ def format_compact(
320
324
  case Time() as time:
321
325
  obj_use = time.round().py_time()
322
326
  fmt_use = "%H%M%S" if fmt is None else fmt
323
- case PlainDateTime() as datetime:
324
- obj_use = datetime.round().py_datetime()
327
+ case PlainDateTime() as date_time:
328
+ obj_use = date_time.round().py_datetime()
325
329
  fmt_use = "%Y%m%dT%H%M%S" if fmt is None else fmt
326
- case ZonedDateTime() as datetime:
327
- return f"{format_compact(datetime.to_plain(), fmt=fmt)}[{datetime.tz}]"
330
+ case ZonedDateTime() as date_time:
331
+ plain = format_compact(date_time.to_plain(), fmt=fmt)
332
+ tz = date_time.tz
333
+ if path:
334
+ tz = tz.replace("/", "~")
335
+ return f"{plain}[{tz}]"
328
336
  case never:
329
337
  assert_never(never)
330
338
  return obj_use.strftime(get_strftime(fmt_use))
@@ -352,7 +360,7 @@ def from_timestamp_nanos(i: int, /, *, time_zone: TimeZoneLike = UTC) -> ZonedDa
352
360
 
353
361
 
354
362
  def get_now(time_zone: TimeZoneLike = UTC, /) -> ZonedDateTime:
355
- """Get the current zoned datetime."""
363
+ """Get the current zoned date-time."""
356
364
  return ZonedDateTime.now(to_time_zone_name(time_zone))
357
365
 
358
366
 
@@ -360,7 +368,7 @@ NOW_UTC = get_now(UTC)
360
368
 
361
369
 
362
370
  def get_now_local() -> ZonedDateTime:
363
- """Get the current local time."""
371
+ """Get the current local date-time."""
364
372
  return get_now(LOCAL_TIME_ZONE)
365
373
 
366
374
 
@@ -368,13 +376,21 @@ NOW_LOCAL = get_now_local()
368
376
 
369
377
 
370
378
  def get_now_plain(time_zone: TimeZoneLike = UTC, /) -> PlainDateTime:
371
- """Get the current zoned datetime."""
379
+ """Get the current date-time as a plain date-time."""
372
380
  return get_now(time_zone).to_plain()
373
381
 
374
382
 
375
383
  NOW_PLAIN = get_now_plain()
376
384
 
377
385
 
386
+ def get_now_local_plain() -> PlainDateTime:
387
+ """Get the current local date-time as a plain date-time."""
388
+ return get_now_local().to_plain()
389
+
390
+
391
+ NOW_LOCAL_PLAIN = get_now_local_plain()
392
+
393
+
378
394
  ##
379
395
 
380
396
 
@@ -1014,19 +1030,6 @@ class _ToHoursNanosecondsError(ToHoursError):
1014
1030
  ##
1015
1031
 
1016
1032
 
1017
- def to_local_plain(date_time: ZonedDateTime, /) -> str:
1018
- """Convert a datetime to its local/plain variant."""
1019
- return format_compact(date_time.to_tz(LOCAL_TIME_ZONE_NAME).to_plain())
1020
-
1021
-
1022
- def parse_plain_local(text: str, /) -> ZonedDateTime:
1023
- """Parse a plain, local datetime."""
1024
- return PlainDateTime.parse_common_iso(text).assume_tz(LOCAL_TIME_ZONE_NAME)
1025
-
1026
-
1027
- ##
1028
-
1029
-
1030
1033
  def to_microseconds(delta: Delta, /) -> int:
1031
1034
  """Compute the number of microseconds in a delta."""
1032
1035
  match delta:
@@ -1644,8 +1647,8 @@ def to_zoned_date_time(
1644
1647
  return sentinel
1645
1648
  case None:
1646
1649
  return get_now(UTC if time_zone is None else time_zone)
1647
- case str():
1648
- date_time_use = ZonedDateTime.parse_common_iso(date_time)
1650
+ case str() as text:
1651
+ date_time_use = ZonedDateTime.parse_common_iso(text.replace("~", "/"))
1649
1652
  case dt.datetime() as py_date_time:
1650
1653
  if isinstance(date_time.tzinfo, ZoneInfo):
1651
1654
  py_date_time_use = py_date_time
@@ -1925,6 +1928,7 @@ __all__ = [
1925
1928
  "MINUTE",
1926
1929
  "MONTH",
1927
1930
  "NOW_LOCAL",
1931
+ "NOW_LOCAL_PLAIN",
1928
1932
  "NOW_PLAIN",
1929
1933
  "SECOND",
1930
1934
  "TIME_DELTA_MAX",
@@ -1965,18 +1969,17 @@ __all__ = [
1965
1969
  "from_timestamp_nanos",
1966
1970
  "get_now",
1967
1971
  "get_now_local",
1972
+ "get_now_local_plain",
1968
1973
  "get_now_plain",
1969
1974
  "get_today",
1970
1975
  "get_today_local",
1971
1976
  "mean_datetime",
1972
1977
  "min_max_date",
1973
- "parse_plain_local",
1974
1978
  "round_date_or_date_time",
1975
1979
  "sub_year_month",
1976
1980
  "to_date",
1977
1981
  "to_date_time_delta",
1978
1982
  "to_days",
1979
- "to_local_plain",
1980
1983
  "to_microseconds",
1981
1984
  "to_milliseconds",
1982
1985
  "to_minutes",