Удобный разбор строки времени в питоне - PullRequest
0 голосов
/ 27 февраля 2019

Мне нужно рассчитать продолжительность от определенной даты до настоящего времени для очистки индекса эластичного поиска.Моя работа будет работать в Python.У меня есть файл конфигурации:

indices:
  - name: test
    template: raw*
    liveLength: 1d

Как проанализировать строку «1d» или «2m» в допустимый интервал времени для расчета длительности от конкретной даты из поля liveLength?

Ответы [ 3 ]

0 голосов
/ 27 февраля 2019

Вы можете использовать регулярное выражение для извлечения частей числа / времени, а затем искать множитель в словаре.Таким образом, он немного короче и, вероятно, намного более читабелен, чем ваш ручной анализ и if/elif цепочка.

>>> mult = {"s": 1, "m": 60, "h": 60*60, "d": 60*60*24}
>>> s = "2d 4h 13m 5.2s"
>>> re.findall(r"(\d+(?:\.\d)?)([smhd])", s)
[('2', 'd'), ('4', 'h'), ('3', 'm'), ('5.2', 's')]
>>> sum(float(x) * mult[m] for x, m in _)
187385.2

Как функция:

def duration(string):
    mult = {"s": 1, "m": 60, "h": 60*60, "d": 60*60*24}
    parts = re.findall(r"(\d+(?:\.\d)?)([smhd])", string)
    total_seconds = sum(float(x) * mult[m] for x, m in parts)
    return timedelta(seconds=total_seconds)

print(duration("2d 4h 13m 5.2s"))
# 2 days, 4:03:05.200000

Это также гарантирует, что номерная часть является действительным числом (а не просто какой-либо последовательностью цифр и точек).Кроме того, это вызовет исключение, если используются какие-либо иные, чем разрешенные единицы времени.

Функция может быть дополнительно оптимизирована путем предварительной компиляции регулярного выражения с re.compile вне функции.Когда я тестировал его с IPython %timeit, мой показался немного быстрее (у вас 2,1 мкс против 2,8 мкс, как без создания timedelta, так и с float вместо Decimal).Кроме того, я бы посчитал, что это будет более читабельным, если иметь гораздо более декларативный и менее императивный стиль, но это, безусловно, вопрос вкуса и предпочтений.

0 голосов
/ 27 февраля 2019

Вот мое решение;Я использовал библиотеку python datetime, и она timedelta:

import datetime

intervals = {
    "w": datetime.timedelta(weeks=1),
    "d": datetime.timedelta(days=1),
    "h": datetime.timedelta(hours=1),
    "m": datetime.timedelta(minutes=1),
    "s": datetime.timedelta(seconds=1)
    }

def parse_live_length(string):
    time_interval_start_index = 0

    for char in string:
        if char.isnumeric():
            time_interval_start_index += 1
        else:
            return int(string[0:time_interval_start_index]), string[time_interval_start_index:]

    return False

# "2w" used as an example
live_length = "2w"
time_scalar, ll_interval = parse_live_length(live_length)

for interval in intervals:
    if interval == ll_interval:
        new_delta = time_scalar * intervals[interval]
        break 

# Example of how it could be used
current = datetime.datetime.now()
new_time = new_delta + current
print(new_time.day, new_time.month, new_time.year)
0 голосов
/ 27 февраля 2019

Я нашел код на GitHub:

from decimal import Decimal
from datetime import timedelta


def duration(duration_string): #example: '5d3h2m1s'
    duration_string = duration_string.lower()
    total_seconds = Decimal('0')
    prev_num = []
    for character in duration_string:
        if character.isalpha():
            if prev_num:
                num = Decimal(''.join(prev_num))
                if character == 'd':
                    total_seconds += num * 60 * 60 * 24
                elif character == 'h':
                    total_seconds += num * 60 * 60
                elif character == 'm':
                    total_seconds += num * 60
                elif character == 's':
                    total_seconds += num
                prev_num = []
        elif character.isnumeric() or character == '.':
            prev_num.append(character)
    return timedelta(seconds=float(total_seconds))

Очень хорошо Пример

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...