dycw-utilities 0.131.11__py3-none-any.whl → 0.131.13__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.
utilities/period.py CHANGED
@@ -1,42 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime as dt
4
- from dataclasses import dataclass, field
5
- from functools import cached_property
6
- from itertools import permutations
7
- from typing import (
8
- TYPE_CHECKING,
9
- Generic,
10
- Literal,
11
- Self,
12
- TypedDict,
13
- TypeVar,
14
- assert_never,
15
- cast,
16
- override,
17
- )
18
-
19
- from utilities.datetime import ZERO_TIME
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Generic, Self, TypedDict, TypeVar, override
5
+ from zoneinfo import ZoneInfo
6
+
7
+ from whenever import Date, DateDelta, TimeDelta, ZonedDateTime
8
+
9
+ from utilities.dataclasses import replace_non_sentinel
20
10
  from utilities.functions import get_class_name
21
- from utilities.iterables import OneUniqueNonUniqueError, always_iterable, one_unique
22
11
  from utilities.sentinel import Sentinel, sentinel
23
- from utilities.typing import is_instance_gen
24
- from utilities.whenever import (
25
- serialize_date,
26
- serialize_plain_datetime,
27
- serialize_zoned_datetime,
28
- )
29
- from utilities.zoneinfo import EnsureTimeZoneError, ensure_time_zone
12
+ from utilities.zoneinfo import get_time_zone_name
30
13
 
31
14
  if TYPE_CHECKING:
32
- from zoneinfo import ZoneInfo
33
-
34
- from utilities.iterables import MaybeIterable
35
- from utilities.types import DateOrDateTime
15
+ from utilities.types import TimeZoneLike
36
16
 
37
-
38
- type _DateOrDateTime = Literal["date", "datetime"]
39
- _TPeriod = TypeVar("_TPeriod", dt.date, dt.datetime)
17
+ _TPeriod = TypeVar("_TPeriod", Date, ZonedDateTime)
40
18
 
41
19
 
42
20
  class _PeriodAsDict(TypedDict, Generic[_TPeriod]):
@@ -44,281 +22,133 @@ class _PeriodAsDict(TypedDict, Generic[_TPeriod]):
44
22
  end: _TPeriod
45
23
 
46
24
 
47
- @dataclass(repr=False, order=True, unsafe_hash=True)
48
- class Period(Generic[_TPeriod]):
49
- """A period of time."""
25
+ @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
26
+ class DatePeriod:
27
+ """A period of dates."""
50
28
 
51
- start: _TPeriod
52
- end: _TPeriod
53
- req_duration: MaybeIterable[dt.timedelta] | None = field(
54
- default=None, repr=False, kw_only=True
55
- )
56
- min_duration: dt.timedelta | None = field(default=None, repr=False, kw_only=True)
57
- max_duration: dt.timedelta | None = field(default=None, repr=False, kw_only=True)
29
+ start: Date
30
+ end: Date
58
31
 
59
32
  def __post_init__(self) -> None:
60
- if any(
61
- is_instance_gen(left, cls) is not is_instance_gen(right, cls)
62
- for left, right in permutations([self.start, self.end], 2)
63
- for cls in [dt.date, dt.datetime]
64
- ):
65
- raise _PeriodDateAndDateTimeMixedError(start=self.start, end=self.end)
66
- for date in [self.start, self.end]:
67
- if isinstance(date, dt.datetime):
68
- try:
69
- _ = ensure_time_zone(date)
70
- except EnsureTimeZoneError:
71
- raise _PeriodNaiveDateTimeError(
72
- start=self.start, end=self.end
73
- ) from None
74
- duration = self.end - self.start
75
- if duration < ZERO_TIME:
33
+ if self.start > self.end:
76
34
  raise _PeriodInvalidError(start=self.start, end=self.end)
