diff --git a/geomagio/Controller.py b/geomagio/Controller.py
index f4e7b5aaef84e612bb22b5942dc3f3ddce186630..2703efaeecd358d0db26f87c42d1d170421a2419 100644
--- a/geomagio/Controller.py
+++ b/geomagio/Controller.py
@@ -84,6 +84,8 @@ class Controller(object):
                     end=endtime,
                     observatory=obs,
                     channels=channels)
+            if input_start is None or input_end is None:
+                continue
             timeseries += self._inputFactory.get_timeseries(
                     observatory=obs,
                     starttime=input_start,
@@ -158,11 +160,13 @@ class Controller(object):
                 algorithm.get_input_channels()
         output_channels = options.outchannels or \
                 algorithm.get_output_channels()
+        starttime = algorithm.get_starttime() or options.starttime
+        endtime = options.endtime
         # input
         timeseries = input_timeseries or self._get_input_timeseries(
                 observatory=options.observatory,
-                starttime=options.starttime,
-                endtime=options.endtime,
+                starttime=starttime,
+                endtime=endtime,
                 channels=input_channels)
         if timeseries.count() == 0:
             return
@@ -174,8 +178,8 @@ class Controller(object):
         processed = algorithm.process(timeseries)
         # trim if --no-trim is not set
         if not options.no_trim:
-            processed.trim(starttime=options.starttime,
-                    endtime=options.endtime)
+            processed.trim(starttime=starttime,
+                    endtime=endtime)
         if options.rename_output_channel:
             processed = self._rename_channels(
                     timeseries=processed,
@@ -183,8 +187,8 @@ class Controller(object):
         # output
         self._outputFactory.put_timeseries(
                 timeseries=processed,
-                starttime=options.starttime,
-                endtime=options.endtime,
+                starttime=starttime,
+                endtime=endtime,
                 channels=output_channels)
 
     def run_as_update(self, options, update_count=0):
@@ -211,6 +215,8 @@ class Controller(object):
             if update_count >= options.update_limit:
                 return
         algorithm = self._algorithm
+        if algorithm.get_starttime() is not None:
+            raise Error('Stateful algorithms should NOT use run_as_update')
         input_channels = options.inchannels or \
                 algorithm.get_input_channels()
         output_observatory = options.output_observatory
diff --git a/geomagio/algorithm/Algorithm.py b/geomagio/algorithm/Algorithm.py
index c7410f8d60a5c5b86a15ad4ad15f25bcadb1663e..c26a8d4346875f3c97aa51eaf80a8f0b12243db0 100644
--- a/geomagio/algorithm/Algorithm.py
+++ b/geomagio/algorithm/Algorithm.py
@@ -111,6 +111,21 @@ class Algorithm(object):
                 return False
         return True
 
+    def get_starttime(self):
+        """Check whether algorithm has a stateful start time.
+
+        When an algorithm reports a start time, the Controller attempts to
+        only process data moving forward.
+
+        Returns
+        -------
+        UTCDateTime:
+            Time at which Controller should start processing,
+            or None (default) if algorithm is stateless.
+        """
+        return None
+
+
     @classmethod
     def add_arguments(cls, parser):
         """Add command line arguments to argparse parser.
diff --git a/geomagio/algorithm/SqDistAlgorithm.py b/geomagio/algorithm/SqDistAlgorithm.py
index e73a8c016ad1a07696c119d3f4719ca22550bb2e..088459dad7dad12df4d6cc7e2ab1d797825c29ac 100644
--- a/geomagio/algorithm/SqDistAlgorithm.py
+++ b/geomagio/algorithm/SqDistAlgorithm.py
@@ -86,6 +86,11 @@ class SqDistAlgorithm(Algorithm):
               'reinitializing.', file=sys.stderr)
         return (start - 3 * 30 * 24 * 60 * 60, end)
 
+    def get_starttime(self):
+        """Return the next_starttime from the state, if it is set.
+        """
+        return self.next_starttime
+
     def load_state(self):
         """Load algorithm state from a file.