Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.0.4] - 2026-06-25
- Avoid RangeIndex beeing modified in modifiy_timezone
- Enhance documentation of modify_timezone

## [0.0.3] - 2026-06-23
- Fixes in modifiy_timezone
- Disarm dependencies to ease compatibility to designer development
Expand Down
5 changes: 4 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,10 @@ <h2>Functions<a class="headerlink" href="#functions" title="Link to this heading
<dt class="sig sig-object py" id="hdhelpers.helpers.modify_timezone">
<span class="sig-prename descclassname"><span class="pre">hdhelpers.helpers.</span></span><span class="sig-name descname"><span class="pre">modify_timezone</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">object_to_convert</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">to_timezone</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">column_names</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">convert_index</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#hdhelpers.helpers.modify_timezone" title="Link to this definition">¶</a></dt>
<dd><p>Converts time information of pandas objects to a certain timezone</p>
<p>This function is applicable to index and/or columns of pd.Series or pd.DataFrame as well as for single pd.Timestamp objects.</p>
<p>This function is applicable to index and/or columns of pd.Series or pd.DataFrame as well as for single pd.Timestamp objects.
If time zone information is not defined in object to convert it is assumed that it is in UTC.
Please note that column_names and convert_index are not exclusive to enable modifying both at the same time.
To enable modifying the value of a series (not the index), please name the series and define the series’ name in column_names.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
<dd class="field-odd"><ul class="simple">
Expand Down
2 changes: 1 addition & 1 deletion docs/searchindex.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ exclude = [

[project]
name = "hdhelpers"
version = "0.0.3"
version = "0.0.4"
description = "Streamlines metadata & timezone handling, and plotting in hetida designer components"
readme = "README.md"
maintainers = [
Expand Down
2 changes: 1 addition & 1 deletion src/hdhelpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .plot_target_settings import StatusColors

# do not edit line of __version__ as it is automatically modified by running ./run build_package
__version__ = "0.0.3"
__version__ = "0.0.4"

# function can be automated with from hdhelpers import *
__all__ = [
Expand Down
15 changes: 7 additions & 8 deletions src/hdhelpers/helpers/timezone_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def _convert_to_optional_timezone(object_to_convert, to_timezone: str | None):
"""Convert object_to_convert to to_timezone if not None,
or to its own timezone if aware
or to UTC otherwise"""
raise NotImplementedError(
f"Not implemented for object_to_convert of type {type(object_to_convert).__name__}"
raise TypeError(
f"Entries to convert do not contain valid timestamps ({type(object_to_convert).__name__})"
)


Expand Down Expand Up @@ -52,6 +52,9 @@ def modify_timezone[T: (pd.Timestamp, datetime.datetime, pd.Series, pd.DataFrame
"""Converts time information of pandas objects to a certain timezone

This function is applicable to index and/or columns of pd.Series or pd.DataFrame as well as for single pd.Timestamp objects.
If time zone information is not defined in object to convert it is assumed that it is in UTC.
Please note that column_names and convert_index are not exclusive to enable modifying both at the same time.
To enable modifying the value of a series (not the index), please name the series and define the series' name in column_names.

Args:
object_to_convert (pd.Timestamp | pd.Series | pd.DataFrame): Timestamp, Series or DataFrame where timezone is modified
Expand Down Expand Up @@ -103,9 +106,7 @@ def modify_timezone[T: (pd.Timestamp, datetime.datetime, pd.Series, pd.DataFrame

if len(column_names) == 0:
if isinstance(object_to_convert, pd.Series):
new_object.index = _convert_to_optional_timezone(
pd.to_datetime(new_object.index), to_timezone
)
new_object.index = _convert_to_optional_timezone(new_object.index, to_timezone)
msg = f"Converted index to datetime starting with {object_to_convert.index.min()}"
logger.debug(msg=msg)
elif isinstance(new_object, pd.DataFrame) and "timestamp" in new_object.columns:
Expand All @@ -123,9 +124,7 @@ def modify_timezone[T: (pd.Timestamp, datetime.datetime, pd.Series, pd.DataFrame
)

if convert_index:
new_object.index = _convert_to_optional_timezone(
pd.to_datetime(new_object.index), to_timezone
)
new_object.index = _convert_to_optional_timezone(new_object.index, to_timezone)

if not isinstance(object_to_convert, pd.Series):
new_object.attrs = object_to_convert.attrs
Expand Down
34 changes: 24 additions & 10 deletions tests/helpers/test_timezone_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_modify_timezone_timestamp_offset(timestamp, timezone, result):

def test_modify_timezone_good_dataframe(dataframe):
local_summertime = modify_timezone(
dataframe, to_timezone="Europe/Berlin", column_names=["timestamp"]
dataframe, to_timezone="Europe/Berlin", column_names=["timestamp"], convert_index=False
)

# German summer time starts in last Sunday in March at 2 am. --> UTC 1am
Expand Down Expand Up @@ -109,17 +109,19 @@ def test_empty_dataframe():
assert modified_data.empty


def test_named_series(series_summer):
def test_named_series_using_column_name(series_summer):
data = pd.Series(series_summer.index)
data.name = "timestamp"
data.attrs = series_summer.attrs
modified_data = modify_timezone(data, to_timezone="Europe/Berlin", column_names=["timestamp"])
modified_data = modify_timezone(
data, to_timezone="Europe/Berlin", column_names=["timestamp"], convert_index=False
)
assert modified_data[1].utcoffset() == datetime.timedelta(seconds=3600)
assert "foo" in modified_data.attrs


def test_named_series_using_index(series_summer):
data = series_summer
data = series_summer.copy()
data.name = "timestamp"
modified_data = modify_timezone(data, to_timezone="Europe/Berlin")
assert modified_data.index[0].utcoffset() == datetime.timedelta(seconds=3600)
Expand All @@ -137,12 +139,6 @@ def test_column_not_known(series_summer, dataframe):
_ = modify_timezone(dataframe, to_timezone="Europe/Berlin", column_names=["timestamp2"])


def test_modify_timezone_no_tz_known(series_summer):
series_summer.index = series_summer.index.tz_localize(None)
with pytest.raises(TypeError, match="Entries to convert do not contain valid timestamps*"):
_ = modify_timezone(series_summer, to_timezone="Europe/Berlin")


def test_modify_timezone_multicolumn_dataframe(multicolumn_frame):
local_summertime = modify_timezone(
multicolumn_frame.copy(),
Expand Down Expand Up @@ -200,3 +196,21 @@ def test_modify_timestamp_datetime():
example_date = pd.to_datetime("2023-03-25 23:00", utc=True)
modified_timestamp = modify_timezone(example_date.to_pydatetime(), to_timezone="Europe/Berlin")
assert modified_timestamp.utcoffset() == datetime.timedelta(seconds=3600)


def test_native_timestamp_handled_as_UTC(series_summer):
series_summer.index = series_summer.index.tz_localize(None)
modified_data = modify_timezone(series_summer.head(2), to_timezone="Europe/Berlin")
assert modified_data.index[0].utcoffset() == datetime.timedelta(seconds=3600)


def test_modify_timezone_no_timestamp_as_index(series_summer):
with pytest.raises(TypeError, match="Entries to convert do not contain valid timestamps"):
_ = modify_timezone(
series_summer.head(2).reset_index(), to_timezone="Europe/Berlin", convert_index=True
)


def test_modify_timezone_wrong_type(series_summer):
with pytest.raises(TypeError, match="object_to_convert is*"):
_ = modify_timezone(1, to_timezone="Europe/Berlin", convert_index=True)
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.