77
- if (self.req_duration is not None) and (
78
- duration not in always_iterable(self.req_duration)
79
- ):
80
- raise _PeriodReqDurationError(
81
- start=self.start,
82
- end=self.end,
83
- duration=duration,
84
- req_duration=self.req_duration,
85
- )
86
- if (self.min_duration is not None) and (duration < self.min_duration):
87
- raise _PeriodMinDurationError(
88
- start=self.start,
89
- end=self.end,
90
- duration=duration,
91
- min_duration=self.min_duration,
92
- )
93
- if (self.max_duration is not None) and (duration > self.max_duration):
94
- raise _PeriodMaxDurationError(
95
- start=self.start,
96
- end=self.end,
97
- duration=duration,
98
- max_duration=self.max_duration,
99
- )
100
35
 
101
- def __add__(self, other: dt.timedelta, /) -> Self:
36
+ def __add__(self, other: DateDelta, /) -> Self:
102
37
  """Offset the period."""
103
38
  return self.replace(start=self.start + other, end=self.end + other)
104
39
 
105
- def __contains__(self, other: DateOrDateTime, /) -> bool:
40
+ def __contains__(self, other: Date, /) -> bool:
106
41
  """Check if a date/datetime lies in the period."""
107
- match self.kind:
108
- case "date":
109
- if isinstance(other, dt.datetime):
110
- raise _PeriodDateContainsDateTimeError(
111
- start=self.start, end=self.end
112
- )
113
- case "datetime":
114
- if not isinstance(other, dt.datetime):
115
- raise _PeriodDateTimeContainsDateError(
116
- start=self.start, end=self.end
117
- )
118
- case _ as never:
119
- assert_never(never)
120
42
  return self.start <= other <= self.end
121
43
 
122
44
  @override
123
45
  def __repr__(self) -> str:
124
46
  cls = get_class_name(self)
125
- match self.kind:
126
- case "date":
127
- result = cast("Period[dt.date]", self)
128
- start, end = map(serialize_date, [result.start, result.end])
129
- return f"{cls}({start}, {end})"
130
- case "datetime":
131
- result = cast("Period[dt.datetime]", self)
132
- try:
133
- time_zone = result.time_zone
134
- except _PeriodTimeZoneNonUniqueError:
135
- start, end = map(
136
- serialize_zoned_datetime, [result.start, result.end]
137
- )
138
- return f"{cls}({start}, {end})"
139
- start, end = (
140
- serialize_plain_datetime(t.replace(tzinfo=None))
141
- for t in [result.start, result.end]
142
- )
143
- return f"{cls}({start}, {end}, {time_zone})"
144
- case _ as never:
145
- assert_never(never)
146
-
147
- def __sub__(self, other: dt.timedelta, /) -> Self:
47
+ return f"{cls}({self.start}, {self.end})"
48
+
49
+ def __sub__(self, other: DateDelta, /) -> Self:
148
50
  """Offset the period."""
149
51
  return self.replace(start=self.start - other, end=self.end - other)
150
52
 
151
- def astimezone(self, time_zone: ZoneInfo, /) -> Self:
152
- """Convert the timezone of the period, if it is a datetime period."""
153
- match self.kind:
154
- case "date":
155
- raise _PeriodAsTimeZoneInapplicableError(start=self.start, end=self.end)
156
- case "datetime":
157
- result = cast("Period[dt.datetime]", self)
158
- result = result.replace(
159
- start=result.start.astimezone(time_zone),
160
- end=result.end.astimezone(time_zone),
161
- )
162
- return cast("Self", result)
163
- case _ as never:
164
- assert_never(never)
165
-
166
- @cached_property
167
- def duration(self) -> dt.timedelta:
168
- """The duration of the period."""
53
+ @property
54
+ def delta(self) -> DateDelta:
55
+ """The delta of the period."""
169
56
  return self.end - self.start
170
57
 
171
- @cached_property
172
- def kind(self) -> _DateOrDateTime:
173
- """The kind of the period."""
174
- return "date" if is_instance_gen(self.start, dt.date) else "datetime"
175
-
176
58
  def replace(
177
- self,
178
- *,
179
- start: _TPeriod | None = None,
180
- end: _TPeriod | None = None,
181
- req_duration: MaybeIterable[dt.timedelta] | None | Sentinel = sentinel,
182
- min_duration: dt.timedelta | None | Sentinel = sentinel,
183
- max_duration: dt.timedelta | None | Sentinel = sentinel,
59
+ self, *, start: Date | Sentinel = sentinel, end: Date | Sentinel = sentinel
184
60
  ) -> Self:
