Форматирование объектов timedelta [дубликаты]

Хотя я обычно соглашаюсь с тем, что inspect является хорошим ответом, я бы не согласился с тем, что вы не можете получить исходный код объектов, определенных в интерпретаторе. Если вы используете dill.source.getsource из dill , вы можете получить источник функций и лямбда, даже если они определены в интерактивном режиме. Он также может получить код для связанных или не связанных классов методов и функций, определенных в карри ... однако вы не сможете скомпилировать этот код без кода объекта-объекта.

>>> from dill.source import getsource
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getsource(add)
def add(x,y):
  return x+y

>>> print getsource(squared)
squared = lambda x:x**2

>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getsource(f.bar)
def bar(self, x):
    return x*x+x

>>> 

29
задан martineau 26 June 2019 в 21:00
поделиться

7 ответов

но мне было интересно, смогу ли я сделать это в одной строке, используя любую функцию даты и времени, например strftime.

Насколько я могу судить, в timedelta нет встроенного метода, который бы это делал. Если вы делаете это часто, вы можете создать свою собственную функцию, например

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)

Использование:

>>> print strfdelta(delta_obj, "{days} days {hours}:{minutes}:{seconds}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{hours} hours and {minutes} to go")
20 hours and 18 to go

Если вы хотите использовать строковый формат ближе к формату, используемому в strftime, мы можем использовать string.Template .

from string import Template

class DeltaTemplate(Template):
    delimiter = "%"

def strfdelta(tdelta, fmt):
    d = {"D": tdelta.days}
    d["H"], rem = divmod(tdelta.seconds, 3600)
    d["M"], d["S"] = divmod(rem, 60)
    t = DeltaTemplate(fmt)
    return t.substitute(**d)

Использование:

>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
20 hours and 18 to go

Значение totalSeconds отображается как 13374 вместо 99774. т.е. игнорирование значения «день».

Обратите внимание, что в приведенном выше примере вы можете использовать timedelta.days для получения значения «день».

В качестве альтернативы, начиная с Python 2.7, timedelta имеет метод total_seconds () , который возвращает общее количество секунд, содержащихся в продолжительности.

47
ответ дан Shawn Chin 26 June 2019 в 21:00
поделиться

В Python2.7 или новее вы можете использовать метод total_seconds :

import datetime as dt

turnaround = dt.timedelta(days = 1, hours = 3, minutes = 42, seconds = 54)

total_seconds = int(turnaround.total_seconds())
hours, remainder = divmod(total_seconds,60*60)
minutes, seconds = divmod(remainder,60)

print('{} hrs {} mins {} secs'.format(hours,minutes,seconds))

приводит к

27 hrs 42 mins 54 secs

В Python2.6 или старше вы Вы можете вычислить total_seconds самостоятельно:

total_seconds = turnaround.seconds + turnaround.days*24*60*60

(более общую формулу, включая микросекунды, смотрите по ссылке выше).

15
ответ дан unutbu 26 June 2019 в 21:00
поделиться

Ответ Шона Чина хороший, но одна проблема с ним заключается в том, что если вы пропустите конкретный элемент в своем формате (как в его втором примере, который имеет только часы и минуты, а не дни или секунды), то это время исчезнет. из вашего результата. Вы можете изменить его, чтобы устранить эту проблему и получить более точные результаты, обрабатывая только те ключевые слова, которые фактически отображаются в строке формата.

class DeltaTemplate(Template):
    delimiter = '%'

def strfdelta(tdelta, fmt):
    d = {}
    l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
    rem = int(tdelta.total_seconds())

    for k in ( 'D', 'H', 'M', 'S' ):
        if "%{}".format(k) in fmt:
            d[k], rem = divmod(rem, l[k])

    t = DeltaTemplate(fmt)
    return t.substitute(**d)

Использование:

>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
44 hours and 18 to go

Хотя форматирование жестко, поскольку вы не можете применить какие-либо строки преобразования и получить такие уродливые вещи, как это:

>>> delta_obj = timedelta(minutes=5, seconds=2)
>>> print strfdelta(delta_obj, "%H:%M:%S")
0:5:2

Однако вы можете воспользоваться тем же подходом и применить его к string.Formatter вместо string.Template и получить что-то намного лучше.

from string import Formatter

def strfdelta(tdelta, fmt):
    f = Formatter()
    d = {}
    l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
    k = map( lambda x: x[1], list(f.parse(fmt)))
    rem = int(tdelta.total_seconds())

    for i in ('D', 'H', 'M', 'S'):
        if i in k and i in l.keys():
            d[i], rem = divmod(rem, l[i])

    return f.format(fmt, **d)

Использование:

>>> delta_obj = timedelta(days=1, hours=20, minutes=18, seconds=12)
>>> print strfdelta(delta_obj, "{D} days {H}:{M}:{S}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{H} hours and {M} to go") 
44 hours and 18 to go

