Repository: DHI/mikeio (python)

Issue:
end_time property does not work in dfs0
https://github.com/DHI/mikeio/blob/ed60b7caeb1e2a2003266a69607157f2f3302c20/mikeio/dfs0.py#L424

Will throw an error since _end_time is not defined. Its implementation should be similar to that in dfs.py as it depends on the type of TimeAxis.

Pull request description:
Dfs0 end_time property. Closes #203

Patch:
diff --git a/mikeio/dfs.py b/mikeio/dfs.py
index cd60dacc..36b7e482 100644
--- a/mikeio/dfs.py
+++ b/mikeio/dfs.py
@@ -1,4 +1,4 @@
-from datetime import datetime, timedelta
+from datetime import datetime
 from abc import abstractmethod
 
 import warnings
@@ -12,7 +12,7 @@ from .dfsutil import _valid_item_numbers, _valid_timesteps, _get_item_info
 from .eum import ItemInfo, TimeStepUnit, EUMType, EUMUnit
 from .custom_exceptions import DataDimensionMismatch, ItemNumbersError
 from mikecore.eum import eumQuantity
-from mikecore.DfsFile import DfsSimpleType
+from mikecore.DfsFile import DfsSimpleType, TimeAxisType
 from mikecore.DfsFactory import DfsFactory
 
 
@@ -99,7 +99,14 @@ class _Dfs123(TimeSeries):
         dfs = self._dfs
         self._n_items = len(dfs.ItemInfo)
         self._items = self._get_item_info(list(range(self._n_items)))
-        self._start_time = dfs.FileInfo.TimeAxis.StartDateTime
+        self._timeaxistype = dfs.FileInfo.TimeAxis.TimeAxisType
+        if self._timeaxistype in {
+            TimeAxisType.CalendarEquidistant,
+            TimeAxisType.CalendarNonEquidistant,
+        }:
+            self._start_time = dfs.FileInfo.TimeAxis.StartDateTime
+        else:  # relative time axis
+            self._start_time = datetime(1970, 1, 1)
         if hasattr(dfs.FileInfo.TimeAxis, "TimeStep"):
             self._timestep_in_seconds = (
                 dfs.FileInfo.TimeAxis.TimeStep
diff --git a/mikeio/dfs0.py b/mikeio/dfs0.py
index def6571e..45ffb0a3 100644
--- a/mikeio/dfs0.py
+++ b/mikeio/dfs0.py
@@ -1,6 +1,6 @@
 import os
 import warnings
-from datetime import datetime
+from datetime import datetime, timedelta
 import numpy as np
 import pandas as pd
 
@@ -35,6 +35,7 @@ class Dfs0(TimeSeries):
         self._source = None
         self._dfs = None
         self._start_time = None
+        self._end_time = None
         self._n_items = None
         self._dt = None
         self._is_equidistant = None
@@ -412,6 +413,16 @@ class Dfs0(TimeSeries):
 
     @property
     def end_time(self):
+        if self._end_time is None:
+            if self._source.FileInfo.TimeAxis.IsEquidistant():
+                dt = self._source.FileInfo.TimeAxis.TimeStep
+                n_steps = self._source.FileInfo.TimeAxis.NumberOfTimeSteps
+                timespan = dt * (n_steps - 1)
+            else:
+                timespan = self._source.FileInfo.TimeAxis.TimeSpan
+
+            self._end_time = self.start_time + timedelta(seconds=timespan)
+
         return self._end_time
 
     @property


Test patch:
diff --git a/tests/test_dfs0.py b/tests/test_dfs0.py
index c0f8f014..51dc9f26 100644
--- a/tests/test_dfs0.py
+++ b/tests/test_dfs0.py
@@ -142,6 +142,17 @@ def test_read_units_write_new(tmpdir):
     assert ds2.items[0].unit == ds.items[0].unit
 
 
+def test_read_start_end_time():
+
+    dfs0file = r"tests/testdata/random.dfs0"
+
+    dfs = Dfs0(dfs0file)
+    ds = dfs.read()
+
+    assert dfs.start_time == ds.start_time
+    assert dfs.end_time == ds.end_time
+
+
 def test_multiple_write(tmpdir):
 
     filename = os.path.join(tmpdir.dirname, "random.dfs0")
diff --git a/tests/test_dfs1.py b/tests/test_dfs1.py
index 3d94c4f2..2327314c 100644
--- a/tests/test_dfs1.py
+++ b/tests/test_dfs1.py
@@ -154,3 +154,25 @@ def test_read_names_access():
     assert res.items[0].name == "testing water level"
     assert res.items[0].type == EUMType.Water_Level
     assert res.items[0].unit == EUMUnit.meter
+
+
+def test_read_start_end_time():
+
+    dfs0file = r"tests/testdata/random.dfs1"
+
+    dfs = Dfs1(dfs0file)
+    ds = dfs.read()
+
+    assert dfs.start_time == ds.start_time
+    assert dfs.end_time == ds.end_time
+
+
+def test_read_start_end_time_relative_time():
+
+    dfs0file = r"tests/testdata/physical_basin_wave_maker_signal.dfs1"
+
+    dfs = Dfs1(dfs0file)
+    ds = dfs.read()
+
+    assert dfs.start_time == ds.start_time
+    assert dfs.end_time == ds.end_time