Преобразовать временную строку, выраженную как <число> [m | h | d | s | w] в секундах в Python
Есть ли хороший способ преобразования строки, представляющей время в формате [m | h | d | s | w] (m = минуты, h = часы, d = дни, s = секунды w = неделя), чтобы количество секунд? То есть.
def convert_to_seconds(timeduration):
...
convert_to_seconds("1h")
-> 3600
convert_to_seconds("1d")
-> 86400
и т.д.?
Спасибо!
Ответы
Ответ 1
Да, существует хороший простой метод, который можно использовать на большинстве языков без необходимости читать руководство для библиотеки datetime. Этот метод также может быть экстраполирован на унции/фунты/тонну и т.д. И т.д.:
seconds_per_unit = {"s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800}
def convert_to_seconds(s):
return int(s[:-1]) * seconds_per_unit[s[-1]]
Ответ 2
Я рекомендую использовать класс timedelta из модуля datetime:
from datetime import timedelta
UNITS = {"s":"seconds", "m":"minutes", "h":"hours", "d":"days", "w":"weeks"}
def convert_to_seconds(s):
count = int(s[:-1])
unit = UNITS[ s[-1] ]
td = timedelta(**{unit: count})
return td.seconds + 60 * 60 * 24 * td.days
Внутренне объекты timedelta
хранят все в виде микросекунд, секунд и дней. Таким образом, хотя вы можете задавать параметры в единицах измерения, например, в миллисекундах, месяцах или годах, в конце вам придется взять timedelta
вами timedelta
и преобразовать ее в секунды.
В случае, если синтаксис **
сбивает вас с толку, это применяется синтаксис Python. По сути, все эти вызовы функций эквивалентны:
def f(x, y): pass
f(5, 6)
f(x=5, y=6)
f(y=6, x=5)
d = {"x": 5, "y": 6}
f(**d)
Ответ 3
Мне обычно нужно поддерживать необработанные числа, строковые номера и строковые номера, заканчивающиеся на [m | h | d | s | w].
Эта версия будет обрабатывать: 10, "10", "10 с", "10 м", "10 ч", "10 д", "10 Вт".
Шляпа подсказка @Eli Courtwright ответ на преобразование строки.
UNITS = {"s":"seconds", "m":"minutes", "h":"hours", "d":"days", "w":"weeks"}
def convert_to_seconds(s):
if isinstance(s, int):
# We are dealing with a raw number
return s
try:
seconds = int(s)
# We are dealing with an integer string
return seconds
except ValueError:
# We are dealing with some other string or type
pass
# Expecting a string ending in [m|h|d|s|w]
count = int(s[:-1])
unit = UNITS[ s[-1] ]
td = timedelta(**{unit: count})
return td.seconds + 60 * 60 * 24 * td.days
Ответ 4
Я написал библиотеку с открытым исходным кодом MgntUtils на Java (не php), которая частично отвечает этому требованию. Он содержит статический метод parsingStringToTimeInterval(String value)
который анализирует строку, которая, как ожидается, будет содержать некоторое значение временного интервала - числовое значение с необязательным суффиксом единицы времени. Например, строка "38s" будет проанализирована как 38 секунд, "24m" - 24 минуты, "4h" - 4 часа, "3d" - 3 дня и "45" как 45 миллисекунд. Поддерживаемые суффиксы: "s" для секунд, "m" для минут, "h" для часов и "d" для дней. Считается, что строка без суффикса содержит значение в миллисекундах. Суффиксы нечувствительны к регистру. Если предоставленная строка содержит неподдерживаемый суффикс или содержит отрицательное числовое значение или ноль или содержит не числовое значение, то генерируется исключение IllegalArgumentException. Этот метод возвращает класс TimeInterval - класс, также определенный в этой библиотеке. По сути, он содержит два свойства с соответствующими методами получения и установки: long "value" и java.util.concurrent.TimeUnit. Но в дополнение к методам получения и установки этот класс имеет методы toMillis(), toSeconds(), toMinutes(), toHours() toDays(). Эти методы возвращают длинное значение в указанном масштабе времени (так же, как соответствующие методы в классе java.util.concurrent.TimeUnit)
Этот метод может быть очень полезен для анализа свойств временных интервалов, таких как время ожидания или периоды ожидания, из файлов конфигурации. Это устраняет ненужные вычисления от различных временных масштабов до миллисекунд назад и вперед. Учтите, что у вас есть свойство methodInvokingInterval, которое необходимо установить на 5 дней. Таким образом, чтобы установить значение в миллисекундах, вам необходимо рассчитать, что 5 дней - это 432000000 миллисекунд (очевидно, это не невыполнимая задача, но раздражает и подвержена ошибкам), а затем любой, кто увидит значение 432000000, должен будет рассчитать его до 5 дней, которые расстраивает Но используя этот метод, вы получите значение свойства "5d" и вызов кода
long seconds = TextUtils.parsingStringToTimeInterval("5d").toSeconds();
решит вашу проблему конверсии. Очевидно, что это не слишком сложная функция, но она может добавить простоту и ясность в ваши файлы конфигурации и сэкономить некоторое разочарование и "глупый" просчет в ошибках миллисекунд. Вот ссылка на статью, которая описывает библиотеку MgntUtils, а также где ее взять: MgntUtils
Ответ 5
И еще один добавить в смесь.
Это решение короткое, но достаточно терпимое и допускает кратные значения, например 10m 30s
from datetime import timedelta
import re
UNITS = {'s':'seconds', 'm':'minutes', 'h':'hours', 'd':'days', 'w':'weeks'}
def convert_to_seconds(s):
return int(timedelta(**{
UNITS.get(m.group('unit').lower(), 'seconds'): int(m.group('val'))
for m in re.finditer(r'(?P<val>\d+)(?P<unit>[smhdw]?)', s, flags=re.I)
}).total_seconds())
Результаты теста:
>>> convert_to_seconds('10s')
10
>>> convert_to_seconds('1') # defaults to seconds
1
>>> convert_to_seconds('1m 10s') # chaining
70
>>> convert_to_seconds('1M10S') # case insensitive
70
>>> convert_to_seconds('1week 3days') # ignores 'eek' and 'ays'
864000
не идеально
>>> convert_to_seconds('1month 3days') # actually 1minute + 3 days
259260
>>> convert_to_seconds('40s 10s') # 1st value clobbered by 2nd
10