Python на несколько дней / недель / месяцев вперед

Я искал ответ через stackoverflow, но мне не удалось найти то, что я ищу, в Python и питоническим способом.

Я пытаюсь получить количество дней, недель или месяцев вперед на основе двух дат. Вот небольшой сценарий, который я создал, который делает то, что я хочу делать, но меня это беспокоит.

import datetime
from dateutil.relativedelta import relativedelta


now = datetime.datetime.now()
days_ahead = datetime.datetime.now() + relativedelta(days=3)
weeks_ahead = datetime.datetime.now() + relativedelta(weeks=2)
month_ahead = datetime.datetime.now() + relativedelta(months=1)
months_ahead = datetime.datetime.now() + relativedelta(months=3)


def get_relative_date(dt):

    ahead = (dt - now).days

    if ahead < 7:
        return "Due in " + str(ahead) + " days"

    elif ahead < 31:
        return "Due in " + str(ahead/7) + " weeks"

    else:
        return "Due in " + str(ahead/30) + " months"

print get_relative_date(days_ahead)
print get_relative_date(weeks_ahead)
print get_relative_date(month_ahead)
print get_relative_date(months_ahead)

Результат следующий:

Due in 3 days
Due in 2 weeks
Due in 1 months
Due in 3 months

Несмотря на то, что это хороший ответ, мои опасения связаны с:

  • Я использую ahead < 30, но как насчет месяцев с 31 днем? Не вызовет ли это каких-то накладных расходов и ошибок в какой-то момент?
  • Есть ли лучший способ получить эту информацию? Какая-то библиотека или встроенная функция для datetime или dateutil, которая возвращает вам эту информацию?

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

Редактировать

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

def relative_date(dt):

    if dt is not None and len(dt) > 0:

        now = datetime.now()
        then = arrow.get(dt).naive

        rd = relativedelta(then, now)
        if rd.years or rd.months:
            months = 12 * rd.years + rd.months

            if months < 0:
                if months == -1:
                    return "Due 1 month ago"

                return "Due %i months ago" % -months

            if months == 1:
                return "Due in 1 month"
            return "Due in %d months" % months

        elif rd.days > 7 or rd.days < -7:
            weeks = rd.days / 7

            if weeks < 0:
                if weeks == -1:
                    return "Due 1 week ago"
                return "Due %i weeks ago" % -weeks

            if weeks == 1:
                return "Due in 1 week"
            return "Due in %d weeks" % weeks

        else:

            if rd.days == 0:
                return "Due Today"

            elif rd.days < 0:
                if rd.days == -1:
                    return "Due 1 day ago"
                return "Due %i days ago" % -rd.days

            elif rd.days == 1:
                return "Due in 1 day"

            return "Due in %d days" % rd.days

    else:
        return ""

person Aitor Martin Gonzalez    schedule 30.07.2015    source источник


Ответы (1)


Да, ваш текущий код является проблемой, потому что не во всех месяцах 31 день. На практике вы можете решить, что это не слишком важно, если в нем указано «Срок оплаты через 2 месяца», тогда как на самом деле срок платежа составляет 1 месяц и 28 дней. В конце концов, округление в меньшую сторону означает, что вы показываете Срок через 2 месяца, тогда как срок оплаты через 2 месяца и 28 дней.

Поскольку вы уже используете модуль dateutil, обратите внимание, что вы можете использовать relativedelta наоборот также (см. страницу примеров).

Если вы создаете экземпляр relativedelta с двумя объектами даты, он возвращает объект relativedelta с атрибутами year, month и day.

>>> relativedelta(date(2015, 7, 20), date(2014, 6, 10))
relativedelta(years=+1, months=+1, days=+10)

Вы можете использовать это в своем методе следующим образом:

from dateutil.relativedelta import relativedelta

def get_relative_date(dt):

    rd = relativedelta(dt, now)
    if rd.years or rd.months:
        months = 12 * rd.years + rd.months
        return "Due in %d months" % months
    elif rd.days > 7:
        weeks = rd.days / 7
        return "Due in %d weeks" % weeks
    else:
        return "Due in %d days" % rd.days
person Alasdair    schedule 30.07.2015
comment
Удивительный не знал об этом. Большое Вам спасибо. - person Aitor Martin Gonzalez; 31.07.2015
comment
Обратите внимание, для будущих читателей не должно быть дополнительного: в конце строки месяцы = 12 * годы + годы. - person SwapnilBhate; 04.01.2021
comment
Хорошее место @swapnilbhate, я обновил ответ. Вы можете использовать кнопку редактирования, чтобы предлагать такие изменения. - person Alasdair; 04.01.2021