дата python предыдущего месяца


132

Я пытаюсь получить дату предыдущего месяца с помощью python. Вот что я пробовал:

str( time.strftime('%Y') ) + str( int(time.strftime('%m'))-1 )

Однако этот способ плох по двум причинам: во-первых, он возвращает 20122 для февраля 2012 года (вместо 201202), а во-вторых, он вернет 0 вместо 12 в январе.

Я решил эту проблему в bash с помощью

echo $(date -d"3 month ago" "+%G%m%d")

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

if int(time.strftime('%m')) == 1:
    return '12'
else:
    if int(time.strftime('%m')) < 10:
        return '0'+str(time.strftime('%m')-1)
    else:
        return str(time.strftime('%m') -1)

Я не тестировал этот код и все равно не хочу его использовать (если только я не смогу найти другой способ: /)

Спасибо за вашу помощь!


Ответы:


302

Классы datetime и datetime.timedelta - ваш друг.

  1. найти сегодня.
  2. используйте это, чтобы найти первый день этого месяца.
  3. используйте timedelta для резервного копирования за один день до последнего дня предыдущего месяца.
  4. напечатайте строку ГГГГММ, которую вы ищете.

Как это:

 import datetime
 today = datetime.date.today()
 first = today.replace(day=1)
 lastMonth = first - datetime.timedelta(days=1)
 print(lastMonth.strftime("%Y%m"))

201202 печатается.


31
вы можете использовать .replace()метод:datetime.utcnow().replace(day=1) - timedelta(days=1)
jfs

1
Прохладно! Я пропустил метод замены.
bgporter

Вы также можете связать .replace()функцию. Сделайте это один раз, чтобы получить последний месяц, а затем повторите, чтобы получить желаемый день. Сначала: d = date.today() затемone_month_ago = (d.replace(day=1) - timedelta(days=1)).replace(day=d.day)
Тейн Пламмер

@JFSebastian Вы правы - спасибо, что указали на это. Кажется, что для этого нет элегантного однострочника, поскольку «месяц» не является постоянным периодом времени. Вы можете сделать что-то уродливое, импортировав calendarи используя calendar.mdays[d.month-1]еще больше уродливости в min()функции во втором replace, но это кажется непитоническим и не учитывает угловые случаи. Я обновил свой ответ ниже, используя try - exceptучетные записи для всех случаев, хотя я ненавижу использование исключений как части алгоритма.
Thane Plummer

посмотрите ответ Ивана и добавьте: min (date.today (). day, last_day_of_previous_month.day)
michel.iamit

70

Вам следует использовать dateutil . При этом вы можете использовать relativedelta, это улучшенная версия timedelta.

>>> import datetime 
>>> import dateutil.relativedelta
>>> now = datetime.datetime.now()
>>> print now
2012-03-15 12:33:04.281248
>>> print now + dateutil.relativedelta.relativedelta(months=-1)
2012-02-15 12:33:04.281248

Это не работает в течение первого месяца года: >>> IllegalMonthError: номер неверного месяца -1; должно быть 1-12
mtoloo

@mtoloo Какая версия dateutil? У меня нет этой проблемы, но я добавлю альтернативный синтаксис
Дэйв Батлер

1
Я предпочитаю это, потому что, хотя у @bgporter есть очень хорошее решение, его решение не так удобно для поиска в следующем месяце.
Daniel F

3
@mtoloo Вы, наверное, опечатали месяцы / месяц
r_black

2
@r_black Да, ты прав. Это была моя вина. Приведенное здесь решение является правильным, и в течение первого месяца года дальнейшая проверка не требуется.
mtoloo

45
from datetime import date, timedelta

first_day_of_current_month = date.today().replace(day=1)
last_day_of_previous_month = first_day_of_current_month - timedelta(days=1)

print "Previous month:", last_day_of_previous_month.month

Или:

from datetime import date, timedelta

prev = date.today().replace(day=1) - timedelta(days=1)
print prev.month

часть решения ... чтобы найти день прошлого месяца, добавьте что-то вроде этого: day_previous_month = min (today.day, last_day_of_previous_month.day), чтобы избежать превышения количества дней.
michel.iamit

9

Основываясь на ответе bgporter .

