-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathcorrect_datetime.py
More file actions
111 lines (94 loc) · 3.88 KB
/
Copy pathcorrect_datetime.py
File metadata and controls
111 lines (94 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "ipetrash"
from datetime import datetime, date, timedelta
# Текущий день может отсутствовать, поэтому ищем ближайший день
# Например, если день 31, то ищем ближайший день 30
def correct_datetime(
dt: datetime | date,
target_year: int,
target_month: int,
target_day: int | None = None,
) -> datetime | date:
# TODO: Можно ли упростить проверку, начиная ее для дня больше 28?
# target_day больше нужен для случаев, если день больше 28
# Можно явно перебирать дни вместе с месяцем и годом
while True:
try:
dt = dt.replace(year=target_year, month=target_month)
break
except ValueError:
dt -= timedelta(days=1)
if target_day is not None:
# Попробуем сразу указать target_day
try:
return dt.replace(day=target_day)
except ValueError:
pass
# Стараемся найти день, ближайший к target_day
start_day = min(dt.day, target_day)
end_day = max(dt.day, target_day)
for day in reversed(range(start_day, end_day + 1)):
try:
return dt.replace(day=day)
except ValueError:
pass
return dt
if __name__ == "__main__":
dt = datetime(year=2023, month=1, day=1, hour=12, minute=34, second=56)
assert isinstance(
correct_datetime(dt, target_year=2023, target_month=1),
datetime,
)
assert isinstance(
correct_datetime(dt.date(), target_year=2023, target_month=1),
date,
)
assert correct_datetime(dt, dt.year, dt.month, dt.day) == dt
assert correct_datetime(dt, dt.year, dt.month, dt.day + 1) == dt.replace(
day=dt.day + 1
)
assert correct_datetime(dt.date(), dt.year, dt.month, dt.day) == dt.date()
assert correct_datetime(
dt.date(), dt.year, dt.month, dt.day + 1
) == dt.date().replace(day=dt.day + 1)
assert correct_datetime(
datetime(year=2023, month=1, day=1, hour=12, minute=34, second=56),
target_year=2025,
target_month=4,
) == datetime(year=2025, month=4, day=1, hour=12, minute=34, second=56)
assert correct_datetime(
datetime(year=2023, month=1, day=1, hour=12, minute=34, second=56),
target_year=2025,
target_month=4,
target_day=30,
) == datetime(year=2025, month=4, day=30, hour=12, minute=34, second=56)
assert correct_datetime(
datetime(year=2023, month=1, day=1, hour=12, minute=34, second=56),
target_year=2025,
target_month=4,
target_day=99,
) == datetime(year=2025, month=4, day=30, hour=12, minute=34, second=56)
# Leap year
assert correct_datetime(
datetime(year=2024, month=2, day=29, hour=12, minute=34, second=56),
target_year=2025,
target_month=2,
) == datetime(year=2025, month=2, day=28, hour=12, minute=34, second=56)
assert correct_datetime(
datetime(year=2024, month=1, day=31, hour=12, minute=34, second=56),
target_year=2024,
target_month=2,
) == datetime(year=2024, month=2, day=29, hour=12, minute=34, second=56)
assert correct_datetime(
datetime(year=2024, month=1, day=31, hour=12, minute=34, second=56),
target_year=2024,
target_month=2,
target_day=28,
) == datetime(year=2024, month=2, day=28, hour=12, minute=34, second=56)
assert correct_datetime(
datetime(year=2024, month=2, day=28, hour=12, minute=34, second=56),
target_year=2024,
target_month=1,
target_day=31,
) == datetime(year=2024, month=1, day=31, hour=12, minute=34, second=56)