185
61
  """Replace elements of the period."""
186
- return type(self)(
187
- self.start if start is None else start,
188
- self.end if end is None else end,
189
- req_duration=self.req_duration
190
- if isinstance(req_duration, Sentinel)
191
- else req_duration,
192
- min_duration=self.min_duration
193
- if isinstance(min_duration, Sentinel)
194
- else min_duration,
195
- max_duration=self.max_duration
196
- if isinstance(max_duration, Sentinel)
197
- else max_duration,
198
- )
199
-
200
- @cached_property
201
- def time_zone(self) -> ZoneInfo:
202
- """The time zone of the period."""
203
- match self.kind:
204
- case "date":
205
- raise _PeriodTimeZoneInapplicableError(
206
- start=self.start, end=self.end
207
- ) from None
208
- case "datetime":
209
- result = cast("Period[dt.datetime]", self)
210
- try:
211
- return one_unique(map(ensure_time_zone, [result.start, result.end]))
212
- except OneUniqueNonUniqueError as error:
213
- raise _PeriodTimeZoneNonUniqueError(
214
- start=self.start,
215
- end=self.end,
216
- first=error.first,
217
- second=error.second,
218
- ) from None
219
- case _ as never:
220
- assert_never(never)
221
-
222
- def to_dict(self) -> _PeriodAsDict:
223
- """Convert the period to a dictionary."""
224
- return {"start": self.start, "end": self.end}
225
-
226
-
227
- @dataclass(kw_only=True, slots=True)
228
- class PeriodError(Generic[_TPeriod], Exception):
229
- start: _TPeriod
230
- end: _TPeriod
62
+ return replace_non_sentinel(self, start=start, end=end)
231
63
 
232
-
233
- @dataclass(kw_only=True, slots=True)
234
- class _PeriodDateAndDateTimeMixedError(PeriodError[_TPeriod]):
235
- @override
236
- def __str__(self) -> str:
237
- return f"Invalid period; got date and datetime mix ({self.start}, {self.end})"
64
+ def to_dict(self) -> _PeriodAsDict[Date]:
65
+ """Convert the period to a dictionary."""
66
+ return _PeriodAsDict(start=self.start, end=self.end)
238
67
 
239
68
 
240
- @dataclass(kw_only=True, slots=True)
241
- class _PeriodNaiveDateTimeError(PeriodError[_TPeriod]):
242
- @override
243
- def __str__(self) -> str:
244
- return f"Invalid period; got naive datetime(s) ({self.start}, {self.end})"
69
+ @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
70
+ class ZonedDateTimePeriod:
71
+ """A period of time."""
245
72
 
73
+ start: ZonedDateTime
74
+ end: ZonedDateTime
246
75
 
247
- @dataclass(kw_only=True, slots=True)
248
- class _PeriodInvalidError(PeriodError[_TPeriod]):
249
- @override
250
- def __str__(self) -> str:
251
- return f"Invalid period; got {self.start} > {self.end}"
76
+ def __post_init__(self) -> None:
77
+ if self.start > self.end:
78
+ raise _PeriodInvalidError(start=self.start, end=self.end)
79
+ if self.start.tz != self.end.tz:
80
+ raise _PeriodTimeZoneError(
81
+ start=ZoneInfo(self.start.tz), end=ZoneInfo(self.end.tz)
82
+ )
252
83
 
84
+ def __add__(self, other: TimeDelta, /) -> Self:
85
+ """Offset the period."""
86
+ return self.replace(start=self.start + other, end=self.end + other)
253
87
 
