Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pendulum/helpers.py: 39%

122 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1from __future__ import absolute_import 

2 

3import os 

4import struct 

5 

6from contextlib import contextmanager 

7from datetime import date 

8from datetime import datetime 

9from datetime import timedelta 

10from math import copysign 

11from typing import TYPE_CHECKING 

12from typing import Iterator 

13from typing import Optional 

14from typing import TypeVar 

15from typing import overload 

16 

17import pendulum 

18 

19from .constants import DAYS_PER_MONTHS 

20from .formatting.difference_formatter import DifferenceFormatter 

21from .locales.locale import Locale 

22 

23 

24if TYPE_CHECKING: 

25 # Prevent import cycles 

26 from .period import Period 

27 

28with_extensions = os.getenv("PENDULUM_EXTENSIONS", "1") == "1" 

29 

30_DT = TypeVar("_DT", bound=datetime) 

31_D = TypeVar("_D", bound=date) 

32 

33try: 

34 if not with_extensions or struct.calcsize("P") == 4: 

35 raise ImportError() 

36 

37 from ._extensions._helpers import local_time 

38 from ._extensions._helpers import precise_diff 

39 from ._extensions._helpers import is_leap 

40 from ._extensions._helpers import is_long_year 

41 from ._extensions._helpers import week_day 

42 from ._extensions._helpers import days_in_year 

43 from ._extensions._helpers import timestamp 

44except ImportError: 

45 from ._extensions.helpers import local_time # noqa 

46 from ._extensions.helpers import precise_diff # noqa 

47 from ._extensions.helpers import is_leap # noqa 

48 from ._extensions.helpers import is_long_year # noqa 

49 from ._extensions.helpers import week_day # noqa 

50 from ._extensions.helpers import days_in_year # noqa 

51 from ._extensions.helpers import timestamp # noqa 

52 

53 

54difference_formatter = DifferenceFormatter() 

55 

56 

57@overload 

58def add_duration( 

59 dt, # type: _DT 

60 years=0, # type: int 

61 months=0, # type: int 

62 weeks=0, # type: int 

63 days=0, # type: int 

64 hours=0, # type: int 

65 minutes=0, # type: int 

66 seconds=0, # type: int 

67 microseconds=0, # type: int 

68): # type: (...) -> _DT 

69 pass 

70 

71 

72@overload 

73def add_duration( 

74 dt, # type: _D 

75 years=0, # type: int 

76 months=0, # type: int 

77 weeks=0, # type: int 

78 days=0, # type: int 

79): # type: (...) -> _D 

80 pass 

81 

82 

83def add_duration( 

84 dt, 

85 years=0, 

86 months=0, 

87 weeks=0, 

88 days=0, 

89 hours=0, 

90 minutes=0, 

91 seconds=0, 

92 microseconds=0, 

93): 

94 """ 

95 Adds a duration to a date/datetime instance. 

96 """ 

97 days += weeks * 7 

98 

99 if ( 

100 isinstance(dt, date) 

101 and not isinstance(dt, datetime) 

102 and any([hours, minutes, seconds, microseconds]) 

103 ): 

104 raise RuntimeError("Time elements cannot be added to a date instance.") 

105 

106 # Normalizing 

107 if abs(microseconds) > 999999: 

108 s = _sign(microseconds) 

109 div, mod = divmod(microseconds * s, 1000000) 

110 microseconds = mod * s 

111 seconds += div * s 

112 

113 if abs(seconds) > 59: 

114 s = _sign(seconds) 

115 div, mod = divmod(seconds * s, 60) 

116 seconds = mod * s 

117 minutes += div * s 

118 

119 if abs(minutes) > 59: 

120 s = _sign(minutes) 

121 div, mod = divmod(minutes * s, 60) 

122 minutes = mod * s 

123 hours += div * s 

124 

125 if abs(hours) > 23: 

126 s = _sign(hours) 

127 div, mod = divmod(hours * s, 24) 

128 hours = mod * s 

129 days += div * s 

130 

131 if abs(months) > 11: 

132 s = _sign(months) 

133 div, mod = divmod(months * s, 12) 

134 months = mod * s 

135 years += div * s 

136 

137 year = dt.year + years 

138 month = dt.month 

139 

140 if months: 

141 month += months 

142 if month > 12: 

143 year += 1 

144 month -= 12 

145 elif month < 1: 

146 year -= 1 

147 month += 12 

148 

149 day = min(DAYS_PER_MONTHS[int(is_leap(year))][month], dt.day) 

150 

151 dt = dt.replace(year=year, month=month, day=day) 

152 

153 return dt + timedelta( 

154 days=days, 

155 hours=hours, 

156 minutes=minutes, 

157 seconds=seconds, 

158 microseconds=microseconds, 

159 ) 

160 

161 

162def format_diff( 

163 diff, is_now=True, absolute=False, locale=None 

164): # type: (Period, bool, bool, Optional[str]) -> str 

165 if locale is None: 

166 locale = get_locale() 

167 

168 return difference_formatter.format(diff, is_now, absolute, locale) 

169 

170 

171def _sign(x): 

172 return int(copysign(1, x)) 

173 

174 

175# Global helpers 

176 

177 

178@contextmanager 

179def test(mock): # type: (pendulum.DateTime) -> Iterator[None] 

180 set_test_now(mock) 

181 try: 

182 yield 

183 finally: 

184 set_test_now() 

185 

186 

187def set_test_now(test_now=None): # type: (Optional[pendulum.DateTime]) -> None 

188 pendulum._TEST_NOW = test_now 

189 

190 

191def get_test_now(): # type: () -> Optional[pendulum.DateTime] 

192 return pendulum._TEST_NOW 

193 

194 

195def has_test_now(): # type: () -> bool 

196 return pendulum._TEST_NOW is not None 

197 

198 

199def locale(name): # type: (str) -> Locale 

200 return Locale.load(name) 

201 

202 

203def set_locale(name): # type: (str) -> None 

204 locale(name) 

205 

206 pendulum._LOCALE = name 

207 

208 

209def get_locale(): # type: () -> str 

210 return pendulum._LOCALE 

211 

212 

213def week_starts_at(wday): # type: (int) -> None 

214 if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY: 

215 raise ValueError("Invalid week day as start of week.") 

216 

217 pendulum._WEEK_STARTS_AT = wday 

218 

219 

220def week_ends_at(wday): # type: (int) -> None 

221 if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY: 

222 raise ValueError("Invalid week day as start of week.") 

223 

224 pendulum._WEEK_ENDS_AT = wday