diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 3a1e9de2a6cf6..6ea30642625fe 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -150,7 +150,7 @@ cpdef convert_to_timedelta64(object ts, object unit): ts = np.timedelta64(delta_to_nanoseconds(ts), 'ns') elif not is_timedelta64_object(ts): raise ValueError("Invalid type for timedelta " - "scalar: %s" % type(ts)) + "scalar: {ts_type}".format(ts_type=type(ts))) return ts.astype('timedelta64[ns]') @@ -526,7 +526,7 @@ cdef class _Timedelta(timedelta): int64_t value # nanoseconds object freq # frequency reference bint is_populated # are my components populated - int64_t _sign, _d, _h, _m, _s, _ms, _us, _ns + int64_t _d, _h, _m, _s, _ms, _us, _ns # higher than np.ndarray and np.matrix __array_priority__ = 100 @@ -560,9 +560,9 @@ cdef class _Timedelta(timedelta): return True # only allow ==, != ops - raise TypeError('Cannot compare type %r with type %r' % - (type(self).__name__, - type(other).__name__)) + raise TypeError('Cannot compare type {!r} with type ' \ + '{!r}'.format(type(self).__name__, + type(other).__name__)) if util.is_array(other): return PyObject_RichCompare(np.array([self]), other, op) return PyObject_RichCompare(other, self, reverse_ops[op]) @@ -571,8 +571,9 @@ cdef class _Timedelta(timedelta): return False elif op == Py_NE: return True - raise TypeError('Cannot compare type %r with type %r' % - (type(self).__name__, type(other).__name__)) + raise TypeError('Cannot compare type {!r} with type ' \ + '{!r}'.format(type(self).__name__, + type(other).__name__)) return cmp_scalar(self.value, ots.value, op) @@ -591,10 +592,6 @@ cdef class _Timedelta(timedelta): td64_to_tdstruct(self.value, &tds) self._d = tds.days - if self._d < 0: - self._sign = -1 - else: - self._sign = 1 self._h = tds.hrs self._m = tds.min self._s = tds.sec @@ -680,60 +677,47 @@ cdef class _Timedelta(timedelta): Parameters ---------- - format : None|all|even_day|sub_day|long + format : None|all|sub_day|long Returns ------- converted : string of a Timedelta """ - cdef object sign_pretty, sign2_pretty, seconds_pretty, subs + cdef object sign, seconds_pretty, subs, fmt, comp_dict self._ensure_components() - if self._sign < 0: - sign_pretty = "-" - sign2_pretty = " +" + if self._d < 0: + sign = " +" else: - sign_pretty = "" - sign2_pretty = " " + sign = " " - # show everything if format == 'all': - seconds_pretty = "%02d.%03d%03d%03d" % ( - self._s, self._ms, self._us, self._ns) - return "%d days%s%02d:%02d:%s" % (self._d, - sign2_pretty, self._h, - self._m, seconds_pretty) - - # by default not showing nano - if self._ms or self._us or self._ns: - seconds_pretty = "%02d.%03d%03d" % (self._s, self._ms, self._us) + fmt = "{days} days{sign}{hours:02}:{minutes:02}:{seconds:02}." \ + "{milliseconds:03}{microseconds:03}{nanoseconds:03}" else: - seconds_pretty = "%02d" % self._s - - # if we have a partial day - subs = (self._h or self._m or self._s or - self._ms or self._us or self._ns) - - if format == 'even_day': - if not subs: - return "%d days" % (self._d) - - elif format == 'sub_day': - if not self._d: - - # degenerate, don't need the extra space - if self._sign > 0: - sign2_pretty = "" - return "%s%s%02d:%02d:%s" % (sign_pretty, sign2_pretty, - self._h, self._m, seconds_pretty) - - if subs or format=='long': - return "%d days%s%02d:%02d:%s" % (self._d, - sign2_pretty, self._h, - self._m, seconds_pretty) - return "%d days" % (self._d) + # if we have a partial day + subs = (self._h or self._m or self._s or + self._ms or self._us or self._ns) + + # by default not showing nano + if self._ms or self._us or self._ns: + seconds_fmt = "{seconds:02}.{milliseconds:03}{microseconds:03}" + else: + seconds_fmt = "{seconds:02}" + + if format == 'sub_day' and not self._d: + fmt = "{hours:02}:{minutes:02}:" + seconds_fmt + elif subs or format == 'long': + fmt = "{days} days{sign}{hours:02}:{minutes:02}:" + seconds_fmt + else: + fmt = "{days} days" + + comp_dict = self.components._asdict() + comp_dict['sign'] = sign + + return fmt.format(**comp_dict) def __repr__(self): return "Timedelta('{0}')".format(self._repr_base(format='long')) diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index 09d6b37bae772..ca3b1cfb18b18 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -2274,7 +2274,7 @@ def _get_format_timedelta64(values, nat_rep='NaT', box=False): consider_values, np.abs(values_int) >= one_day_nanos).sum() == 0 if even_days: - format = 'even_day' + format = None elif all_sub_day: format = 'sub_day' else: diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index bfaa47bf39f83..47632b1399991 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -2281,22 +2281,9 @@ def test_none(self): assert drepr(delta_1s) == "0 days 00:00:01" assert drepr(delta_500ms) == "0 days 00:00:00.500000" assert drepr(delta_1d + delta_1s) == "1 days 00:00:01" + assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01" assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000" - - def test_even_day(self): - delta_1d = pd.to_timedelta(1, unit='D') - delta_0d = pd.to_timedelta(0, unit='D') - delta_1s = pd.to_timedelta(1, unit='s') - delta_500ms = pd.to_timedelta(500, unit='ms') - - drepr = lambda x: x._repr_base(format='even_day') - assert drepr(delta_1d) == "1 days" - assert drepr(-delta_1d) == "-1 days" - assert drepr(delta_0d) == "0 days" - assert drepr(delta_1s) == "0 days 00:00:01" - assert drepr(delta_500ms) == "0 days 00:00:00.500000" - assert drepr(delta_1d + delta_1s) == "1 days 00:00:01" - assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000" + assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000" def test_sub_day(self): delta_1d = pd.to_timedelta(1, unit='D') @@ -2311,7 +2298,9 @@ def test_sub_day(self): assert drepr(delta_1s) == "00:00:01" assert drepr(delta_500ms) == "00:00:00.500000" assert drepr(delta_1d + delta_1s) == "1 days 00:00:01" + assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01" assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000" + assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000" def test_long(self): delta_1d = pd.to_timedelta(1, unit='D') @@ -2326,7 +2315,9 @@ def test_long(self): assert drepr(delta_1s) == "0 days 00:00:01" assert drepr(delta_500ms) == "0 days 00:00:00.500000" assert drepr(delta_1d + delta_1s) == "1 days 00:00:01" + assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01" assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000" + assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000" def test_all(self): delta_1d = pd.to_timedelta(1, unit='D') @@ -2335,8 +2326,10 @@ def test_all(self): drepr = lambda x: x._repr_base(format='all') assert drepr(delta_1d) == "1 days 00:00:00.000000000" + assert drepr(-delta_1d) == "-1 days +00:00:00.000000000" assert drepr(delta_0d) == "0 days 00:00:00.000000000" assert drepr(delta_1ns) == "0 days 00:00:00.000000001" + assert drepr(-delta_1d + delta_1ns) == "-1 days +00:00:00.000000001" class TestTimedelta64Formatter(object):