@@ -279,6 +279,7 @@ def test_concat_NaT_series_dataframe_all_NaT(self, tz1, tz2):
279279 tm .assert_frame_equal (result , expected )
280280
281281 def test_concat_ns_and_s_preserves_datetime64 (self ):
282+ # GH 53307
282283 # ensure concatenating a datetime64[ns] column and a copy cast to M8[s]
283284 # yields a datetime64 dtype (finest unit should be ns)
284285 df = pd .DataFrame (
@@ -617,24 +618,51 @@ def test_concat_float_datetime64():
617618 result = concat ([df_time , df_float .iloc [:0 ]])
618619 tm .assert_frame_equal (result , expected )
619620
620- @pytest .mark .parametrize ("order" , [[0 , 1 ], [1 , 0 ]])
621- def test_concat_ns_and_s_order_invariance (order ):
622- df = pd .DataFrame (
623- {"ints" : range (2 ), "dates" : pd .date_range ("2000" , periods = 2 , freq = "min" )}
624- )
621+
622+ @pytest .mark .parametrize (
623+ "unit,unit2" ,
624+ [(u1 , u2 ) for u1 in ("ns" , "us" , "ms" , "s" ) for u2 in ("ns" , "us" , "ms" , "s" )],
625+ )
626+ def test_concat_mixed_units_preserve_datetime_and_unit (unit , unit2 ):
627+ # GH 53307
628+ # for each pair of units, concatenating columns of those units should
629+ # result in a datetime64 dtype with the finest unit
630+ df = pd .DataFrame ({"dates" : pd .to_datetime (["2000-01-01" , "2000-01-02" ])})
631+ # cast copies to requested unit
632+ df1 = df .copy ()
633+ df1 ["dates" ] = df1 ["dates" ].astype (f"M8[{ unit } ]" )
625634 df2 = df .copy ()
626- df2 ["dates" ] = df2 ["dates" ].astype ("M8[s ]" )
635+ df2 ["dates" ] = df2 ["dates" ].astype (f "M8[{ unit2 } ]" )
627636
628- parts = [df , df2 ]
629- combined = pd .concat ([parts [i ] for i in order ], ignore_index = True )
637+ exp_unit = tm .get_finest_unit (unit , unit2 )
630638
631- assert pd .api .types .is_datetime64_any_dtype (combined ["dates" ].dtype )
639+ # test both concat orders
640+ for a , b in ((df1 , df2 ), (df2 , df1 )):
641+ combined = pd .concat ([a , b ], ignore_index = True )
642+
643+ assert pd .api .types .is_datetime64_any_dtype (combined ["dates" ].dtype )
644+
645+ res_unit = np .datetime_data (combined ["dates" ].dtype )[0 ]
646+ assert res_unit == exp_unit
647+
648+
649+ @pytest .mark .parametrize (
650+ "unit,unit2" ,
651+ [(u1 , u2 ) for u1 in ("ns" , "us" , "ms" , "s" ) for u2 in ("ns" , "us" , "ms" , "s" )],
652+ )
653+ def test_concat_mixed_units_with_all_nat (unit , unit2 ):
654+ # GH 53307
655+ # mixing non-empty datetime column and an all-NaT column typed to unit2
656+ df = pd .DataFrame ({"dates" : pd .to_datetime (["2000-01-01" ])})
657+ df1 = df .copy ()
658+ df1 ["dates" ] = df1 ["dates" ].astype (f"M8[{ unit } ]" )
632659
660+ ser_nat = pd .Series ([pd .NaT ], dtype = f"datetime64[{ unit2 } ]" )
661+ df2 = pd .DataFrame ({"dates" : ser_nat })
633662
634- def test_concat_ns_and_s_with_all_nat_and_empty ():
635- # mixing a ns datetime column with an all-NaT seconds-typed column
636- df = pd .DataFrame ({"dates" : pd .date_range ("2000" , periods = 2 , freq = "min" )})
637- df2 = pd .DataFrame ({"dates" : [pd .NaT , pd .NaT ]}).astype ({"dates" : "datetime64[s]" })
663+ exp_unit = tm .get_finest_unit (unit , unit2 )
638664
639- combined = pd .concat ([df , df2 ], ignore_index = True )
665+ combined = pd .concat ([df1 , df2 ], ignore_index = True )
640666 assert pd .api .types .is_datetime64_any_dtype (combined ["dates" ].dtype )
667+ res_unit = np .datetime_data (combined ["dates" ].dtype )[0 ]
668+ assert res_unit == exp_unit
0 commit comments