simple-dwd-weatherforecast 2.0.33__py3-none-any.whl → 2.1.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.
@@ -298,13 +298,15 @@ class Weather:
298
298
  return (
299
299
  self.strip_to_day(
300
300
  arrow.get(
301
- list(self.forecast_data.keys())[0], "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
301
+ list(self.forecast_data.keys())[0], # type: ignore
302
+ "YYYY-MM-DDTHH:mm:ss.SSSZ", # type: ignore
302
303
  ).datetime
303
304
  )
304
305
  <= self.strip_to_day(timestamp)
305
306
  <= self.strip_to_day(
306
307
  arrow.get(
307
- list(self.forecast_data.keys())[-1], "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
308
+ list(self.forecast_data.keys())[-1], # type: ignore
309
+ "YYYY-MM-DDTHH:mm:ss.SSSZ", # type: ignore
308
310
  ).datetime
309
311
  )
310
312
  )
@@ -358,7 +360,7 @@ class Weather:
358
360
  def get_daily_condition(self, timestamp: datetime, shouldUpdate=True):
359
361
  if shouldUpdate:
360
362
  self.update()
361
- if self.is_in_timerange(timestamp):
363
+ if self.is_in_timerange_day(timestamp):
362
364
  return self.get_condition(self.get_day_values(timestamp))
363
365
  return None
364
366
 
@@ -609,7 +611,8 @@ class Weather:
609
611
  "timestamp has to be checked prior to be in timerange"
610
612
  result = []
611
613
  first_entry_date = arrow.get(
612
- next(iter(self.forecast_data)), "YYYY-MM-DDTHH:mm:ss.SSSZ" # type: ignore
614
+ next(iter(self.forecast_data)), # type: ignore
615
+ "YYYY-MM-DDTHH:mm:ss.SSSZ", # type: ignore
613
616
  ).datetime # type: ignore
614
617
  if timestamp.day != first_entry_date.day:
615
618
  time_step = self.strip_to_day(timestamp)
@@ -1,8 +1,11 @@
1
+ from typing import Iterable
1
2
  import requests
2
3
  import math
3
4
  from io import BytesIO
4
- from PIL import Image
5
+ from PIL import Image, ImageFile
5
6
  from enum import Enum
7
+ from collections import deque
8
+ from datetime import datetime, timedelta, timezone
6
9
 
7
10
 
8
11
  class WeatherMapType(Enum):
@@ -25,6 +28,13 @@ class WeatherBackgroundMapType(Enum):
25
28
  GEWAESSER = "dwd:Gewaesser"
26
29
 
27
30
 