def prev_month_range(when = None): 
    """Return (previous month's start date, previous month's end date)."""
    if not when:
        # Default to today.
        when = datetime.datetime.today()
    # Find previous month: https://stackoverflow.com/a/9725093/564514
    # Find today.
    first = datetime.date(day=1, month=when.month, year=when.year)
    # Use that to find the first day of this month.
    prev_month_end = first - datetime.timedelta(days=1)
    prev_month_start = datetime.date(day=1, month= prev_month_end.month, year= prev_month_end.year)
    # Return previous month's start and end dates in YY-MM-DD format.
    return (prev_month_start.strftime('%Y-%m-%d'), prev_month_end.strftime('%Y-%m-%d'))

5

Это очень легко и просто. Сделай это

from dateutil.relativedelta import relativedelta
from datetime import datetime

today_date = datetime.today()
print "todays date time: %s" %today_date

one_month_ago = today_date - relativedelta(months=1)
print "one month ago date time: %s" % one_month_ago
print "one month ago date: %s" % one_month_ago.date()

Вот результат: $ python2.7 main.py

todays date time: 2016-09-06 02:13:01.937121
one month ago date time: 2016-08-06 02:13:01.937121
one month ago date: 2016-08-06

4

Для тех, кто приехал сюда и хочет получить как первый, так и последний день предыдущего месяца:

from datetime import date, timedelta

last_day_of_prev_month = date.today().replace(day=1) - timedelta(days=1)

start_day_of_prev_month = date.today().replace(day=1) - timedelta(days=last_day_of_prev_month.day)

# For printing results
print("First day of prev month:", start_day_of_prev_month)
print("Last day of prev month:", last_day_of_prev_month)

Вывод:

First day of prev month: 2019-02-01
Last day of prev month: 2019-02-28

Если вы хотите узнать начало и конец месяца (и более), взгляните на Calendarмодуль: stackabuse.com/introduction-to-the-python-calendar-module
toast38coza

Если мы хотим, чтобы 2-й месяц начинался и заканчивался?
gamer

3
def prev_month(date=datetime.datetime.today()):
    if date.month == 1:
        return date.replace(month=12,year=date.year-1)
    else:
        try:
            return date.replace(month=date.month-1)
        except ValueError:
            return prev_month(date=date.replace(day=date.day-1))

Перерывы 31 марта
Майк,

1

Просто для удовольствия, чисто математический ответ с использованием divmod. Довольно бесполезно из-за умножения, с таким же успехом можно было бы выполнить простую проверку номера месяца (если он равен 12, увеличить год и т. Д.)

year = today.year
month = today.month

nm = list(divmod(year * 12 + month + 1, 12))
if nm[1] == 0:
    nm[1] = 12
    nm[0] -= 1
pm = list(divmod(year * 12 + month - 1, 12))
if pm[1] == 0:
    pm[1] = 12
    pm[0] -= 1

next_month = nm
previous_month = pm

1

С очень полной библиотекой Pendulum у нас есть subtractметод (а не subStract):

import pendulum
today = pendulum.datetime.today()  # 2020, january
lastmonth = today.subtract(months=1)
lastmonth.strftime('%Y%m')
# '201912'

Мы видим, что он справляется с прыжковыми годами.

Обратный эквивалент add.

https://pendulum.eustace.io/docs/#addition-and-subtraction


1

Существует библиотека высокого уровня, dateparserкоторая может определять прошедшую дату на естественном языке и возвращать соответствующий datetimeобъект Python.

from dateparser import parse
parse('4 months ago')

0

Основываясь на комментарии @JF Sebastian, вы можете связать replace()функцию, чтобы вернуться на один «месяц». Поскольку месяц не является постоянным периодом времени, это решение пытается вернуться к той же дате в предыдущем месяце, что, конечно, не работает для всех месяцев. В таком случае этот алгоритм по умолчанию использует последний день предыдущего месяца.

from datetime import datetime, timedelta

d = datetime(2012, 3, 31) # A problem date as an example

# last day of last month
one_month_ago = (d.replace(day=1) - timedelta(days=1))
try:
    # try to go back to same day last month
    one_month_ago = one_month_ago.replace(day=d.day)
except ValueError:
    pass
print("one_month_ago: {0}".format(one_month_ago))

Вывод:

one_month_ago: 2012-02-29 00:00:00

0

Если вы хотите посмотреть на буквы ASCII в файле типа EXE в среде LINUX / UNIX, попробуйте «od -c 'filename' | more»

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


Не могли бы вы отредактировать это, чтобы объяснить, как он отвечает на вопрос.
AdrianHHH
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.