254
- @dataclass(kw_only=True, slots=True)
255
- class _PeriodReqDurationError(PeriodError[_TPeriod]):
256
- duration: dt.timedelta
257
- req_duration: MaybeIterable[dt.timedelta]
88
+ def __contains__(self, other: ZonedDateTime, /) -> bool:
89
+ """Check if a date/datetime lies in the period."""
90
+ return self.start <= other <= self.end
258
91
 
259
92
  @override
260
- def __str__(self) -> str:
261
- return f"Period must have duration {self.req_duration}; got {self.duration})"
262
-
263
-
264
- @dataclass(kw_only=True, slots=True)
265
- class _PeriodMinDurationError(PeriodError[_TPeriod]):
266
- duration: dt.timedelta
267
- min_duration: dt.timedelta
93
+ def __repr__(self) -> str:
94
+ cls = get_class_name(self)
95
+ return f"{cls}({self.start.to_plain()}, {self.end.to_plain()}[{self.time_zone.key}])"
268
96
 
269
- @override
270
- def __str__(self) -> str:
271
- return (
272
- f"Period must have min duration {self.min_duration}; got {self.duration})"
273
- )
97
+ def __sub__(self, other: TimeDelta, /) -> Self:
98
+ """Offset the period."""
99
+ return self.replace(start=self.start - other, end=self.end - other)
274
100
 
101
+ @property
102
+ def delta(self) -> TimeDelta:
103
+ """The duration of the period."""
104
+ return self.end - self.start
275
105
 
276
- @dataclass(kw_only=True, slots=True)
277
- class _PeriodMaxDurationError(PeriodError[_TPeriod]):
278
- duration: dt.timedelta
279
- max_duration: dt.timedelta
106
+ def replace(
107
+ self,
108
+ *,
109
+ start: ZonedDateTime | Sentinel = sentinel,
110
+ end: ZonedDateTime | Sentinel = sentinel,
111
+ ) -> Self:
112
+ """Replace elements of the period."""
113
+ return replace_non_sentinel(self, start=start, end=end)
280
114
 
281
- @override
282
- def __str__(self) -> str:
283
- return f"Period must have duration at most {self.max_duration}; got {self.duration})"
115
+ @property
116
+ def time_zone(self) -> ZoneInfo:
117
+ """The time zone of the period."""
118
+ return ZoneInfo(self.start.tz)
284
119
 
120
+ def to_dict(self) -> _PeriodAsDict[ZonedDateTime]:
121
+ """Convert the period to a dictionary."""
122
+ return _PeriodAsDict(start=self.start, end=self.end)
285
123
 
286
- @dataclass(kw_only=True, slots=True)
287
- class _PeriodAsTimeZoneInapplicableError(PeriodError[_TPeriod]):
288
- @override
289
- def __str__(self) -> str:
290
- return "Period of dates does not have a timezone attribute"
124
+ def to_tz(self, time_zone: TimeZoneLike, /) -> Self:
125
+ """Convert the time zone."""
126
+ tz = get_time_zone_name(time_zone)
127
+ return self.replace(start=self.start.to_tz(tz), end=self.end.to_tz(tz))
291
128
 
292
129
 
293
130
  @dataclass(kw_only=True, slots=True)
294
- class _PeriodDateContainsDateTimeError(PeriodError[_TPeriod]):
295
- @override
296
- def __str__(self) -> str:
297
- return "Period of dates cannot contain datetimes"
131
+ class PeriodError(Exception): ...
298
132
 
299
133
 
300
134
  @dataclass(kw_only=True, slots=True)
301
- class _PeriodDateTimeContainsDateError(PeriodError[_TPeriod]):
302
- @override
303
- def __str__(self) -> str:
304
- return "Period of datetimes cannot contain dates"
305
-
135
+ class _PeriodInvalidError(PeriodError, Generic[_TPeriod]):
136
+ start: _TPeriod
137
+ end: _TPeriod
306
138
 
307
- @dataclass(kw_only=True, slots=True)
308
- class _PeriodTimeZoneInapplicableError(PeriodError[_TPeriod]):
309
139
  @override
310
140
  def __str__(self) -> str:
