weatherdb 1.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.
- docker/Dockerfile +30 -0
- docker/docker-compose.yaml +58 -0
- docker/docker-compose_test.yaml +24 -0
- docker/start-docker-test.sh +6 -0
- docs/requirements.txt +10 -0
- docs/source/Changelog.md +2 -0
- docs/source/License.rst +7 -0
- docs/source/Methode.md +161 -0
- docs/source/_static/custom.css +8 -0
- docs/source/_static/favicon.ico +0 -0
- docs/source/_static/logo.png +0 -0
- docs/source/api/api.rst +15 -0
- docs/source/api/cli.rst +8 -0
- docs/source/api/weatherDB.broker.rst +10 -0
- docs/source/api/weatherDB.config.rst +7 -0
- docs/source/api/weatherDB.db.rst +23 -0
- docs/source/api/weatherDB.rst +22 -0
- docs/source/api/weatherDB.station.rst +56 -0
- docs/source/api/weatherDB.stations.rst +46 -0
- docs/source/api/weatherDB.utils.rst +22 -0
- docs/source/conf.py +137 -0
- docs/source/index.rst +33 -0
- docs/source/setup/Configuration.md +127 -0
- docs/source/setup/Hosting.md +9 -0
- docs/source/setup/Install.md +49 -0
- docs/source/setup/Quickstart.md +183 -0
- docs/source/setup/setup.rst +12 -0
- weatherdb/__init__.py +24 -0
- weatherdb/_version.py +1 -0
- weatherdb/alembic/README.md +8 -0
- weatherdb/alembic/alembic.ini +80 -0
- weatherdb/alembic/config.py +9 -0
- weatherdb/alembic/env.py +100 -0
- weatherdb/alembic/script.py.mako +26 -0
- weatherdb/alembic/versions/V1.0.0_initial_database_creation.py +898 -0
- weatherdb/alembic/versions/V1.0.2_more_charachters_for_settings+term_station_ma_raster.py +88 -0
- weatherdb/alembic/versions/V1.0.5_fix-ma-raster-values.py +152 -0
- weatherdb/alembic/versions/V1.0.6_update-views.py +22 -0
- weatherdb/broker.py +667 -0
- weatherdb/cli.py +214 -0
- weatherdb/config/ConfigParser.py +663 -0
- weatherdb/config/__init__.py +5 -0
- weatherdb/config/config_default.ini +162 -0
- weatherdb/db/__init__.py +3 -0
- weatherdb/db/connections.py +374 -0
- weatherdb/db/fixtures/RichterParameters.json +34 -0
- weatherdb/db/models.py +402 -0
- weatherdb/db/queries/get_quotient.py +155 -0
- weatherdb/db/views.py +165 -0
- weatherdb/station/GroupStation.py +710 -0
- weatherdb/station/StationBases.py +3108 -0
- weatherdb/station/StationET.py +111 -0
- weatherdb/station/StationP.py +807 -0
- weatherdb/station/StationPD.py +98 -0
- weatherdb/station/StationT.py +164 -0
- weatherdb/station/__init__.py +13 -0
- weatherdb/station/constants.py +21 -0
- weatherdb/stations/GroupStations.py +519 -0
- weatherdb/stations/StationsBase.py +1021 -0
- weatherdb/stations/StationsBaseTET.py +30 -0
- weatherdb/stations/StationsET.py +17 -0
- weatherdb/stations/StationsP.py +128 -0
- weatherdb/stations/StationsPD.py +24 -0
- weatherdb/stations/StationsT.py +21 -0
- weatherdb/stations/__init__.py +11 -0
- weatherdb/utils/TimestampPeriod.py +369 -0
- weatherdb/utils/__init__.py +3 -0
- weatherdb/utils/dwd.py +350 -0
- weatherdb/utils/geometry.py +69 -0
- weatherdb/utils/get_data.py +285 -0
- weatherdb/utils/logging.py +126 -0
- weatherdb-1.1.0.dist-info/LICENSE +674 -0
- weatherdb-1.1.0.dist-info/METADATA +765 -0
- weatherdb-1.1.0.dist-info/RECORD +77 -0
- weatherdb-1.1.0.dist-info/WHEEL +5 -0
- weatherdb-1.1.0.dist-info/entry_points.txt +2 -0
- weatherdb-1.1.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# libraries
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from ..db.connections import db_engine
|
5
|
+
from .StationsBase import StationsBase
|
6
|
+
from .StationsP import StationsP
|
7
|
+
|
8
|
+
# set settings
|
9
|
+
# ############
|
10
|
+
__all__ = ["StationsBaseTET"]
|
11
|
+
log = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
# class definition
|
14
|
+
##################
|
15
|
+
class StationsBaseTET(StationsBase):
|
16
|
+
@db_engine.deco_update_privilege
|
17
|
+
def fillup(self, only_real=False, stids="all", **kwargs):
|
18
|
+
# create virtual stations if necessary
|
19
|
+
if not only_real:
|
20
|
+
meta = self.get_meta(
|
21
|
+
infos=["Station_id"], only_real=False)
|
22
|
+
meta_p = StationsP().get_meta(
|
23
|
+
infos=["Station_id"], only_real=False)
|
24
|
+
stids_missing = set(meta_p.index.values) - set(meta.index.values)
|
25
|
+
if stids != "all":
|
26
|
+
stids_missing = set(stids).intersection(stids_missing)
|
27
|
+
for stid in stids_missing:
|
28
|
+
self._StationClass(stid) # this creates the virtual station
|
29
|
+
|
30
|
+
super().fillup(only_real=only_real, stids=stids, **kwargs)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# libraries
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from ..station import StationET
|
5
|
+
from .StationsBaseTET import StationsBaseTET
|
6
|
+
|
7
|
+
# set settings
|
8
|
+
# ############
|
9
|
+
__all__ = ["StationsET"]
|
10
|
+
log = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
# class definition
|
13
|
+
##################
|
14
|
+
class StationsET(StationsBaseTET):
|
15
|
+
"""A class to work with and download potential Evapotranspiration (VPGB) data for several stations."""
|
16
|
+
_StationClass = StationET
|
17
|
+
_timeout_raw_imp = 120
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# libraries
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from ..db.connections import db_engine
|
5
|
+
from ..station import StationP
|
6
|
+
from .StationsBase import StationsBase
|
7
|
+
|
8
|
+
# set settings
|
9
|
+
# ############
|
10
|
+
__all__ = ["StationsP"]
|
11
|
+
log = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
# class definition
|
14
|
+
##################
|
15
|
+
class StationsP(StationsBase):
|
16
|
+
"""A class to work with and download 10 minutes precipitation data for several stations."""
|
17
|
+
_StationClass = StationP
|
18
|
+
_timeout_raw_imp = 360
|
19
|
+
|
20
|
+
@db_engine.deco_update_privilege
|
21
|
+
def update_richter_class(self, stids="all", do_mp=True, **kwargs):
|
22
|
+
"""Update the Richter exposition class.
|
23
|
+
|
24
|
+
Get the value from the raster, compare with the richter categories and save to the database.
|
25
|
+
|
26
|
+
Parameters
|
27
|
+
----------
|
28
|
+
stids: string or list of int, optional
|
29
|
+
The Stations for which to compute.
|
30
|
+
Can either be "all", for all possible stations
|
31
|
+
or a list with the Station IDs.
|
32
|
+
The default is "all".
|
33
|
+
**kwargs : dict, optional
|
34
|
+
The keyword arguments to be handed to the station.StationP.update_richter_class and get_stations method.
|
35
|
+
|
36
|
+
Raises
|
37
|
+
------
|
38
|
+
ValueError
|
39
|
+
If the given stids (Station_IDs) are not all valid.
|
40
|
+
"""
|
41
|
+
self._run_method(
|
42
|
+
stations=self.get_stations(only_real=True, stids=stids, **kwargs),
|
43
|
+
method="update_richter_class",
|
44
|
+
name="update richter class for {para}".format(para=self._para.upper()),
|
45
|
+
kwds=kwargs,
|
46
|
+
do_mp=do_mp)
|
47
|
+
|
48
|
+
@db_engine.deco_update_privilege
|
49
|
+
def richter_correct(self, stids="all", **kwargs):
|
50
|
+
"""Richter correct the filled data.
|
51
|
+
|
52
|
+
Parameters
|
53
|
+
----------
|
54
|
+
stids: string or list of int, optional
|
55
|
+
The Stations for which to compute.
|
56
|
+
Can either be "all", for all possible stations
|
57
|
+
or a list with the Station IDs.
|
58
|
+
The default is "all".
|
59
|
+
**kwargs : dict, optional
|
60
|
+
The additional keyword arguments for the _run_method and get_stations method
|
61
|
+
|
62
|
+
Raises
|
63
|
+
------
|
64
|
+
ValueError
|
65
|
+
If the given stids (Station_IDs) are not all valid.
|
66
|
+
"""
|
67
|
+
self._run_method(
|
68
|
+
stations=self.get_stations(only_real=False, stids=stids, **kwargs),
|
69
|
+
method="richter_correct",
|
70
|
+
name="richter correction on {para}".format(para=self._para.upper()),
|
71
|
+
do_mp=False, **kwargs)
|
72
|
+
|
73
|
+
@db_engine.deco_update_privilege
|
74
|
+
def last_imp_corr(self, stids="all", do_mp=False, **kwargs):
|
75
|
+
"""Richter correct the filled data for the last imported period.
|
76
|
+
|
77
|
+
Parameters
|
78
|
+
----------
|
79
|
+
stids: string or list of int, optional
|
80
|
+
The Stations for which to compute.
|
81
|
+
Can either be "all", for all possible stations
|
82
|
+
or a list with the Station IDs.
|
83
|
+
The default is "all".
|
84
|
+
do_mp : bool, optional
|
85
|
+
Should the method be done in multiprocessing mode?
|
86
|
+
If False the methods will be called in threading mode.
|
87
|
+
Multiprocessing needs more memory and a bit more initiating time. Therefor it is only usefull for methods with a lot of computation effort in the python code.
|
88
|
+
If the most computation of a method is done in the postgresql database, then threading is enough to speed the process up.
|
89
|
+
The default is False.
|
90
|
+
**kwargs : dict, optional
|
91
|
+
The additional keyword arguments for the _run_method and get_stations method
|
92
|
+
|
93
|
+
Raises
|
94
|
+
------
|
95
|
+
ValueError
|
96
|
+
If the given stids (Station_IDs) are not all valid.
|
97
|
+
"""
|
98
|
+
stations = self.get_stations(only_real=True, stids=stids, **kwargs)
|
99
|
+
period = stations[0].get_last_imp_period(all=True)
|
100
|
+
log.info("The {para_long} Stations fillup of the last import is started for the period {min_tstp} - {max_tstp}".format(
|
101
|
+
para_long=self._para_long,
|
102
|
+
**period.get_sql_format_dict(format="%Y%m%d %H:%M")))
|
103
|
+
self._run_method(
|
104
|
+
stations=stations,
|
105
|
+
method="last_imp_corr",
|
106
|
+
kwds={"_last_imp_period": period},
|
107
|
+
name="richter correction on {para}".format(para=self._para.upper()),
|
108
|
+
do_mp=do_mp, **kwargs)
|
109
|
+
|
110
|
+
@db_engine.deco_update_privilege
|
111
|
+
def update(self, only_new=True, **kwargs):
|
112
|
+
"""Make a complete update of the stations.
|
113
|
+
|
114
|
+
Does the update_raw, quality check, fillup and richter correction of the stations.
|
115
|
+
|
116
|
+
Parameters
|
117
|
+
----------
|
118
|
+
only_new : bool, optional
|
119
|
+
Should a only new values be computed?
|
120
|
+
If False: The stations are updated for the whole possible period.
|
121
|
+
If True, the stations are only updated for new values.
|
122
|
+
The default is True.
|
123
|
+
"""
|
124
|
+
super().update(only_new=only_new, **kwargs)
|
125
|
+
if only_new:
|
126
|
+
self.last_imp_richter_correct(**kwargs)
|
127
|
+
else:
|
128
|
+
self.richter_correct(**kwargs)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# libraries
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from ..station import StationPD
|
5
|
+
from .StationsP import StationsP
|
6
|
+
from .StationsBase import StationsBase
|
7
|
+
|
8
|
+
# set settings
|
9
|
+
# ############
|
10
|
+
__all__ = ["StationsPD"]
|
11
|
+
log = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
# class definition
|
14
|
+
##################
|
15
|
+
|
16
|
+
class StationsPD(StationsBase):
|
17
|
+
"""A class to work with and download daily precipitation data for several stations.
|
18
|
+
|
19
|
+
Those stations data are only downloaded to do some quality checks on the 10 minutes data.
|
20
|
+
Therefor there is no special quality check and richter correction done on this data.
|
21
|
+
If you want daily precipitation data, better use the 10 minutes station class (StationP) and aggregate to daily values.
|
22
|
+
"""
|
23
|
+
_StationClass = StationPD
|
24
|
+
_timeout_raw_imp = 120
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# libraries
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from ..station import StationT
|
5
|
+
from .StationsBaseTET import StationsBaseTET
|
6
|
+
|
7
|
+
# set settings
|
8
|
+
# ############
|
9
|
+
__all__ = ["StationsT"]
|
10
|
+
log = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
# class definition
|
13
|
+
##################
|
14
|
+
|
15
|
+
class StationsT(StationsBaseTET):
|
16
|
+
"""A class to work with and download temperature data for several stations."""
|
17
|
+
_StationClass = StationT
|
18
|
+
_timeout_raw_imp = 120
|
19
|
+
|
20
|
+
def get_quotient(self, **kwargs):
|
21
|
+
raise NotImplementedError("The quotient is not yet implemented for temperature.")
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""
|
2
|
+
This module has grouping classes for all the stations of one parameter. E.G. StationsP (or StationsP) groups all the Precipitation Stations available.
|
3
|
+
Those classes can get used to do actions on all the stations.
|
4
|
+
"""
|
5
|
+
from .StationsP import StationsP
|
6
|
+
from .StationsPD import StationsPD
|
7
|
+
from .StationsT import StationsT
|
8
|
+
from .StationsET import StationsET
|
9
|
+
from .GroupStations import GroupStations
|
10
|
+
|
11
|
+
__all__ = ["StationsP", "StationsPD", "StationsT", "StationsET", "GroupStations"]
|
@@ -0,0 +1,369 @@
|
|
1
|
+
import re
|
2
|
+
from pandas import Timestamp, NaT, Timedelta
|
3
|
+
import datetime
|
4
|
+
|
5
|
+
class TimestampPeriod(object):
|
6
|
+
"""A class to save a Timespan with a minimal and maximal Timestamp.
|
7
|
+
"""
|
8
|
+
_COMPARE = {
|
9
|
+
"inner": {
|
10
|
+
0: max,
|
11
|
+
1: min},
|
12
|
+
"outer": {
|
13
|
+
0: min,
|
14
|
+
1: max}}
|
15
|
+
_REGEX_HAS_TIME = re.compile(
|
16
|
+
r"((^\d{6}[ \-\.]+)"+ # 991231
|
17
|
+
r"|(^\d{8}[ \-\.]*)|" + # 19991231
|
18
|
+
r"(^\d{1,4}[ \-\.]\d{1,2}[ \-\.]\d{1,4}[ \-\.]+))" + # 1999-12-31
|
19
|
+
r"+(\d+)") # has additional numbers -> time
|
20
|
+
|
21
|
+
def __init__(self, start, end, tzinfo="UTC"):
|
22
|
+
"""Initiate a TimestampPeriod.
|
23
|
+
|
24
|
+
Parameters
|
25
|
+
----------
|
26
|
+
start : pd.Timestamp or similar
|
27
|
+
The start of the Period.
|
28
|
+
end : pd.Timestamp or similar
|
29
|
+
The end of the Period.
|
30
|
+
tzinfo : str or datetime.timezone object or None, optional
|
31
|
+
The timezone to set to the timestamps.
|
32
|
+
If the timestamps already have a timezone they will get converted.
|
33
|
+
If None, then the timezone is not changed or set.
|
34
|
+
The default is "UTC".
|
35
|
+
"""
|
36
|
+
# check if input is a date or a timestamp
|
37
|
+
if ((isinstance(start, datetime.date) and isinstance(end, datetime.date)) or
|
38
|
+
(isinstance(start, str) and not self._REGEX_HAS_TIME.match(start) and
|
39
|
+
isinstance(end, str) and not self._REGEX_HAS_TIME.match(end))):
|
40
|
+
self.is_date = True
|
41
|
+
else:
|
42
|
+
self.is_date = False
|
43
|
+
|
44
|
+
# convert to correct timestamp format
|
45
|
+
period = list([start, end])
|
46
|
+
for i, tstp in enumerate(period):
|
47
|
+
if not isinstance(tstp, Timestamp):
|
48
|
+
period[i] = Timestamp(tstp)
|
49
|
+
|
50
|
+
# check timezone
|
51
|
+
self.tzinfo = tzinfo
|
52
|
+
if tzinfo is not None:
|
53
|
+
if period[i].tzinfo is None:
|
54
|
+
period[i] = period[i].tz_localize(tzinfo)
|
55
|
+
else:
|
56
|
+
period[i] = period[i].tz_convert(tzinfo)
|
57
|
+
|
58
|
+
self.start = period[0]
|
59
|
+
self.end = period[1]
|
60
|
+
|
61
|
+
@staticmethod
|
62
|
+
def _check_period(period):
|
63
|
+
if not isinstance(period, TimestampPeriod):
|
64
|
+
period = TimestampPeriod(*period)
|
65
|
+
return period
|
66
|
+
|
67
|
+
def union(self, other, how="inner"):
|
68
|
+
"""Unite 2 TimestampPeriods to one.
|
69
|
+
|
70
|
+
Compares the Periods and computes a new one.
|
71
|
+
|
72
|
+
Parameters
|
73
|
+
----------
|
74
|
+
other : TimestampPeriod
|
75
|
+
The other TimestampPeriod with whome to compare.
|
76
|
+
how : str, optional
|
77
|
+
How to compare the 2 TimestampPeriods.
|
78
|
+
Can be "inner" or "outer".
|
79
|
+
"inner": the maximal Timespan for both is computed.
|
80
|
+
"outer": The minimal Timespan for both is computed.
|
81
|
+
The default is "inner".
|
82
|
+
|
83
|
+
Returns
|
84
|
+
-------
|
85
|
+
TimestampPeriod
|
86
|
+
A new TimespanPeriod object uniting both TimestampPeriods.
|
87
|
+
"""
|
88
|
+
other = self._check_period(other)
|
89
|
+
|
90
|
+
# check for daily period in elements
|
91
|
+
tdsother = [Timedelta(0), Timedelta(0)]
|
92
|
+
tdsself = [Timedelta(0), Timedelta(0)]
|
93
|
+
if self.is_date and not other.is_date and not other.is_empty():
|
94
|
+
tdsself[1] = Timedelta(
|
95
|
+
hours=other.end.hour,
|
96
|
+
minutes=other.end.minute,
|
97
|
+
seconds=other.end.second)
|
98
|
+
elif not self.is_date and other.is_date and not self.is_empty():
|
99
|
+
tdsother[1] = Timedelta(
|
100
|
+
hours=self.end.hour,
|
101
|
+
minutes=self.end.minute,
|
102
|
+
seconds=self.end.second)
|
103
|
+
|
104
|
+
# check if empty and inner
|
105
|
+
if how=="inner" and (self.is_empty() or other.is_empty()):
|
106
|
+
return TimestampPeriod(None, None)
|
107
|
+
|
108
|
+
# get the united period
|
109
|
+
period = [None, None]
|
110
|
+
for i in range(2):
|
111
|
+
comp_list = [val + td
|
112
|
+
for val, td in zip([self[i], other[i]],
|
113
|
+
[tdsself[i], tdsother[i]])
|
114
|
+
if isinstance(val, Timestamp)]
|
115
|
+
if len(comp_list) > 0:
|
116
|
+
period[i] = self._COMPARE[how][i](comp_list)
|
117
|
+
|
118
|
+
# check if end < start
|
119
|
+
if period[0]>=period[1]:
|
120
|
+
period = (None, None)
|
121
|
+
|
122
|
+
# return the period
|
123
|
+
if self.is_date and other.is_date and all(period):
|
124
|
+
# if both were data periods, then the result should also be a date period
|
125
|
+
return TimestampPeriod(
|
126
|
+
*[val.date() for val in period
|
127
|
+
if isinstance(val, Timestamp)])
|
128
|
+
else:
|
129
|
+
return TimestampPeriod(*period)
|
130
|
+
|
131
|
+
def get_period(self):
|
132
|
+
return (self.start, self.end)
|
133
|
+
|
134
|
+
def __getitem__(self, key):
|
135
|
+
if key == 0 or key == "start":
|
136
|
+
return self.start
|
137
|
+
elif key == 1 or key == "end":
|
138
|
+
return self.end
|
139
|
+
|
140
|
+
def __setitem__(self, key, value):
|
141
|
+
if value != Timestamp:
|
142
|
+
value = Timestamp(value)
|
143
|
+
|
144
|
+
if key == 0 or key == "start":
|
145
|
+
self.start = value
|
146
|
+
elif key == 1 or key == "end":
|
147
|
+
self.end = value
|
148
|
+
|
149
|
+
def __iter__(self):
|
150
|
+
return self.get_period().__iter__()
|
151
|
+
|
152
|
+
def __str__(self):
|
153
|
+
msg = "TimestampPeriod: {0} - {1}"
|
154
|
+
if self.is_date:
|
155
|
+
return msg.format(*self.strftime(format="%Y-%m-%d"))
|
156
|
+
else:
|
157
|
+
return msg.format(*self.strftime(format="%Y-%m-%d %H:%M:%S"))
|
158
|
+
|
159
|
+
def __repr__(self):
|
160
|
+
return self.__str__()
|
161
|
+
|
162
|
+
def __eq__(self, other):
|
163
|
+
other = self._check_period(other)
|
164
|
+
|
165
|
+
if self.start == other.start and self.end == other.end:
|
166
|
+
return True
|
167
|
+
else:
|
168
|
+
return False
|
169
|
+
|
170
|
+
def __ne__(self, other):
|
171
|
+
return not self.__eq__(other)
|
172
|
+
|
173
|
+
def __lt__(self, other):
|
174
|
+
return self.inside(other)
|
175
|
+
|
176
|
+
def __le__(self, other):
|
177
|
+
return self.inside(other)
|
178
|
+
|
179
|
+
def __gt__(self, other):
|
180
|
+
return self.contains(other)
|
181
|
+
|
182
|
+
def __ge__(self, other):
|
183
|
+
return self.contains(other)
|
184
|
+
|
185
|
+
def has_NaT(self):
|
186
|
+
"""Has the TimestampPeriod at least one NaT.
|
187
|
+
|
188
|
+
This means that the start or end is not given.
|
189
|
+
Normally this should never happen, because it makes no sense.
|
190
|
+
|
191
|
+
Returns
|
192
|
+
-------
|
193
|
+
bool
|
194
|
+
True if the TimestampPeriod has at least on NaT.
|
195
|
+
False if the TimestampPeriod has at least a start or a end.
|
196
|
+
"""
|
197
|
+
return any([tstp is NaT for tstp in self])
|
198
|
+
|
199
|
+
def has_only_NaT(self):
|
200
|
+
"""Has the TimestampPeriod only NaT, meaning is empty.
|
201
|
+
|
202
|
+
This means that the start and end is not given.
|
203
|
+
|
204
|
+
Returns
|
205
|
+
-------
|
206
|
+
bool
|
207
|
+
True if the TimestampPeriod is empty.
|
208
|
+
False if the TimestampPeriod has a start and an end.
|
209
|
+
"""
|
210
|
+
return all([tstp is NaT for tstp in self])
|
211
|
+
|
212
|
+
def is_empty(self):
|
213
|
+
"""Is the TimestampPeriod empty.
|
214
|
+
|
215
|
+
This means that the start and end is not given.
|
216
|
+
|
217
|
+
Returns
|
218
|
+
-------
|
219
|
+
bool
|
220
|
+
True if the TimestampPeriod is empty.
|
221
|
+
False if the TimestampPeriod has a start and an end.
|
222
|
+
"""
|
223
|
+
return self.has_only_NaT()
|
224
|
+
|
225
|
+
def strftime(self, format="%Y-%m-%d %H:%M:%S"):
|
226
|
+
"""Convert the TimestampPeriod to a list of strings.
|
227
|
+
|
228
|
+
Formates the Timestamp as a string.
|
229
|
+
|
230
|
+
Parameters
|
231
|
+
----------
|
232
|
+
format : str, optional
|
233
|
+
The Timestamp-format to use.
|
234
|
+
The Default is "%Y-%m-%d %H:%M:%S"
|
235
|
+
|
236
|
+
Returns
|
237
|
+
-------
|
238
|
+
list of 2 strings
|
239
|
+
A list of the start and end of the TimestampPeriod as formated string.
|
240
|
+
"""
|
241
|
+
out = [tstp.strftime(format) if tstp is not NaT else None
|
242
|
+
for tstp in self.get_period()]
|
243
|
+
return out
|
244
|
+
|
245
|
+
def inside(self, other):
|
246
|
+
"""Is the TimestampPeriod inside another TimestampPeriod?
|
247
|
+
|
248
|
+
Parameters
|
249
|
+
----------
|
250
|
+
other : Timestampperiod or tuple of 2 Timestamp or Timestamp strings
|
251
|
+
The other Timestamp to test against.
|
252
|
+
Test if this TimestampPeriod is inside the other.
|
253
|
+
|
254
|
+
Returns
|
255
|
+
-------
|
256
|
+
bool
|
257
|
+
True if this TimestampPeriod is inside the other.
|
258
|
+
Meaning that the start is higher or equal than the others starts
|
259
|
+
and the end is smaller than the others end.
|
260
|
+
"""
|
261
|
+
other = self._check_period(other)
|
262
|
+
if self.start >= other.start and self.end <= other.end:
|
263
|
+
return True
|
264
|
+
else:
|
265
|
+
return False
|
266
|
+
|
267
|
+
def contains(self, other):
|
268
|
+
"""Does this TimestampPeriod contain another TimestampPeriod?
|
269
|
+
|
270
|
+
Parameters
|
271
|
+
----------
|
272
|
+
other : Timestampperiod or tuple of 2 Timestamp or Timestamp strings
|
273
|
+
The other Timestamp to test against.
|
274
|
+
Test if this TimestampPeriod contains the other.
|
275
|
+
|
276
|
+
Returns
|
277
|
+
-------
|
278
|
+
bool
|
279
|
+
True if this TimestampPeriod contains the other.
|
280
|
+
Meaning that the start is smaller or equal than the others starts
|
281
|
+
and the end is higher than the others end.
|
282
|
+
"""
|
283
|
+
other = self._check_period(other)
|
284
|
+
return other.inside(self)
|
285
|
+
|
286
|
+
def get_sql_format_dict(self, format="'%Y%m%d %H:%M'"):
|
287
|
+
"""Get the dictionary to use in sql queries.
|
288
|
+
|
289
|
+
Parameters
|
290
|
+
----------
|
291
|
+
format : str, optional
|
292
|
+
The Timestamp-format to use.
|
293
|
+
The Default is "'%Y%m%d %H:%M'"
|
294
|
+
|
295
|
+
Returns
|
296
|
+
-------
|
297
|
+
dict
|
298
|
+
a dictionary with 2 keys (min_tstp, max_tstp) and the corresponding Timestamp as formated string.
|
299
|
+
"""
|
300
|
+
period_str = self.strftime(format=format)
|
301
|
+
period_str = [str(el).replace("None", "NULL") for el in period_str]
|
302
|
+
return dict(min_tstp=period_str[0], max_tstp=period_str[1])
|
303
|
+
|
304
|
+
def get_interval(self):
|
305
|
+
"""Get the interval of the TimestampPeriod.
|
306
|
+
|
307
|
+
Returns
|
308
|
+
-------
|
309
|
+
pd.Timedelta
|
310
|
+
The interval of this TimestampPeriod.
|
311
|
+
E.G. Timedelta(2 days 12:30:12)
|
312
|
+
"""
|
313
|
+
return self.end - self.start
|
314
|
+
|
315
|
+
def get_middle(self):
|
316
|
+
"""Get the middle Timestamp of the TimestampPeriod.
|
317
|
+
|
318
|
+
Returns
|
319
|
+
-------
|
320
|
+
Timestamp
|
321
|
+
The middle Timestamp of this TimestampPeriod.
|
322
|
+
"""
|
323
|
+
middle = self.start + self.get_interval() / 2
|
324
|
+
if self.is_date:
|
325
|
+
middle = Timestamp(middle.date())
|
326
|
+
if self.tzinfo is not None:
|
327
|
+
if middle.tzinfo is None:
|
328
|
+
middle = middle.tz_localize(self.tzinfo)
|
329
|
+
return middle
|
330
|
+
|
331
|
+
def copy(self):
|
332
|
+
"""Copy this TimestampPeriod.
|
333
|
+
|
334
|
+
Returns
|
335
|
+
-------
|
336
|
+
TimestampPeriod
|
337
|
+
a new TimestampPeriod object that is equal to this one.
|
338
|
+
"""
|
339
|
+
new = TimestampPeriod(self.start, self.end)
|
340
|
+
new.is_date = self.is_date
|
341
|
+
return new
|
342
|
+
|
343
|
+
def expand_to_timestamp(self):
|
344
|
+
if self.is_date:
|
345
|
+
return TimestampPeriod(
|
346
|
+
start=self.start,
|
347
|
+
end=self.end + Timedelta(
|
348
|
+
hours=23, minutes=59, seconds=59, milliseconds=999))
|
349
|
+
else:
|
350
|
+
return self
|
351
|
+
|
352
|
+
def set_tz(self, tzinfo):
|
353
|
+
"""Set the TimestampPeriod to a new timezone.
|
354
|
+
|
355
|
+
Parameters
|
356
|
+
----------
|
357
|
+
tzinfo : str or datetime.timezone object
|
358
|
+
The timezone to set the TimestampPeriod to.
|
359
|
+
|
360
|
+
Returns
|
361
|
+
-------
|
362
|
+
TimestampPeriod
|
363
|
+
This TimestampPeriod.
|
364
|
+
"""
|
365
|
+
if not self.is_date:
|
366
|
+
self.start.replace(tzinfo=tzinfo)
|
367
|
+
self.end.replace(tzinfo=tzinfo)
|
368
|
+
return self
|
369
|
+
|