>>> delta_obj = timedelta(minutes=5, seconds=2)                     
>>> print strfdelta(delta_obj, "{H:02}h{M:02}m{S:02}s")  
00h05m02s
>>> print strfdelta(delta_obj, "{H:02}:{M:02}:{S:02}")
00:05:02
14
ответ дан mpounsett 26 June 2019 в 21:00
поделиться

Вы можете использовать модуль dateutil, который имеет более дружественный объект относительной дельты.

import dateutil
import datetime

alpha = datetime.datetime(2012, 1, 16, 6, 0)
beta = datetime.datetime(2012, 1, 18, 10, 42, 57, 230301)
delta = dateutil.relativedelta(beta, alpha)

это дает вам объектную дельту, которая выглядит как

>>> delta
relativedelta(days=+2, hours=+4, minutes=+42, seconds=+57, microseconds=+230301)

Затем вы можете сделать

print('turnaround %i hrs %i mins %i secs' % (delta.days * 24 + delta.hours, delta.minutes, delta.seconds)

)

7
ответ дан dabhaid 26 June 2019 в 21:00
поделиться

Небольшой вариант ответа Шона Чина , который также затрагивает последующую проблему , поднятую mpouncett - накладывает часы , минуты и секунды с ведущими нулями, чтобы все 3 элемента использовали 2 места (более соответствует спецификации для этих полей в strftime ):

from string import Template

class DeltaTemplate(Template):
    delimiter = "%"

def strfdelta(tdelta, fmt):
    d = {"D": tdelta.days}
    hours, rem = divmod(tdelta.seconds, 3600)
    minutes, seconds = divmod(rem, 60)
    d["H"] = '{:02d}'.format(hours)
    d["M"] = '{:02d}'.format(minutes)
    d["S"] = '{:02d}'.format(seconds)
    t = DeltaTemplate(fmt)
    return t.substitute(**d)

Вот тест некоторые выборочные значения:

from datetime import timedelta
for seconds in [0, 1, 59, 60, 61, 3599, 3600, 3601]:
    print strfdelta(timedelta(0, seconds), '%H:%M:%S')

А вот и вывод:

00:00:00
00:00:01
00:00:59
00:01:00
00:01:01
00:59:59
01:00:00
01:00:01
12
ответ дан Community 26 June 2019 в 21:00
поделиться
def to_time(seconds):
  delta = datetime.timedelta(seconds=seconds)
  return str(delta.days) + 'd ' + (datetime.datetime.utcfromtimestamp(0) + delta).strftime('%H:%M')
3
ответ дан Daniel F 26 June 2019 в 21:00
поделиться

Вышеуказанные ответы, по-видимому, не обрабатывают отрицательных значений временной шкалы (как, например, получается из pytz для часовых поясов, «оставленных» от UTC). Как указано в документации , объекты timedelta нормализованы, а отрицательная timedelta представлена ​​отрицательным атрибутом экземпляра day. Из документации:

Обратите внимание, что нормализация отрицательных значений может сначала удивить.

и

Строковые представления объектов timedelta нормализуются аналогично их внутреннему представлению. Это приводит к несколько необычным результатам для отрицательных timedeltas.

Например:

>>> td = timedelta(seconds=-30)
>>> str(td)
'-1 day, 23:59:30'
>>> repr(td)
'datetime.timedelta(-1, 86370)'

Учитывая этот пример timedelta, оба принятого ответа Шона Чина и ответа Гумпшена возвращают '23:59:30', и ответ mpounsett '-1:59:30'.

Я думаю, что для того, чтобы печатать как отрицательные, так и положительные временные интервалы более читабельным образом, нам нужно явно обработать знак и абсолютное значение объекта часового пояса: строковое представление:

>>> strfdelta(td, "%s%H:%M:%S")  # Note that %s refers to the timedelta’s sign.
'-00:00:30'
>>> strfdelta(timedelta(days=-1), "%s%D %H:%M:%S")
'-1 00:00:00'
>>> strfdelta(timedelta(days=-1, minutes=5), "%s%D %H:%M:%S")
'-0 23:55:00'
>>> strfdelta(timedelta(days=-1, minutes=-5), "%s%D %H:%M:%S")
'-1 00:05:00'

… или в более практическом контексте часовых поясов:

>>> import pytz
>>> import datetime
>>> td = pytz.timezone("Canada/Newfoundland").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(-1, 77400)
>>> strfdelta(td, fmt="%s%H:%M")
'-02:30'
>>> td = pytz.timezone("Australia/Eucla").utcoffset(datetime.datetime.now())
>>> td
datetime.timedelta(0, 31500)
>>> strfdelta(td, fmt="%s%H:%M")
'+08:45'
2
ответ дан Jens 26 June 2019 в 21:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: