Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pendulum/helpers.py: 39%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import annotations
3import os
4import struct
6from datetime import date
7from datetime import datetime
8from datetime import timedelta
9from math import copysign
10from typing import TYPE_CHECKING
11from typing import TypeVar
12from typing import overload
14import pendulum
16from pendulum.constants import DAYS_PER_MONTHS
17from pendulum.day import WeekDay
18from pendulum.formatting.difference_formatter import DifferenceFormatter
19from pendulum.locales.locale import Locale
22if TYPE_CHECKING:
23 # Prevent import cycles
24 from pendulum.duration import Duration
26with_extensions = os.getenv("PENDULUM_EXTENSIONS", "1") == "1"
28_DT = TypeVar("_DT", bound=datetime)
29_D = TypeVar("_D", bound=date)
31try:
32 if not with_extensions or struct.calcsize("P") == 4:
33 raise ImportError()
35 from pendulum._pendulum import PreciseDiff
36 from pendulum._pendulum import days_in_year
37 from pendulum._pendulum import is_leap
38 from pendulum._pendulum import is_long_year
39 from pendulum._pendulum import local_time
40 from pendulum._pendulum import precise_diff
41 from pendulum._pendulum import week_day
42except ImportError:
43 from pendulum._helpers import PreciseDiff # type: ignore[assignment]
44 from pendulum._helpers import days_in_year
45 from pendulum._helpers import is_leap
46 from pendulum._helpers import is_long_year
47 from pendulum._helpers import local_time
48 from pendulum._helpers import precise_diff # type: ignore[assignment]
49 from pendulum._helpers import week_day
51difference_formatter = DifferenceFormatter()
54@overload
55def add_duration(
56 dt: _DT,
57 years: int = 0,
58 months: int = 0,
59 weeks: int = 0,
60 days: int = 0,
61 hours: int = 0,
62 minutes: int = 0,
63 seconds: float = 0,
64 microseconds: int = 0,
65) -> _DT: ...
68@overload
69def add_duration(
70 dt: _D,
71 years: int = 0,
72 months: int = 0,
73 weeks: int = 0,
74 days: int = 0,
75) -> _D:
76 pass
79def add_duration(
80 dt: date | datetime,
81 years: int = 0,
82 months: int = 0,
83 weeks: int = 0,
84 days: int = 0,
85 hours: int = 0,
86 minutes: int = 0,
87 seconds: float = 0,
88 microseconds: int = 0,
89) -> date | datetime:
90 """
91 Adds a duration to a date/datetime instance.
92 """
93 days += weeks * 7
95 if (
96 isinstance(dt, date)
97 and not isinstance(dt, datetime)
98 and any([hours, minutes, seconds, microseconds])
99 ):
100 raise RuntimeError("Time elements cannot be added to a date instance.")
102 # Normalizing
103 if abs(microseconds) > 999999:
104 s = _sign(microseconds)
105 div, mod = divmod(microseconds * s, 1000000)
106 microseconds = mod * s
107 seconds += div * s
109 if abs(seconds) > 59:
110 s = _sign(seconds)
111 div, mod = divmod(seconds * s, 60) # type: ignore[assignment]
112 seconds = mod * s
113 minutes += div * s
115 if abs(minutes) > 59:
116 s = _sign(minutes)
117 div, mod = divmod(minutes * s, 60)
118 minutes = mod * s
119 hours += div * s
121 if abs(hours) > 23:
122 s = _sign(hours)
123 div, mod = divmod(hours * s, 24)
124 hours = mod * s
125 days += div * s
127 if abs(months) > 11:
128 s = _sign(months)
129 div, mod = divmod(months * s, 12)
130 months = mod * s
131 years += div * s
133 year = dt.year + years
134 month = dt.month
136 if months:
137 month += months
138 if month > 12:
139 year += 1
140 month -= 12
141 elif month < 1:
142 year -= 1
143 month += 12
145 day = min(DAYS_PER_MONTHS[int(is_leap(year))][month], dt.day)
147 dt = dt.replace(year=year, month=month, day=day)
149 return dt + timedelta(
150 days=days,
151 hours=hours,
152 minutes=minutes,
153 seconds=seconds,
154 microseconds=microseconds,
155 )
158def format_diff(
159 diff: Duration,
160 is_now: bool = True,
161 absolute: bool = False,
162 locale: str | None = None,
163) -> str:
164 if locale is None:
165 locale = get_locale()
167 return difference_formatter.format(diff, is_now, absolute, locale)
170def _sign(x: float) -> int:
171 return int(copysign(1, x))
174# Global helpers
177def locale(name: str) -> Locale:
178 return Locale.load(name)
181def set_locale(name: str) -> None:
182 locale(name)
184 pendulum._LOCALE = name
187def get_locale() -> str:
188 return pendulum._LOCALE
191def week_starts_at(wday: WeekDay) -> None:
192 if wday < WeekDay.MONDAY or wday > WeekDay.SUNDAY:
193 raise ValueError("Invalid day of week")
195 pendulum._WEEK_STARTS_AT = wday
198def week_ends_at(wday: WeekDay) -> None:
199 if wday < WeekDay.MONDAY or wday > WeekDay.SUNDAY:
200 raise ValueError("Invalid day of week")
202 pendulum._WEEK_ENDS_AT = wday
205__all__ = [
206 "PreciseDiff",
207 "add_duration",
208 "days_in_year",
209 "format_diff",
210 "get_locale",
211 "is_leap",
212 "is_long_year",
213 "local_time",
214 "locale",
215 "precise_diff",
216 "set_locale",
217 "week_day",
218 "week_ends_at",
219 "week_starts_at",
220]