31
+ class germany_boundaries:
32
+ minx = 4.4
33
+ miny = 46.4
34
+ maxx = 16.1
35
+ maxy = 55.6
36
+
37
+
28
38
  def get_from_location(
29
39
  longitude,
30
40
  latitude,
@@ -60,7 +70,14 @@ def get_germany(
60
70
  image_height=580,
61
71
  ):
62
72
  return get_map(
63
- 4.4, 46.4, 16.1, 55.6, map_type, background_type, image_width, image_height
73
+ germany_boundaries.minx,
74
+ germany_boundaries.miny,
75
+ germany_boundaries.maxx,
76
+ germany_boundaries.maxy,
77
+ map_type,
78
+ background_type,
79
+ image_width,
80
+ image_height,
64
81
  )
65
82
 
66
83
 
@@ -83,3 +100,83 @@ def get_map(
83
100
  if request.status_code == 200:
84
101
  image = Image.open(BytesIO(request.content))
85
102
  return image
103
+
104
+
105
+ class ImageLoop:
106
+ _last_update: datetime
107
+ _images: deque[ImageFile.ImageFile]
108
+
109
+ _minx: float
110
+ _miny: float
111
+ _maxx: float
112
+ _maxy: float
113
+ _map_type: WeatherMapType
114
+ _background_type: WeatherBackgroundMapType
115
+ _image_width: int
116
+ _image_height: int
117
+
118
+ def __init__(
119
+ self,
120
+ minx: float,
121
+ miny: float,
122
+ maxx: float,
123
+ maxy: float,
124
+ map_type: WeatherMapType,
125
+ background_type: WeatherBackgroundMapType,
126
+ steps: int = 6,
127
+ image_width: int = 520,
128
+ image_height: int = 580,
129
+ ):
130
+ if image_width > 1200 or image_height > 1400:
131
+ raise ValueError(
132
+ "Width and height must not exceed 1200 and 1400 respectively. Please be kind to the DWD servers."
133
+ )
134
+ self._minx = minx
135
+ self._miny = miny
136
+ self._maxx = maxx
137
+ self._maxy = maxy
138
+ self._map_type = map_type
139
+ self._background_type = background_type
140
+ self._steps = steps
141
+ self._image_width = image_width
142
+ self._image_height = image_height
143
+
144
+ self._images = deque([], steps)
145
+
146
+ self._full_reload()
147
+
148
+ def get_images(self) -> Iterable[ImageFile.ImageFile]:
149
+ return self._images
150
+
151
+ def _full_reload(self):
152
+ self._images.clear()
153
+ now = get_time_last_5_min(datetime.now(timezone.utc))
154
+ self._last_update = now - timedelta(minutes=5) * self._steps
155
+
156
+ while now > self._last_update:
157
+ self._last_update += timedelta(minutes=5)
158
+ self._images.append(self._get_image(self._last_update))
159
+
160
+ def update(self):
161
+ now = get_time_last_5_min(datetime.now(timezone.utc))
162
+
163
+ # If last update is older than the buffer can hold, reload the whole buffer
164
+ if now - self._last_update > self._steps * timedelta(minutes=5):
165
+ self._full_reload()
166
+ # Update the buffer and fetch only the new images
167
+ else:
168
+ while now > self._last_update:
169
+ self._last_update += timedelta(minutes=5)
170
+ self._images.append(self._get_image(self._last_update))
171
+
172
+ def _get_image(self, date: datetime) -> ImageFile.ImageFile:
173
+ url = f"https://maps.dwd.de/geoserver/dwd/wms?service=WMS&version=1.1.0&request=GetMap&layers={self._map_type.value},{self._background_type.value}&bbox={self._minx},{self._miny},{self._maxx},{self._maxy}&width={self._image_width}&height={self._image_height}&srs=EPSG:4326&styles=&format=image/png&TIME={date.strftime("%Y-%m-%dT%H:%M:00.0Z")}"
174
+ request = requests.get(url, stream=True)
175
+ if request.status_code != 200:
176
+ raise ConnectionError("Error during image request from DWD servers")
177
+ return Image.open(BytesIO(request.content))
178
+
179
+
180
+ def get_time_last_5_min(date: datetime) -> datetime:
181
+ minute = math.floor(date.minute / 5) * 5
182
+ return date.replace(minute=minute, second=0, microsecond=0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simple_dwd_weatherforecast
3
- Version: 2.0.33
3
+ Version: 2.1.0
4
4
  Summary: A simple tool to retrieve a weather forecast from DWD OpenData
5
5
  Home-page: https://github.com/FL550/simple_dwd_weatherforecast.git
6
6
  Author: Max Fermor
@@ -198,13 +198,50 @@ class WeatherBackgroundMapType(Enum):
198
198
  GEMEINDEN = "dwd:Warngebiete_Gemeinden"
199
199
  SATELLIT = "dwd:bluemarble"
200
200
 
201
- def get_from_location(longitude, latitude, radius_km, map_type: WeatherMapType, background_type: WeatherBackgroundMapType, optional integer image_width, optional integer image_height) #Returns map as pillow image with given radius from coordinates
201
+ get_from_location(longitude, latitude, radius_km, map_type: WeatherMapType, background_type: WeatherBackgroundMapType, optional integer image_width, optional integer image_height) #Returns map as pillow image with given radius from coordinates
202
202
 
203
203
  get_germany(map_type: WeatherMapType, optional WeatherBackgroundMapType background_type, optional integer image_width, optional integer image_height, optional string save_to_filename) #Returns map as pillow image of whole germany
204
204
 
205
205
  get_map(minx,miny,maxx,maxy, map_type: WeatherMapType, background_type: WeatherBackgroundMapType, optional integer image_width, optional integer image_height, optional string save_to_filename) #Returns map as pillow image
206
206
  ```
207
207
 
208
+
209
+ ### Image loop
210
+
211
+ There is also the possibility to retrieve multiple images as a loop. This can be done by the class ImageLoop.
212
+
213
+
214
+ #### Usage example
215
+ ```python
216
+ from simple_dwd_weatherforecast import dwdmap
217
+
218
+ maploop = dwdmap.ImageLoop(
219
+ dwdmap.germany_boundaries.minx,
220
+ dwdmap.germany_boundaries.miny,
221
+ dwdmap.germany_boundaries.maxx,
222
+ dwdmap.germany_boundaries.maxy,
223
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
224
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
225
+ steps=5,
226
+ )
227
+
228
+ for image in enumerate(maploop._images):
229
+ image[1].save(f"image{image[0]}.png")
230
+
231
+ ```
232
+
233
+ #### Available methods
234
+
235
+ ```python
236
+ ImageLoop(minx: float, miny: float, maxx: float, maxy: float, map_type: WeatherMapType, background_type: WeatherBackgroundMapType,
237
+ steps: int = 6, image_width: int = 520,image_height: int = 580) -> ImageLoop
238
+
239
+ get_images() -> Iterable[ImageFile.ImageFile] # Returns the image loop
240
+
241
+ update() # Updates the loop to the most recent files
242
+
243
+ ```
244
+
208
245
  ## Help and Contribution
209
246
 
210
247
  Feel free to open an issue if you find one and I will do my best to help you. If you want to contribute, your help is appreciated! If you want to add a new feature, add a pull request first so we can chat about the details.
@@ -1,6 +1,6 @@
1
1
  simple_dwd_weatherforecast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- simple_dwd_weatherforecast/dwdforecast.py,sha256=4ZqQweWyXCMJ8NajdKV_Ca0WkbxrsJXKX7RD0lQayXU,36587
3
- simple_dwd_weatherforecast/dwdmap.py,sha256=fZMi3nk4MwzZm0dJ8TUwCgOuTw6t8kZmnOkoHGKpXx4,2695
2
+ simple_dwd_weatherforecast/dwdforecast.py,sha256=ctnQAFJS8UID9KZCXK7O5FyBTlgkqvoNLVJG5E3TkCY,36694
3
+ simple_dwd_weatherforecast/dwdmap.py,sha256=OpFbBgALHUcvuH95dzOxMPwb7eFGNX7OJJkNPRr0AB4,5954
4
4
  simple_dwd_weatherforecast/stations.json,sha256=1u8qc2CT_rVy49SAlOicGixzHln6Y0FXevuFAz2maBw,838948
5
5
  simple_dwd_weatherforecast/uv_stations.json,sha256=ADenYo-aR6qbf0UFkfYr72kkFzL9HyUKe4VQ23POGF8,2292
6
6
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -8,7 +8,7 @@ tests/dummy_data.py,sha256=sF8pXxq8innSpRc4lW0XxGcr34dESSAoBdAf2F2D4AI,63395
8
8
  tests/dummy_data_full.py,sha256=IwYoeqVX8cpfn_gE-7arXaWV9btRm_HHqka_LfKqW-E,64053
9
9
  tests/dummy_uv.py,sha256=TM1TwvNq_ea4WgIJyYsNAEXZJTx1dXH1ZVrW_LfLBLg,4548
10
10
  tests/test_get_daily_avg.py,sha256=MNd7u9Y7_E6SIyxg59EKfdKx4QJ7R_WT5wvRgm7Gzks,2315
11
- tests/test_get_daily_condition.py,sha256=foRgUO0W4ctWuer04RvUi2JqcFpiDBhFoLg9OdQSFj8,2004
11
+ tests/test_get_daily_condition.py,sha256=9Qrhv14-vLnLz0N0FWG7Mv6_iEbNPqrHDDWWNQNydU0,2298
12
12
  tests/test_get_daily_max.py,sha256=schjGJDflg1YEQSdfRndw2NT4AvrVheSDveyVZrFySM,2220
13
13
  tests/test_get_daily_min.py,sha256=GzqlOfLdwLqGLYVeAJ0fbK1JRq-_fT7z6Gea74lSY7E,2224
14
14
  tests/test_get_daily_sum.py,sha256=UEntbPwGSleHocu0587WnuC5ijptQtzVNreR1d6yoM0,2221
@@ -25,7 +25,7 @@ tests/test_get_timeframe_values.py,sha256=z8ozpWlyilw8-zjbk2gDExhTobNbgmcVTbZ6ZH
25
25
  tests/test_is_in_timerange.py,sha256=3y88L3N73NxSTJ-_edx6OCnxHWKJWWFma98gjZvJDGg,1338
26
26
  tests/test_is_valid_timeframe.py,sha256=mXjeu3lUyixiBUEljirTf6qDM_FZFQGWa-Rk0NBMUDU,891
27
27
  tests/test_location_tools.py,sha256=wto_XzVnARJQ-Qc83YAn0ahfMBSaOHpfzqAeKRDsNm8,1208
28
- tests/test_map.py,sha256=Bnf7XSap7xAfozE5U9aB0GjjMiHmXrpyJPE79VmEvFg,830
28
+ tests/test_map.py,sha256=uKxNjMXLFT3pczZKLqkfPK5xaVfmql-r5L9VPgCbS3Q,5671
29
29
  tests/test_parsekml.py,sha256=Y0EHJi5e8lqFUS8N9yfA5ByQkKV4-iyrwUaIipQpM7w,1065
30
30
  tests/test_region.py,sha256=ReUB9Cy9roBemkpEkTjZZav-Mu3Ha7ADOAfa9J-gi80,877
31
31
  tests/test_reported_weather.py,sha256=ULg4ogZRxus01p2rdxiSFL75AisqtcvnLDOc7uJMBH0,767
@@ -35,8 +35,8 @@ tests/test_update.py,sha256=r763R-MfqFqQQy43PcmE9yWAiQU6T2rQ1u55ujlwMt8,7216
35
35
  tests/test_update_hourly.py,sha256=mUc66JHndgIMdZ0DD_KXQTbPPg1g86F6CPUwJYjBV5U,1619
36
36
  tests/test_uv_index.py,sha256=tr6wnOyHlXT1S3yp1oeHc4-Brmc-EMEdM4mtyrdpcHg,579
37
37
  tests/test_weather.py,sha256=ZyX4ldUoJpJp7YpiNQwU6Od-nYRay-3qcaDJdNq8fhY,780
38
- simple_dwd_weatherforecast-2.0.33.dist-info/LICENCE,sha256=27UG7gteqvSWuZlsbIq2_OAbh7VyifGGl-1zpuUoBcw,1072
39
- simple_dwd_weatherforecast-2.0.33.dist-info/METADATA,sha256=OoVmEQpJwfD2ThO8I7DcKwD2Xcv0sm5izDTWFaJkOTs,10937
40
- simple_dwd_weatherforecast-2.0.33.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
41
- simple_dwd_weatherforecast-2.0.33.dist-info/top_level.txt,sha256=iyEobUh14Tzitx39Oi8qm0NhBrnZovl_dNKtvLUkLEM,33
42
- simple_dwd_weatherforecast-2.0.33.dist-info/RECORD,,
38
+ simple_dwd_weatherforecast-2.1.0.dist-info/LICENCE,sha256=27UG7gteqvSWuZlsbIq2_OAbh7VyifGGl-1zpuUoBcw,1072
39
+ simple_dwd_weatherforecast-2.1.0.dist-info/METADATA,sha256=Czz5cBb-mPwEPqRITu4_umcHf-Krkb0kGjlBJwlqQDw,11893
40
+ simple_dwd_weatherforecast-2.1.0.dist-info/WHEEL,sha256=uCRv0ZEik_232NlR4YDw4Pv3Ajt5bKvMH13NUU7hFuI,91
41
+ simple_dwd_weatherforecast-2.1.0.dist-info/top_level.txt,sha256=iyEobUh14Tzitx39Oi8qm0NhBrnZovl_dNKtvLUkLEM,33
42
+ simple_dwd_weatherforecast-2.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (73.0.1)
2
+ Generator: setuptools (74.1.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -49,3 +49,11 @@ class Weather_get_daily_condition(unittest.TestCase):
49
49
  self.dwd_weather.get_daily_condition(test_time),
50
50
  "cloudy",
51
51
  )
52
+
53
+ @patch("simple_dwd_weatherforecast.dwdforecast.Weather.update", return_value=None)
54
+ def test_same_day(self, _):
55
+ test_time = datetime(2020, 11, 6, 0, 0)
56
+ self.assertEqual(
57
+ self.dwd_weather.get_daily_condition(test_time),
58
+ "sunny",
59
+ )
tests/test_map.py CHANGED
@@ -1,16 +1,171 @@
1
1
  import unittest
2
+ from unittest.mock import patch
2
3
  from simple_dwd_weatherforecast import dwdmap
4
+ from datetime import datetime, timedelta, timezone
3
5
 
4
6
 
5
7
  class MapTestCase(unittest.TestCase):
6
8
  def test_prevent_too_large_height(self):
7
9
  with self.assertRaises(ValueError):
8
- dwdmap.get_map(4.4, 46.4, 16.1, 55.6, dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR, dwdmap.WeatherBackgroundMapType.BUNDESLAENDER, 1300, 700)
10
+ dwdmap.get_map(
11
+ 4.4,
12
+ 46.4,
13
+ 16.1,
14
+ 55.6,
15
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
16
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
17
+ 1300,
18
+ 700,
19
+ )
9
20
 
10
21
  def test_prevent_too_large_width(self):
11
22
  with self.assertRaises(ValueError):
12
- dwdmap.get_map(4.4, 46.4, 16.1, 55.6, dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR, dwdmap.WeatherBackgroundMapType.BUNDESLAENDER, 300, 1700)
23
+ dwdmap.get_map(
24
+ 4.4,
25
+ 46.4,
26
+ 16.1,
27
+ 55.6,
28
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
29
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
30
+ 300,
31
+ 1700,
32
+ )
13
33
 
14
34
  def test_prevent_too_large(self):
15
35
  with self.assertRaises(ValueError):
16
- dwdmap.get_map(4.4, 46.4, 16.1, 55.6, dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR, dwdmap.WeatherBackgroundMapType.BUNDESLAENDER, 1300, 1700)
36
+ dwdmap.get_map(
37
+ 4.4,
38
+ 46.4,
39
+ 16.1,
40
+ 55.6,
41
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
42
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
43
+ 1300,
44
+ 1700,
45
+ )
46
+
47
+
48
+ class ImageLoopTestCase(unittest.TestCase):
49
+ @patch("simple_dwd_weatherforecast.dwdmap.ImageLoop._get_image", return_value=None)
50
+ def test_init(self, mock_function):
51
+ maploop = dwdmap.ImageLoop(
52
+ 0.1,
53
+ 0.2,
54
+ 0.3,
55
+ 0.4,
56
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
57
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
58
+ 1,
59
+ )
60
+ self.assertEqual(
61
+ maploop._minx,
62
+ 0.1,
63
+ )
64
+ self.assertEqual(
65
+ maploop._miny,
66
+ 0.2,
67
+ )
68
+ self.assertEqual(
69
+ maploop._maxx,
70
+ 0.3,
71
+ )
72
+ self.assertEqual(
73
+ maploop._maxy,
74
+ 0.4,
75
+ )
76
+ self.assertEqual(
77
+ maploop._map_type,
78
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
79
+ )
80
+ self.assertEqual(
81
+ maploop._background_type,
82
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
83
+ )
84
+ mock_function.assert_called_once()
85
+
86
+ @patch("simple_dwd_weatherforecast.dwdmap.ImageLoop._get_image", return_value=None)
87
+ def test_steps1(self, mock_function):
88
+ _ = dwdmap.ImageLoop(
89
+ 0.1,
90
+ 0.2,
91
+ 0.3,
92
+ 0.4,
93
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
94
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
95
+ 5,
96
+ )
97
+ self.assertEqual(mock_function.call_count, 5)
98
+
99
+ @patch("simple_dwd_weatherforecast.dwdmap.ImageLoop._get_image", return_value=None)
100
+ def test_steps2(self, mock_function):
101
+ _ = dwdmap.ImageLoop(
102
+ 0.1,
103
+ 0.2,
104
+ 0.3,
105
+ 0.4,
106
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
107
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
108
+ 10,
109
+ )
110
+ self.assertEqual(mock_function.call_count, 10)
111
+
112
+ @patch("simple_dwd_weatherforecast.dwdmap.ImageLoop._get_image", return_value=None)
113
+ def test_update_full(self, mock_function):
114
+ maploop = dwdmap.ImageLoop(
115
+ 0.1,
116
+ 0.2,
117
+ 0.3,
118
+ 0.4,
119
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
120
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
121
+ 5,
122
+ )
123
+ maploop._last_update = datetime(year=2024, month=9, day=4, hour=5, minute=50)
124
+ self.assertEqual(mock_function.call_count, 5)
125
+
126
+ @patch("simple_dwd_weatherforecast.dwdmap.ImageLoop._get_image", return_value=None)
127
+ def test_update_part(self, mock_function):
128
+ maploop = dwdmap.ImageLoop(
129
+ 0.1,
130
+ 0.2,
131
+ 0.3,
132
+ 0.4,
133
+ dwdmap.WeatherMapType.NIEDERSCHLAGSRADAR,
134
+ dwdmap.WeatherBackgroundMapType.BUNDESLAENDER,
135
+ 5,
136
+ )
137
+ now = dwdmap.get_time_last_5_min(datetime.now(timezone.utc))
138
+ maploop._last_update = now - timedelta(minutes=15)
139
+ mock_function.reset_mock()
140
+ maploop.update()
141
+ self.assertEqual(mock_function.call_count, 3)
142
+
143
+
144
+ class GeneralTestCase(unittest.TestCase):
145
+ def test_get_time_last_5_min_strip(self):
146
+ time = datetime(year=2024, month=9, day=4, hour=9, minute=50, second=52)
147
+ self.assertEqual(
148
+ dwdmap.get_time_last_5_min(time),
149
+ datetime(year=2024, month=9, day=4, hour=9, minute=50),
150
+ )
151
+
152
+ def test_get_time_last_5_min_exact(self):
153
+ time = datetime(year=2024, month=9, day=4, hour=9, minute=50, second=00)
154
+ self.assertEqual(
155
+ dwdmap.get_time_last_5_min(time),
156
+ datetime(year=2024, month=9, day=4, hour=9, minute=50),
157
+ )
158
+
159
+ def test_get_time_last_5_min_between1(self):
160
+ time = datetime(year=2024, month=9, day=4, hour=9, minute=52, second=00)
161
+ self.assertEqual(
162
+ dwdmap.get_time_last_5_min(time),
163
+ datetime(year=2024, month=9, day=4, hour=9, minute=50),
164
+ )
165
+
166
+ def test_get_time_last_5_min_between2(self):
167
+ time = datetime(year=2024, month=9, day=4, hour=9, minute=3, second=00)
168
+ self.assertEqual(
169
+ dwdmap.get_time_last_5_min(time),
170
+ datetime(year=2024, month=9, day=4, hour=9, minute=0),
171
+ )