Repository: pandas-dev/pandas

Issue:
DateTimeIndex appending with loc inconsistency in handling numpy datetime64
This is in Pandas `0.15.2` (but I also tried it on '0.15.2-148-g484f668'):

``` python
df = pd.DataFrame()
df.loc[np.datetime64(datetime.datetime.now()),'one'] = 100
df.loc[np.datetime64(datetime.datetime.now()),'one'] = 100
```

This is the output:

``` text
                               one
2015-02-18 14:50:05.606510     100
1970-01-17 11:37:51.007748755  100
```

It seems the the first usage of `loc` correctly works around limitations of `datetime64` but I cannot explain the second one.



Discussion:
I had a quick peek.  Inside `_NDFrameIndexer._setitem_with_indexer()`, this line here: `self.obj._data = self.obj.reindex_axis(labels, i)._data` is where the labels go from good to bad.  The first reference to labels inside `NDFrame.reindex_axis(...)` is erroneous...

This code might help somebody more senior than I:

```
from pandas import DataFrame
from numpy import datetime64 as d64
from datetime import datetime as dt

df = DataFrame()

df.loc[d64(dt(2015,1,1,1,1,1)),'C1'] = 'GOOD'
df.loc[d64(dt(2015,1,1,1,1,1)),'C1'] = 'BAD'
df.loc[d64(dt(2015,1,1,1,1,2)),'C1'] = 'sec'
df.loc[d64(dt(2015,1,1,1,2,1)),'C1'] = 'min'
df.loc[d64(dt(2015,1,1,2,1,1)),'C1'] = 'hr'
df.loc[d64(dt(2015,1,2,1,1,1)),'C1'] = 'day'
df.loc[d64(dt(2015,2,1,1,1,1)),'C1'] = 'mth'
```

```
>>> df
                             C1
2015-01-01 01:01:01         BAD
1970-01-17 10:27:54.062000  sec
1970-01-17 10:27:54.121000  min
1970-01-17 10:27:57.661000   hr
1970-01-17 10:29:20.461000  day
1970-01-17 11:12:32.461000  mth
```

Notice the date component dropped,  And the month/day/hour/minute/second specified is incrementing hour/minute/... _respectively_.  Also notice that "GOOD" is over-written, by "BAD".


Resolving patch:
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -246,6 +246,7 @@ def _setitem_with_indexer(self, indexer, value):
                         new_indexer = convert_from_missing_indexer_tuple(
                             indexer, self.obj.axes)
                         self._setitem_with_indexer(new_indexer, value)
+
                         return self.obj
 
                     # reindex the axis
diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py
--- a/pandas/tseries/index.py
+++ b/pandas/tseries/index.py
@@ -1509,7 +1509,7 @@ def insert(self, loc, item):
         """
 
         freq = None
-        if isinstance(item, datetime):
+        if isinstance(item, (datetime, np.datetime64)):
             zone = tslib.get_timezone(self.tz)
             izone = tslib.get_timezone(getattr(item, 'tzinfo', None))
             if zone != izone:


Test patch:
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -3171,6 +3171,22 @@ def test_partial_setting_with_datetimelike_dtype(self):
         df.loc[mask, 'C'] = df.loc[mask].index
         assert_frame_equal(df, expected)
 
+    def test_loc_setitem_datetime(self):
+
+        # GH 9516
+        dt1 = Timestamp('20130101 09:00:00')
+        dt2 = Timestamp('20130101 10:00:00')
+
+        for conv in [lambda x: x, lambda x: x.to_datetime64(),
+                     lambda x: x.to_pydatetime(), lambda x: np.datetime64(x)]:
+
+            df = pd.DataFrame()
+            df.loc[conv(dt1),'one'] = 100
+            df.loc[conv(dt2),'one'] = 200
+
+            expected = DataFrame({'one' : [100.0,200.0]},index=[dt1,dt2])
+            assert_frame_equal(df, expected)
+
     def test_series_partial_set(self):
         # partial set with new index
         # Regression from GH4825