Repository: pandas-dev/pandas

Issue:
BUG: creating multi-index with datetimes in the levels
http://stackoverflow.com/questions/25059140/pandas-multiindex-not-working-with-read-csv-and-datetime-objects/25059472#25059472

```
In [3]: date1 = datetime.date.today()

In [4]: date2 = datetime.date.today().replace(month=1)

In [5]: date_cols=['date1', 'date2']

In [6]: index = pd.MultiIndex.from_product([[date1],[date2]])
```

The first level of this multi-index is a `Index` of object dtyped `datetimes`, rather than a `DatetimeIndex`.

might be a bug in the creation process



Discussion:

Resolving patch:
diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py
--- a/pandas/core/categorical.py
+++ b/pandas/core/categorical.py
@@ -232,7 +232,7 @@ def __init__(self, values, levels=None, ordered=None, name=None, fastpath=False,
             # which is fine, but since factorize does this correctly no need here
             # this is an issue because _sanitize_array also coerces np.nan to a string
             # under certain versions of numpy as well
-            values = com._possibly_infer_to_datetimelike(values)
+            values = com._possibly_infer_to_datetimelike(values, convert_dates=True)
             if not isinstance(values, np.ndarray):
                 values = _convert_to_list_like(values)
                 from pandas.core.series import _sanitize_array
diff --git a/pandas/core/common.py b/pandas/core/common.py
--- a/pandas/core/common.py
+++ b/pandas/core/common.py
@@ -1961,15 +1961,24 @@ def _possibly_cast_to_datetime(value, dtype, coerce=False):
     return value
 
 
-def _possibly_infer_to_datetimelike(value):
-    # we might have a array (or single object) that is datetime like,
-    # and no dtype is passed don't change the value unless we find a
-    # datetime/timedelta set
+def _possibly_infer_to_datetimelike(value, convert_dates=False):
+    """
+    we might have a array (or single object) that is datetime like,
+    and no dtype is passed don't change the value unless we find a
+    datetime/timedelta set
+
+    this is pretty strict in that a datetime/timedelta is REQUIRED
+    in addition to possible nulls/string likes
+
+    ONLY strings are NOT datetimelike
 
-    # this is pretty strict in that a datetime/timedelta is REQUIRED
-    # in addition to possible nulls/string likes
+    Parameters
+    ----------
+    convert_dates : boolean, default False
+       if True try really hard to convert dates (such as datetime.date), other
+       leave inferred dtype 'date' alone
 
-    # ONLY strings are NOT datetimelike
+    """
 
     v = value
     if not is_list_like(v):
@@ -2011,7 +2020,7 @@ def _try_timedelta(v):
         sample = v[:min(3,len(v))]
         inferred_type = lib.infer_dtype(sample)
 
-        if inferred_type in ['datetime', 'datetime64']:
+        if inferred_type in ['datetime', 'datetime64'] or (convert_dates and inferred_type in ['date']):
             value = _try_datetime(v)
         elif inferred_type in ['timedelta', 'timedelta64']:
             value = _try_timedelta(v)


Test patch:
diff --git a/pandas/tests/test_multilevel.py b/pandas/tests/test_multilevel.py
--- a/pandas/tests/test_multilevel.py
+++ b/pandas/tests/test_multilevel.py
@@ -1,12 +1,13 @@
 # pylint: disable-msg=W0612,E1101,W0141
 import datetime
+import itertools
 import nose
 
 from numpy.random import randn
 import numpy as np
 
 from pandas.core.index import Index, MultiIndex
-from pandas import Panel, DataFrame, Series, notnull, isnull
+from pandas import Panel, DataFrame, Series, notnull, isnull, Timestamp
 
 from pandas.util.testing import (assert_almost_equal,
                                  assert_series_equal,
@@ -2066,6 +2067,17 @@ def test_datetimeindex(self):
         self.assertTrue(idx.levels[0].equals(expected1))
         self.assertTrue(idx.levels[1].equals(idx2))
 
+        # from datetime combos
+        # GH 7888
+        date1 = datetime.date.today()
+        date2 = datetime.datetime.today()
+        date3 = Timestamp.today()
+
+        for d1, d2 in itertools.product([date1,date2,date3],[date1,date2,date3]):
+            index = pd.MultiIndex.from_product([[d1],[d2]])
+            self.assertIsInstance(index.levels[0],pd.DatetimeIndex)
+            self.assertIsInstance(index.levels[1],pd.DatetimeIndex)
+
     def test_set_index_datetime(self):
         # GH 3950
         df = pd.DataFrame({'label':['a', 'a', 'a', 'b', 'b', 'b'],