311
- return "Period of dates does not have a timezone attribute"
141
+ return f"Invalid period; got {self.start} > {self.end}"
312
142
 
313
143
 
314
144
  @dataclass(kw_only=True, slots=True)
315
- class _PeriodTimeZoneNonUniqueError(PeriodError[_TPeriod]):
316
- first: ZoneInfo
317
- second: ZoneInfo
145
+ class _PeriodTimeZoneError(PeriodError):
146
+ start: ZoneInfo
147
+ end: ZoneInfo
318
148
 
319
149
  @override
320
150
  def __str__(self) -> str:
321
- return f"Period must contain exactly one time zone; got {self.first} and {self.second}"
151
+ return f"Period must contain exactly one time zone; got {self.start} and {self.end}"
322
152
 
323
153
 
324
- __all__ = ["Period", "PeriodError"]
154
+ __all__ = ["DatePeriod", "PeriodError", "ZonedDateTimePeriod"]
utilities/pyinstrument.py CHANGED
@@ -7,9 +7,8 @@ from typing import TYPE_CHECKING
7
7
  from pyinstrument.profiler import Profiler
8
8
 
9
9
  from utilities.atomicwrites import writer
10
- from utilities.datetime import serialize_compact
11
10
  from utilities.pathlib import get_path
12
- from utilities.tzlocal import get_now_local
11
+ from utilities.whenever2 import format_compact, get_now
13
12
 
14
13
  if TYPE_CHECKING:
15
14
  from collections.abc import Iterator
@@ -23,7 +22,7 @@ def profile(*, path: MaybeCallablePathLike | None = Path.cwd) -> Iterator[None]:
23
22
  with Profiler() as profiler:
24
23
  yield
25
24
  filename = get_path(path=path).joinpath(
26
- f"profile__{serialize_compact(get_now_local())}.html"
25
+ f"profile__{format_compact(get_now())}.html"
27
26
  )
28
27
  with writer(filename) as temp, temp.open(mode="w") as fh:
29
28
  _ = fh.write(profiler.output_html())
utilities/traceback.py CHANGED
@@ -14,7 +14,6 @@ from traceback import TracebackException
14
14
  from typing import TYPE_CHECKING, override
15
15
 
16
16
  from utilities.atomicwrites import writer
17
- from utilities.datetime import get_datetime, get_now, serialize_compact
18
17
  from utilities.errors import repr_error
19
18
  from utilities.iterables import OneEmptyError, one
20
19
  from utilities.pathlib import get_path
@@ -27,16 +26,19 @@ from utilities.reprlib import (
27
26
  RICH_MAX_WIDTH,
28
27
  yield_mapping_repr,
29
28
  )
30
- from utilities.tzlocal import get_local_time_zone, get_now_local
31
29
  from utilities.version import get_version
32
- from utilities.whenever import serialize_duration, serialize_zoned_datetime
30
+ from utilities.whenever2 import format_compact, get_now, to_zoned_date_time
33
31
 
34
32
  if TYPE_CHECKING:
35
33
  from collections.abc import Callable, Iterator, Sequence
36
34
  from traceback import FrameSummary
37
35
  from types import TracebackType
38
36
 
39
- from utilities.types import MaybeCallablePathLike, MaybeCallablePyDateTime, PathLike
37
+ from utilities.types import (
38
+ MaybeCallablePathLike,
39
+ MaybeCallableZonedDateTime,
40
+ PathLike,
41
+ )
40
42
  from utilities.version import MaybeCallableVersionLike
41
43
 
42
44
 
