We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SARIMAX predict does not actually allow for datetime start/end
Docs indicate it does, but TimeSeriesModel._get_predict_start requires either a string or an int.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `statsmodels/tsa/base/tsa_model.py`
Content:
```
1 from statsmodels.compat.python import lrange, long
2 from statsmodels.compat.pandas import is_numeric_dtype
3 
4 import datetime
5 
6 from pandas import to_datetime, DatetimeIndex, Period, PeriodIndex, Timestamp
7 
8 from statsmodels.base import data
9 import statsmodels.base.model as base
10 import statsmodels.base.wrapper as wrap
11 from statsmodels.tsa.base import datetools
12 
13 _freq_to_pandas = datetools._freq_to_pandas
14 
15 _tsa_doc = """
16     %(model)s
17 
18     Parameters
19     ----------
20     %(params)s
21     dates : array-like of datetime, optional
22         An array-like object of datetime objects. If a pandas object is given
23         for endog or exog, it is assumed to have a DateIndex.
24     freq : str, optional
25         The frequency of the time-series. A Pandas offset or 'B', 'D', 'W',
26         'M', 'A', or 'Q'. This is optional if dates are given.
27     %(extra_params)s
28     %(extra_sections)s
29 """
30 
31 _model_doc = "Timeseries model base class"
32 
33 _generic_params = base._model_params_doc
34 _missing_param_doc = base._missing_param_doc
35 
36 class TimeSeriesModel(base.LikelihoodModel):
37 
38     __doc__ = _tsa_doc % {"model" : _model_doc, "params" : _generic_params,
39                           "extra_params" : _missing_param_doc,
40                           "extra_sections" : ""}
41 
42     def __init__(self, endog, exog=None, dates=None, freq=None, missing='none'):
43         super(TimeSeriesModel, self).__init__(endog, exog, missing=missing)
44         self._init_dates(dates, freq)
45 
46     def _init_dates(self, dates, freq):
47         if dates is None:
48             dates = self.data.row_labels
49 
50         if dates is not None:
51             if (not datetools._is_datetime_index(dates) and
52                     isinstance(self.data, data.PandasData)):
53                 try:
54                     if is_numeric_dtype(dates):
55                         raise ValueError
56                     dates = to_datetime(dates)
57                 except ValueError:
58                     raise ValueError("Given a pandas object and the index does "
59                                      "not contain dates")
60             if not freq:
61                 try:
62                     freq = datetools._infer_freq(dates)
63                 except:
64                     raise ValueError("Frequency inference failed. Use `freq` "
65                                      "keyword.")
66 
67             if isinstance(dates[0], datetime.datetime):
68                 dates = DatetimeIndex(dates)
69             else: # preserve PeriodIndex
70                 dates = PeriodIndex(dates)
71         self.data.dates = dates
72         self.data.freq = freq
73 
74         # Test for nanoseconds in early pandas versions
75         if freq is not None and _freq_to_pandas[freq].freqstr == 'N':
76             from distutils.version import LooseVersion
77             from pandas import __version__ as pd_version
78             if LooseVersion(pd_version) < '0.14':
79                 raise NotImplementedError('Nanosecond index not available in'
80                                           ' Pandas < 0.14')
81 
82 
83     def _get_exog_names(self):
84         return self.data.xnames
85 
86     def _set_exog_names(self, vals):
87         if not isinstance(vals, list):
88             vals = [vals]
89         self.data.xnames = vals
90 
91     #overwrite with writable property for (V)AR models
92     exog_names = property(_get_exog_names, _set_exog_names)
93 
94     def _get_dates_loc(self, dates, date):
95         date = dates.get_loc(date)
96         return date
97 
98     def _str_to_date(self, date):
99         """
100         Takes a string and returns a datetime object
101         """
102         if isinstance(self.data.dates, PeriodIndex):
103             return Period(date)
104         else:
105             return datetools.date_parser(date)
106 
107     def _set_predict_start_date(self, start):
108         dates = self.data.dates
109         if dates is None:
110             return
111         if start > len(dates):
112             raise ValueError("Start must be <= len(endog)")
113         if start == len(dates):
114             self.data.predict_start = datetools._date_from_idx(dates[-1],
115                                                     1, self.data.freq)
116         elif start < len(dates):
117             self.data.predict_start = dates[start]
118         else:
119             raise ValueError("Start must be <= len(dates)")
120 
121     def _get_predict_start(self, start):
122         """
123         Returns the index of the given start date. Subclasses should define
124         default behavior for start = None. That isn't handled here.
125 
126         Start can be a string or an integer if self.data.dates is None.
127         """
128         dates = self.data.dates
129         if not isinstance(start, (int, long)):
130             start = str(start)
131             if dates is None:
132                 raise ValueError("Got a string for start and dates is None")
133             dtstart = self._str_to_date(start)
134             self.data.predict_start = dtstart
135             try:
136                 start = self._get_dates_loc(dates, dtstart)
137             except KeyError:
138                 raise ValueError("Start must be in dates. Got %s | %s" %
139                         (str(start), str(dtstart)))
140 
141         self._set_predict_start_date(start)
142         return start
143 
144 
145     def _get_predict_end(self, end):
146         """
147         See _get_predict_start for more information. Subclasses do not
148         need to define anything for this.
149         """
150 
151         out_of_sample = 0 # will be overwritten if needed
152         if end is None: # use data for ARIMA - endog changes
153             end = len(self.data.endog) - 1
154 
155         dates = self.data.dates
156         freq = self.data.freq
157 
158         if isinstance(end, str) or (dates is not None
159                                     and isinstance(end, type(dates[0]))):
160             if dates is None:
161                 raise ValueError("Got a string or date for `end` and `dates` is None")
162 
163             if isinstance(end, str):
164                 dtend = self._str_to_date(end)
165             else:
166                 dtend = end  # end could be a pandas TimeStamp not a datetime
167 
168             self.data.predict_end = dtend
169             try:
170                 end = self._get_dates_loc(dates, dtend)
171             except KeyError as err: # end is greater than dates[-1]...probably
172                 if dtend > self.data.dates[-1]:
173                     end = len(self.data.endog) - 1
174                     freq = self.data.freq
175                     out_of_sample = datetools._idx_from_dates(dates[-1], dtend,
176                                             freq)
177                 else:
178                     if freq is None:
179                         raise ValueError("There is no frequency for these "
180                                          "dates and date %s is not in dates "
181                                          "index. Try giving a date that is in "
182                                          "the dates index or use an integer."
183                                          % dtend)
184                     else: #pragma: no cover
185                         raise err # should never get here
186             self._make_predict_dates() # attaches self.data.predict_dates
187 
188         elif isinstance(end, (int, long)) and dates is not None:
189             try:
190                 self.data.predict_end = dates[end]
191             except IndexError as err:
192                 nobs = len(self.data.endog) - 1 # as an index
193                 out_of_sample = end - nobs
194                 end = nobs
195                 if freq is not None:
196                     self.data.predict_end = datetools._date_from_idx(dates[-1],
197                             out_of_sample, freq)
198                 elif out_of_sample <= 0: # have no frequency but are in sample
199                     #TODO: what error to catch here to make sure dates is
200                     #on the index?
201                     try:
202                         self.data.predict_end = self._get_dates_loc(dates, end)
203                     except KeyError:
204                         raise
205                 else:
206                     self.data.predict_end = end + out_of_sample
207                     self.data.predict_start = self._get_dates_loc(dates,
208                                                 self.data.predict_start)
209 
210             self._make_predict_dates()
211 
212         elif isinstance(end, (int, long)):
213             nobs = len(self.data.endog) - 1 # is an index
214             if end > nobs:
215                 out_of_sample = end - nobs
216                 end = nobs
217 
218         elif freq is None: # should have a date with freq = None
219             print('#'*80)
220             print(freq)
221             print(type(freq))
222             print('#'*80)
223             raise ValueError("When freq is None, you must give an integer "
224                              "index for end.")
225 
226         else:
227             print('#'*80)
228             print(freq)
229             print(type(freq))
230             print('#'*80)
231             raise ValueError("no rule for interpreting end")
232 
233         return end, out_of_sample
234 
235     def _make_predict_dates(self):
236         data = self.data
237         dtstart = data.predict_start
238         dtend = data.predict_end
239         freq = data.freq
240 
241         if freq is not None:
242             pandas_freq = _freq_to_pandas[freq]
243             # preserve PeriodIndex or DatetimeIndex
244             dates = self.data.dates.__class__(start=dtstart,
245                                               end=dtend,
246                                               freq=pandas_freq)
247 
248             if pandas_freq.freqstr == 'N':
249                 _dtend = dtend
250                 if isinstance(dates[-1], Period):
251                     _dtend = pd.to_datetime(_dtend).to_period(dates.freq)
252                 if not dates[-1] == _dtend:
253                     # TODO: this is a hack because a DatetimeIndex with
254                     # nanosecond frequency does not include "end"
255                     dtend = Timestamp(dtend.value + 1)
256                     dates = self.data.dates.__class__(start=dtstart,
257                                                       end=dtend,
258                                                       freq=pandas_freq)
259         # handle
260         elif freq is None and (isinstance(dtstart, (int, long)) and
261                                isinstance(dtend, (int, long))):
262             from pandas import Index
263             dates = Index(lrange(dtstart, dtend+1))
264         # if freq is None and dtstart and dtend aren't integers, we're
265         # in sample
266         else:
267             dates = self.data.dates
268             start = self._get_dates_loc(dates, dtstart)
269             end = self._get_dates_loc(dates, dtend)
270             dates = dates[start:end+1] # is this index inclusive?
271         self.data.predict_dates = dates
272 
273 class TimeSeriesModelResults(base.LikelihoodModelResults):
274     def __init__(self, model, params, normalized_cov_params, scale=1.):
275         self.data = model.data
276         super(TimeSeriesModelResults,
277                 self).__init__(model, params, normalized_cov_params, scale)
278 
279 class TimeSeriesResultsWrapper(wrap.ResultsWrapper):
280     _attrs = {}
281     _wrap_attrs = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_attrs,
282                                     _attrs)
283     _methods = {'predict' : 'dates'}
284     _wrap_methods = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_methods,
285                                      _methods)
286 wrap.populate_wrapper(TimeSeriesResultsWrapper,
287                       TimeSeriesModelResults)
288 
289 if __name__ == "__main__":
290     import statsmodels.api as sm
291     import pandas
292 
293     data = sm.datasets.macrodata.load()
294 
295     #make a DataFrame
296     #TODO: attach a DataFrame to some of the datasets, for quicker use
297     dates = [str(int(x[0])) +':'+ str(int(x[1])) \
298              for x in data.data[['year','quarter']]]
299 
300     df = pandas.DataFrame(data.data[['realgdp','realinv','realcons']], index=dates)
301     ex_mod = TimeSeriesModel(df)
302
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/statsmodels/tsa/base/tsa_model.py b/statsmodels/tsa/base/tsa_model.py
--- a/statsmodels/tsa/base/tsa_model.py
+++ b/statsmodels/tsa/base/tsa_model.py
@@ -155,6 +155,9 @@
         dates = self.data.dates
         freq = self.data.freq
 
+        if isinstance(end, datetime.datetime):
+            end = self._str_to_date(str(end))
+
         if isinstance(end, str) or (dates is not None
                                     and isinstance(end, type(dates[0]))):
             if dates is None:

{"golden_diff": "diff --git a/statsmodels/tsa/base/tsa_model.py b/statsmodels/tsa/base/tsa_model.py\n--- a/statsmodels/tsa/base/tsa_model.py\n+++ b/statsmodels/tsa/base/tsa_model.py\n@@ -155,6 +155,9 @@\n         dates = self.data.dates\n         freq = self.data.freq\n \n+        if isinstance(end, datetime.datetime):\n+            end = self._str_to_date(str(end))\n+\n         if isinstance(end, str) or (dates is not None\n                                     and isinstance(end, type(dates[0]))):\n             if dates is None:\n", "issue": "SARIMAX predict does not actually allow for datetime start/end\nDocs indicate it does, but TimeSeriesModel._get_predict_start requires either a string or an int.\n\n", "before_files": [{"content": "from statsmodels.compat.python import lrange, long\nfrom statsmodels.compat.pandas import is_numeric_dtype\n\nimport datetime\n\nfrom pandas import to_datetime, DatetimeIndex, Period, PeriodIndex, Timestamp\n\nfrom statsmodels.base import data\nimport statsmodels.base.model as base\nimport statsmodels.base.wrapper as wrap\nfrom statsmodels.tsa.base import datetools\n\n_freq_to_pandas = datetools._freq_to_pandas\n\n_tsa_doc = \"\"\"\n    %(model)s\n\n    Parameters\n    ----------\n    %(params)s\n    dates : array-like of datetime, optional\n        An array-like object of datetime objects. If a pandas object is given\n        for endog or exog, it is assumed to have a DateIndex.\n    freq : str, optional\n        The frequency of the time-series. A Pandas offset or 'B', 'D', 'W',\n        'M', 'A', or 'Q'. This is optional if dates are given.\n    %(extra_params)s\n    %(extra_sections)s\n\"\"\"\n\n_model_doc = \"Timeseries model base class\"\n\n_generic_params = base._model_params_doc\n_missing_param_doc = base._missing_param_doc\n\nclass TimeSeriesModel(base.LikelihoodModel):\n\n    __doc__ = _tsa_doc % {\"model\" : _model_doc, \"params\" : _generic_params,\n                          \"extra_params\" : _missing_param_doc,\n                          \"extra_sections\" : \"\"}\n\n    def __init__(self, endog, exog=None, dates=None, freq=None, missing='none'):\n        super(TimeSeriesModel, self).__init__(endog, exog, missing=missing)\n        self._init_dates(dates, freq)\n\n    def _init_dates(self, dates, freq):\n        if dates is None:\n            dates = self.data.row_labels\n\n        if dates is not None:\n            if (not datetools._is_datetime_index(dates) and\n                    isinstance(self.data, data.PandasData)):\n                try:\n                    if is_numeric_dtype(dates):\n                        raise ValueError\n                    dates = to_datetime(dates)\n                except ValueError:\n                    raise ValueError(\"Given a pandas object and the index does \"\n                                     \"not contain dates\")\n            if not freq:\n                try:\n                    freq = datetools._infer_freq(dates)\n                except:\n                    raise ValueError(\"Frequency inference failed. Use `freq` \"\n                                     \"keyword.\")\n\n            if isinstance(dates[0], datetime.datetime):\n                dates = DatetimeIndex(dates)\n            else: # preserve PeriodIndex\n                dates = PeriodIndex(dates)\n        self.data.dates = dates\n        self.data.freq = freq\n\n        # Test for nanoseconds in early pandas versions\n        if freq is not None and _freq_to_pandas[freq].freqstr == 'N':\n            from distutils.version import LooseVersion\n            from pandas import __version__ as pd_version\n            if LooseVersion(pd_version) < '0.14':\n                raise NotImplementedError('Nanosecond index not available in'\n                                          ' Pandas < 0.14')\n\n\n    def _get_exog_names(self):\n        return self.data.xnames\n\n    def _set_exog_names(self, vals):\n        if not isinstance(vals, list):\n            vals = [vals]\n        self.data.xnames = vals\n\n    #overwrite with writable property for (V)AR models\n    exog_names = property(_get_exog_names, _set_exog_names)\n\n    def _get_dates_loc(self, dates, date):\n        date = dates.get_loc(date)\n        return date\n\n    def _str_to_date(self, date):\n        \"\"\"\n        Takes a string and returns a datetime object\n        \"\"\"\n        if isinstance(self.data.dates, PeriodIndex):\n            return Period(date)\n        else:\n            return datetools.date_parser(date)\n\n    def _set_predict_start_date(self, start):\n        dates = self.data.dates\n        if dates is None:\n            return\n        if start > len(dates):\n            raise ValueError(\"Start must be <= len(endog)\")\n        if start == len(dates):\n            self.data.predict_start = datetools._date_from_idx(dates[-1],\n                                                    1, self.data.freq)\n        elif start < len(dates):\n            self.data.predict_start = dates[start]\n        else:\n            raise ValueError(\"Start must be <= len(dates)\")\n\n    def _get_predict_start(self, start):\n        \"\"\"\n        Returns the index of the given start date. Subclasses should define\n        default behavior for start = None. That isn't handled here.\n\n        Start can be a string or an integer if self.data.dates is None.\n        \"\"\"\n        dates = self.data.dates\n        if not isinstance(start, (int, long)):\n            start = str(start)\n            if dates is None:\n                raise ValueError(\"Got a string for start and dates is None\")\n            dtstart = self._str_to_date(start)\n            self.data.predict_start = dtstart\n            try:\n                start = self._get_dates_loc(dates, dtstart)\n            except KeyError:\n                raise ValueError(\"Start must be in dates. Got %s | %s\" %\n                        (str(start), str(dtstart)))\n\n        self._set_predict_start_date(start)\n        return start\n\n\n    def _get_predict_end(self, end):\n        \"\"\"\n        See _get_predict_start for more information. Subclasses do not\n        need to define anything for this.\n        \"\"\"\n\n        out_of_sample = 0 # will be overwritten if needed\n        if end is None: # use data for ARIMA - endog changes\n            end = len(self.data.endog) - 1\n\n        dates = self.data.dates\n        freq = self.data.freq\n\n        if isinstance(end, str) or (dates is not None\n                                    and isinstance(end, type(dates[0]))):\n            if dates is None:\n                raise ValueError(\"Got a string or date for `end` and `dates` is None\")\n\n            if isinstance(end, str):\n                dtend = self._str_to_date(end)\n            else:\n                dtend = end  # end could be a pandas TimeStamp not a datetime\n\n            self.data.predict_end = dtend\n            try:\n                end = self._get_dates_loc(dates, dtend)\n            except KeyError as err: # end is greater than dates[-1]...probably\n                if dtend > self.data.dates[-1]:\n                    end = len(self.data.endog) - 1\n                    freq = self.data.freq\n                    out_of_sample = datetools._idx_from_dates(dates[-1], dtend,\n                                            freq)\n                else:\n                    if freq is None:\n                        raise ValueError(\"There is no frequency for these \"\n                                         \"dates and date %s is not in dates \"\n                                         \"index. Try giving a date that is in \"\n                                         \"the dates index or use an integer.\"\n                                         % dtend)\n                    else: #pragma: no cover\n                        raise err # should never get here\n            self._make_predict_dates() # attaches self.data.predict_dates\n\n        elif isinstance(end, (int, long)) and dates is not None:\n            try:\n                self.data.predict_end = dates[end]\n            except IndexError as err:\n                nobs = len(self.data.endog) - 1 # as an index\n                out_of_sample = end - nobs\n                end = nobs\n                if freq is not None:\n                    self.data.predict_end = datetools._date_from_idx(dates[-1],\n                            out_of_sample, freq)\n                elif out_of_sample <= 0: # have no frequency but are in sample\n                    #TODO: what error to catch here to make sure dates is\n                    #on the index?\n                    try:\n                        self.data.predict_end = self._get_dates_loc(dates, end)\n                    except KeyError:\n                        raise\n                else:\n                    self.data.predict_end = end + out_of_sample\n                    self.data.predict_start = self._get_dates_loc(dates,\n                                                self.data.predict_start)\n\n            self._make_predict_dates()\n\n        elif isinstance(end, (int, long)):\n            nobs = len(self.data.endog) - 1 # is an index\n            if end > nobs:\n                out_of_sample = end - nobs\n                end = nobs\n\n        elif freq is None: # should have a date with freq = None\n            print('#'*80)\n            print(freq)\n            print(type(freq))\n            print('#'*80)\n            raise ValueError(\"When freq is None, you must give an integer \"\n                             \"index for end.\")\n\n        else:\n            print('#'*80)\n            print(freq)\n            print(type(freq))\n            print('#'*80)\n            raise ValueError(\"no rule for interpreting end\")\n\n        return end, out_of_sample\n\n    def _make_predict_dates(self):\n        data = self.data\n        dtstart = data.predict_start\n        dtend = data.predict_end\n        freq = data.freq\n\n        if freq is not None:\n            pandas_freq = _freq_to_pandas[freq]\n            # preserve PeriodIndex or DatetimeIndex\n            dates = self.data.dates.__class__(start=dtstart,\n                                              end=dtend,\n                                              freq=pandas_freq)\n\n            if pandas_freq.freqstr == 'N':\n                _dtend = dtend\n                if isinstance(dates[-1], Period):\n                    _dtend = pd.to_datetime(_dtend).to_period(dates.freq)\n                if not dates[-1] == _dtend:\n                    # TODO: this is a hack because a DatetimeIndex with\n                    # nanosecond frequency does not include \"end\"\n                    dtend = Timestamp(dtend.value + 1)\n                    dates = self.data.dates.__class__(start=dtstart,\n                                                      end=dtend,\n                                                      freq=pandas_freq)\n        # handle\n        elif freq is None and (isinstance(dtstart, (int, long)) and\n                               isinstance(dtend, (int, long))):\n            from pandas import Index\n            dates = Index(lrange(dtstart, dtend+1))\n        # if freq is None and dtstart and dtend aren't integers, we're\n        # in sample\n        else:\n            dates = self.data.dates\n            start = self._get_dates_loc(dates, dtstart)\n            end = self._get_dates_loc(dates, dtend)\n            dates = dates[start:end+1] # is this index inclusive?\n        self.data.predict_dates = dates\n\nclass TimeSeriesModelResults(base.LikelihoodModelResults):\n    def __init__(self, model, params, normalized_cov_params, scale=1.):\n        self.data = model.data\n        super(TimeSeriesModelResults,\n                self).__init__(model, params, normalized_cov_params, scale)\n\nclass TimeSeriesResultsWrapper(wrap.ResultsWrapper):\n    _attrs = {}\n    _wrap_attrs = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_attrs,\n                                    _attrs)\n    _methods = {'predict' : 'dates'}\n    _wrap_methods = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_methods,\n                                     _methods)\nwrap.populate_wrapper(TimeSeriesResultsWrapper,\n                      TimeSeriesModelResults)\n\nif __name__ == \"__main__\":\n    import statsmodels.api as sm\n    import pandas\n\n    data = sm.datasets.macrodata.load()\n\n    #make a DataFrame\n    #TODO: attach a DataFrame to some of the datasets, for quicker use\n    dates = [str(int(x[0])) +':'+ str(int(x[1])) \\\n             for x in data.data[['year','quarter']]]\n\n    df = pandas.DataFrame(data.data[['realgdp','realinv','realcons']], index=dates)\n    ex_mod = TimeSeriesModel(df)\n", "path": "statsmodels/tsa/base/tsa_model.py"}], "after_files": [{"content": "from statsmodels.compat.python import lrange, long\nfrom statsmodels.compat.pandas import is_numeric_dtype\n\nimport datetime\n\nfrom pandas import to_datetime, DatetimeIndex, Period, PeriodIndex, Timestamp\n\nfrom statsmodels.base import data\nimport statsmodels.base.model as base\nimport statsmodels.base.wrapper as wrap\nfrom statsmodels.tsa.base import datetools\n\n_freq_to_pandas = datetools._freq_to_pandas\n\n_tsa_doc = \"\"\"\n    %(model)s\n\n    Parameters\n    ----------\n    %(params)s\n    dates : array-like of datetime, optional\n        An array-like object of datetime objects. If a pandas object is given\n        for endog or exog, it is assumed to have a DateIndex.\n    freq : str, optional\n        The frequency of the time-series. A Pandas offset or 'B', 'D', 'W',\n        'M', 'A', or 'Q'. This is optional if dates are given.\n    %(extra_params)s\n    %(extra_sections)s\n\"\"\"\n\n_model_doc = \"Timeseries model base class\"\n\n_generic_params = base._model_params_doc\n_missing_param_doc = base._missing_param_doc\n\nclass TimeSeriesModel(base.LikelihoodModel):\n\n    __doc__ = _tsa_doc % {\"model\" : _model_doc, \"params\" : _generic_params,\n                          \"extra_params\" : _missing_param_doc,\n                          \"extra_sections\" : \"\"}\n\n    def __init__(self, endog, exog=None, dates=None, freq=None, missing='none'):\n        super(TimeSeriesModel, self).__init__(endog, exog, missing=missing)\n        self._init_dates(dates, freq)\n\n    def _init_dates(self, dates, freq):\n        if dates is None:\n            dates = self.data.row_labels\n\n        if dates is not None:\n            if (not datetools._is_datetime_index(dates) and\n                    isinstance(self.data, data.PandasData)):\n                try:\n                    if is_numeric_dtype(dates):\n                        raise ValueError\n                    dates = to_datetime(dates)\n                except ValueError:\n                    raise ValueError(\"Given a pandas object and the index does \"\n                                     \"not contain dates\")\n            if not freq:\n                try:\n                    freq = datetools._infer_freq(dates)\n                except:\n                    raise ValueError(\"Frequency inference failed. Use `freq` \"\n                                     \"keyword.\")\n\n            if isinstance(dates[0], datetime.datetime):\n                dates = DatetimeIndex(dates)\n            else: # preserve PeriodIndex\n                dates = PeriodIndex(dates)\n        self.data.dates = dates\n        self.data.freq = freq\n\n        # Test for nanoseconds in early pandas versions\n        if freq is not None and _freq_to_pandas[freq].freqstr == 'N':\n            from distutils.version import LooseVersion\n            from pandas import __version__ as pd_version\n            if LooseVersion(pd_version) < '0.14':\n                raise NotImplementedError('Nanosecond index not available in'\n                                          ' Pandas < 0.14')\n\n\n    def _get_exog_names(self):\n        return self.data.xnames\n\n    def _set_exog_names(self, vals):\n        if not isinstance(vals, list):\n            vals = [vals]\n        self.data.xnames = vals\n\n    #overwrite with writable property for (V)AR models\n    exog_names = property(_get_exog_names, _set_exog_names)\n\n    def _get_dates_loc(self, dates, date):\n        date = dates.get_loc(date)\n        return date\n\n    def _str_to_date(self, date):\n        \"\"\"\n        Takes a string and returns a datetime object\n        \"\"\"\n        if isinstance(self.data.dates, PeriodIndex):\n            return Period(date)\n        else:\n            return datetools.date_parser(date)\n\n    def _set_predict_start_date(self, start):\n        dates = self.data.dates\n        if dates is None:\n            return\n        if start > len(dates):\n            raise ValueError(\"Start must be <= len(endog)\")\n        if start == len(dates):\n            self.data.predict_start = datetools._date_from_idx(dates[-1],\n                                                    1, self.data.freq)\n        elif start < len(dates):\n            self.data.predict_start = dates[start]\n        else:\n            raise ValueError(\"Start must be <= len(dates)\")\n\n    def _get_predict_start(self, start):\n        \"\"\"\n        Returns the index of the given start date. Subclasses should define\n        default behavior for start = None. That isn't handled here.\n\n        Start can be a string or an integer if self.data.dates is None.\n        \"\"\"\n        dates = self.data.dates\n        if not isinstance(start, (int, long)):\n            start = str(start)\n            if dates is None:\n                raise ValueError(\"Got a string for start and dates is None\")\n            dtstart = self._str_to_date(start)\n            self.data.predict_start = dtstart\n            try:\n                start = self._get_dates_loc(dates, dtstart)\n            except KeyError:\n                raise ValueError(\"Start must be in dates. Got %s | %s\" %\n                        (str(start), str(dtstart)))\n\n        self._set_predict_start_date(start)\n        return start\n\n\n    def _get_predict_end(self, end):\n        \"\"\"\n        See _get_predict_start for more information. Subclasses do not\n        need to define anything for this.\n        \"\"\"\n\n        out_of_sample = 0 # will be overwritten if needed\n        if end is None: # use data for ARIMA - endog changes\n            end = len(self.data.endog) - 1\n\n        dates = self.data.dates\n        freq = self.data.freq\n\n        if isinstance(end, datetime.datetime):\n            end = self._str_to_date(str(end))\n\n        if isinstance(end, str) or (dates is not None\n                                    and isinstance(end, type(dates[0]))):\n            if dates is None:\n                raise ValueError(\"Got a string or date for `end` and `dates` is None\")\n\n            if isinstance(end, str):\n                dtend = self._str_to_date(end)\n            else:\n                dtend = end  # end could be a pandas TimeStamp not a datetime\n\n            self.data.predict_end = dtend\n            try:\n                end = self._get_dates_loc(dates, dtend)\n            except KeyError as err: # end is greater than dates[-1]...probably\n                if dtend > self.data.dates[-1]:\n                    end = len(self.data.endog) - 1\n                    freq = self.data.freq\n                    out_of_sample = datetools._idx_from_dates(dates[-1], dtend,\n                                            freq)\n                else:\n                    if freq is None:\n                        raise ValueError(\"There is no frequency for these \"\n                                         \"dates and date %s is not in dates \"\n                                         \"index. Try giving a date that is in \"\n                                         \"the dates index or use an integer.\"\n                                         % dtend)\n                    else: #pragma: no cover\n                        raise err # should never get here\n            self._make_predict_dates() # attaches self.data.predict_dates\n\n        elif isinstance(end, (int, long)) and dates is not None:\n            try:\n                self.data.predict_end = dates[end]\n            except IndexError as err:\n                nobs = len(self.data.endog) - 1 # as an index\n                out_of_sample = end - nobs\n                end = nobs\n                if freq is not None:\n                    self.data.predict_end = datetools._date_from_idx(dates[-1],\n                            out_of_sample, freq)\n                elif out_of_sample <= 0: # have no frequency but are in sample\n                    #TODO: what error to catch here to make sure dates is\n                    #on the index?\n                    try:\n                        self.data.predict_end = self._get_dates_loc(dates, end)\n                    except KeyError:\n                        raise\n                else:\n                    self.data.predict_end = end + out_of_sample\n                    self.data.predict_start = self._get_dates_loc(dates,\n                                                self.data.predict_start)\n\n            self._make_predict_dates()\n\n        elif isinstance(end, (int, long)):\n            nobs = len(self.data.endog) - 1 # is an index\n            if end > nobs:\n                out_of_sample = end - nobs\n                end = nobs\n\n        elif freq is None: # should have a date with freq = None\n            print('#'*80)\n            print(freq)\n            print(type(freq))\n            print('#'*80)\n            raise ValueError(\"When freq is None, you must give an integer \"\n                             \"index for end.\")\n\n        else:\n            print('#'*80)\n            print(freq)\n            print(type(freq))\n            print('#'*80)\n            raise ValueError(\"no rule for interpreting end\")\n\n        return end, out_of_sample\n\n    def _make_predict_dates(self):\n        data = self.data\n        dtstart = data.predict_start\n        dtend = data.predict_end\n        freq = data.freq\n\n        if freq is not None:\n            pandas_freq = _freq_to_pandas[freq]\n            # preserve PeriodIndex or DatetimeIndex\n            dates = self.data.dates.__class__(start=dtstart,\n                                              end=dtend,\n                                              freq=pandas_freq)\n\n            if pandas_freq.freqstr == 'N':\n                _dtend = dtend\n                if isinstance(dates[-1], Period):\n                    _dtend = pd.to_datetime(_dtend).to_period(dates.freq)\n                if not dates[-1] == _dtend:\n                    # TODO: this is a hack because a DatetimeIndex with\n                    # nanosecond frequency does not include \"end\"\n                    dtend = Timestamp(dtend.value + 1)\n                    dates = self.data.dates.__class__(start=dtstart,\n                                                      end=dtend,\n                                                      freq=pandas_freq)\n        # handle\n        elif freq is None and (isinstance(dtstart, (int, long)) and\n                               isinstance(dtend, (int, long))):\n            from pandas import Index\n            dates = Index(lrange(dtstart, dtend+1))\n        # if freq is None and dtstart and dtend aren't integers, we're\n        # in sample\n        else:\n            dates = self.data.dates\n            start = self._get_dates_loc(dates, dtstart)\n            end = self._get_dates_loc(dates, dtend)\n            dates = dates[start:end+1] # is this index inclusive?\n        self.data.predict_dates = dates\n\nclass TimeSeriesModelResults(base.LikelihoodModelResults):\n    def __init__(self, model, params, normalized_cov_params, scale=1.):\n        self.data = model.data\n        super(TimeSeriesModelResults,\n                self).__init__(model, params, normalized_cov_params, scale)\n\nclass TimeSeriesResultsWrapper(wrap.ResultsWrapper):\n    _attrs = {}\n    _wrap_attrs = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_attrs,\n                                    _attrs)\n    _methods = {'predict' : 'dates'}\n    _wrap_methods = wrap.union_dicts(base.LikelihoodResultsWrapper._wrap_methods,\n                                     _methods)\nwrap.populate_wrapper(TimeSeriesResultsWrapper,\n                      TimeSeriesModelResults)\n\nif __name__ == \"__main__\":\n    import statsmodels.api as sm\n    import pandas\n\n    data = sm.datasets.macrodata.load()\n\n    #make a DataFrame\n    #TODO: attach a DataFrame to some of the datasets, for quicker use\n    dates = [str(int(x[0])) +':'+ str(int(x[1])) \\\n             for x in data.data[['year','quarter']]]\n\n    df = pandas.DataFrame(data.data[['realgdp','realinv','realcons']], index=dates)\n    ex_mod = TimeSeriesModel(df)\n", "path": "statsmodels/tsa/base/tsa_model.py"}]}