@@ -51,7 +53,7 @@ def format_exception_stack(
51
53
  /,
52
54
  *,
53
55
  header: bool = False,
54
- start: MaybeCallablePyDateTime | None = _START,
56
+ start: MaybeCallableZonedDateTime | None = _START,
55
57
  version: MaybeCallableVersionLike | None = None,
56
58
  capture_locals: bool = False,
57
59
  max_width: int = RICH_MAX_WIDTH,
@@ -82,21 +84,18 @@ def format_exception_stack(
82
84
 
83
85
  def _yield_header_lines(
84
86
  *,
85
- start: MaybeCallablePyDateTime | None = _START,
87
+ start: MaybeCallableZonedDateTime | None = _START,
86
88
  version: MaybeCallableVersionLike | None = None,
87
89
  ) -> Iterator[str]:
88
90
  """Yield the header lines."""
89
- now = get_now_local()
90
- start_use = get_datetime(datetime=start)
91
- start_use = (
92
- None if start_use is None else start_use.astimezone(get_local_time_zone())
93
- )
94
- yield f"Date/time | {serialize_zoned_datetime(now)}"
95
- start_str = "" if start_use is None else serialize_zoned_datetime(start_use)
91
+ now = get_now()
92
+ start_use = to_zoned_date_time(date_time=start)
93
+ yield f"Date/time | {format_compact(now)}"
94
+ start_str = "" if start_use is None else format_compact(start_use)
96
95
  yield f"Started | {start_str}"
97
- duration = None if start_use is None else (now - start_use)
98
- duration_str = "" if duration is None else serialize_duration(duration)
99
- yield f"Duration | {duration_str}"
96
+ delta = None if start_use is None else (now - start_use)
97
+ delta_str = "" if delta is None else delta.format_common_iso()
98
+ yield f"Duration | {delta_str}"
100
99
  yield f"User | {getuser()}"
101
100
  yield f"Host | {gethostname()}"
102
101
  version_use = "" if version is None else get_version(version=version)
@@ -193,7 +192,7 @@ def _trim_path(path: PathLike, pattern: str, /) -> Path | None:
193
192
 
194
193
  def make_except_hook(
195
194
  *,
196
- start: MaybeCallablePyDateTime | None = _START,
195
+ start: MaybeCallableZonedDateTime | None = _START,
197
196
  version: MaybeCallableVersionLike | None = None,
198
197
  path: MaybeCallablePathLike | None = None,
199
198
  max_width: int = RICH_MAX_WIDTH,
@@ -228,7 +227,7 @@ def _make_except_hook_inner(
228
227
  traceback: TracebackType | None,
229
228
  /,
230
229
  *,
231
- start: MaybeCallablePyDateTime | None = _START,
230
+ start: MaybeCallableZonedDateTime | None = _START,
232
231
  version: MaybeCallableVersionLike | None = None,
233
232
  path: MaybeCallablePathLike | None = None,
234
233
  max_width: int = RICH_MAX_WIDTH,
@@ -247,9 +246,7 @@ def _make_except_hook_inner(
247
246
  _ = sys.stderr.write(f"{slim}\n") # don't 'from sys import stderr'
248
247
  if path is not None:
249
248
  path = (
250
- get_path(path=path)
251
- .joinpath(serialize_compact(get_now_local()))
252
- .with_suffix(".txt")
249
+ get_path(path=path).joinpath(format_compact(get_now())).with_suffix(".txt")
253
250
  )
254
251
  full = format_exception_stack(
255
252
  exc_val,
utilities/typing.py CHANGED
@@ -25,6 +25,16 @@ from typing import get_type_hints as _get_type_hints
25
25
  from uuid import UUID
26
26
  from warnings import warn
27
27
 
28
+ from whenever import (
29
+ Date,
30
+ DateDelta,
31
+ DateTimeDelta,
32
+ PlainDateTime,
33
+ Time,
34
+ TimeDelta,
35
+ ZonedDateTime,
36
+ )
37
+
28
38
  from utilities.iterables import unique_everseen
29
39
  from utilities.sentinel import Sentinel
30
40
  from utilities.types import StrMapping
@@ -133,7 +143,21 @@ def get_type_hints(
133
143
  ) -> dict[str, Any]:
134
144
  """Get the type hints of an object."""
135
145
  result: dict[str, Any] = obj.__annotations__
136
- _ = {Literal, Path, Sentinel, StrMapping, UUID, dt}
146
+ _ = {
147
+ Date,
148
+ DateDelta,
149
+ DateTimeDelta,
150
+ Literal,
151
+ Path,
152
+ PlainDateTime,
153
+ Sentinel,
154
+ StrMapping,
155
+ Time,
156
+ TimeDelta,
157
+ UUID,
158
+ ZonedDateTime,
159
+ dt,
160
+ }
137
161
  globalns_use = globals() | ({} if globalns is None else dict(globalns))
138
162
  localns_use = {} if localns is None else dict(localns)
139
163
  try:
utilities/tzdata.py CHANGED
@@ -1,63 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
4
3
  from zoneinfo import ZoneInfo
5
4
 
6
- from utilities.datetime import get_now, get_today
7
-
8
- if TYPE_CHECKING:
9
- import datetime as dt
10
-
11
-
12
5
  HongKong = ZoneInfo("Asia/Hong_Kong")
13
6
  Tokyo = ZoneInfo("Asia/Tokyo")
14
7
  USCentral = ZoneInfo("US/Central")
15
8
  USEastern = ZoneInfo("US/Eastern")
16
9
 
17
10
 
18
- def get_now_hong_kong() -> dt.datetime:
19
- """Get the current time in Hong Kong."""
20
- return get_now(time_zone=HongKong)
21
-
22
-
23
- NOW_HONG_KONG = get_now_hong_kong()
24
-
25
-
26
- def get_now_tokyo() -> dt.datetime:
27
- """Get the current time in Tokyo."""
28
- return get_now(time_zone=Tokyo)
29
-
30
-
31
- NOW_TOKYO = get_now_tokyo()
32
-
33
-
34
- def get_today_hong_kong() -> dt.date:
35
- """Get the current date in Hong Kong."""
36
- return get_today(time_zone=HongKong)
37
-
38
-
39
- TODAY_HONG_KONG = get_today_hong_kong()
40
-
41
-
42
- def get_today_tokyo() -> dt.date:
43
- """Get the current date in Tokyo."""
44
- return get_today(time_zone=Tokyo)
45
-
46
-
47
- TODAY_TOKYO = get_today_tokyo()
48
-
49
-
50
- __all__ = [
51
- "NOW_HONG_KONG",
52
- "NOW_TOKYO",
53
- "TODAY_HONG_KONG",
54
- "TODAY_TOKYO",
55
- "HongKong",
56
- "Tokyo",
57
- "USCentral",
58
- "USEastern",
59
- "get_now_hong_kong",
60
- "get_now_tokyo",
61
- "get_today_hong_kong",
62
- "get_today_tokyo",
63
- ]
11
+ __all__ = ["HongKong", "Tokyo", "USCentral", "USEastern"]
utilities/tzlocal.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime as dt
4
3
  from logging import getLogger
5
4
  from typing import TYPE_CHECKING
6
5
 
@@ -21,30 +20,7 @@ def get_local_time_zone() -> ZoneInfo:
21
20
 
22
21
 
23
22
  LOCAL_TIME_ZONE = get_local_time_zone()
23
+ LOCAL_TIME_ZONE_NAME = LOCAL_TIME_ZONE.key
24
24
 
25
25
 
26
- def get_now_local() -> dt.datetime:
27
- """Get the current local time."""
28
- return dt.datetime.now(tz=LOCAL_TIME_ZONE)
29
-
30
-
31
- NOW_LOCAL = get_now_local()
32
-
33
-
34
- def get_today_local() -> dt.date:
35
- """Get the current, timezone-aware local date."""
36
- return get_now_local().date()
37
-
38
-
39
- TODAY_LOCAL = get_today_local()
40
-
41
-
42
- __all__ = [
43
- "LOCAL_TIME_ZONE",
44
- "LOCAL_TIME_ZONE",
45
- "NOW_LOCAL",
46
- "TODAY_LOCAL",
47
- "get_local_time_zone",
48
- "get_now_local",
49
- "get_today_local",
50
- ]
26
+ __all__ = ["LOCAL_TIME_ZONE", "LOCAL_TIME_ZONE_NAME", "get_local_time_zone"]