Skip to content

Instantly share code, notes, and snippets.

@oliveiraev
Created July 3, 2015 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oliveiraev/e030a0ab578e0cbf3e50 to your computer and use it in GitHub Desktop.
Save oliveiraev/e030a0ab578e0cbf3e50 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
"""
Adiciona períodos a datas
"""
import datetime
DAY = "1"
WEEK = "7"
MONTH = "30"
def add_period(amount, period=DAY, date=None):
"""
>>> day = datetime.date(2012, 1, 1)
>>> add_period(1, DAY, day)
datetime.date(2012, 1, 2)
>>> add_period(-1, DAY, day)
datetime.date(2011, 12, 31)
>>> add_period(0.5, DAY, day)
datetime.date(2012, 1, 1)
>>> add_period(-0.5, DAY, day)
datetime.date(2011, 12, 31)
>>> add_period(2, DAY, day)
datetime.date(2012, 1, 3)
>>> add_period(-2, DAY, day)
datetime.date(2011, 12, 30)
>>> add_period(2.5, DAY, day)
datetime.date(2012, 1, 3)
>>> add_period(-2.5, DAY, day)
datetime.date(2011, 12, 29)
>>> add_period(1, WEEK, day)
datetime.date(2012, 1, 8)
>>> add_period(-1, WEEK, day)
datetime.date(2011, 12, 25)
>>> add_period(0.5, WEEK, day)
datetime.date(2012, 1, 4)
>>> add_period(-0.5, WEEK, day)
datetime.date(2011, 12, 28)
>>> add_period(2, WEEK, day)
datetime.date(2012, 1, 15)
>>> add_period(-2, WEEK, day)
datetime.date(2011, 12, 18)
>>> add_period(2.5, WEEK, day)
datetime.date(2012, 1, 18)
>>> add_period(-2.5, WEEK, day)
datetime.date(2011, 12, 14)
>>> add_period(1, MONTH, day)
datetime.date(2012, 2, 1)
>>> add_period(-1, MONTH, day)
datetime.date(2011, 12, 1)
>>> add_period(0.5, MONTH, day)
datetime.date(2012, 1, 16)
>>> add_period(-0.5, MONTH, day)
datetime.date(2011, 12, 16)
>>> add_period(2, MONTH, day)
datetime.date(2012, 3, 1)
>>> add_period(-2, MONTH, day)
datetime.date(2011, 11, 1)
>>> add_period(2.5, MONTH, day)
datetime.date(2012, 3, 16)
>>> add_period(-2.5, MONTH, day)
datetime.date(2011, 10, 16)
>>> add_period(.25, MONTH, day)
datetime.date(2012, 1, 8)
>>> add_period(-.25, MONTH, day)
datetime.date(2011, 12, 24)
>>> day = datetime.date(2013, 1, 31)
>>> add_period(1, MONTH, day)
datetime.date(2013, 2, 28)
>>> day = datetime.date(2013, 3, 31)
>>> add_period(-1, MONTH, day)
datetime.date(2013, 2, 28)
"""
date = date or datetime.date.today()
if period == DAY:
return date + datetime.timedelta(days=amount * 1)
if period == WEEK:
return date + datetime.timedelta(days=amount * 7)
offset = amount > 0 and 32 or 0
amount = abs(amount)
while amount:
step = amount < 1 and amount or 1
delta = date + datetime.timedelta(days=offset - date.day)
delta = set_day(delta, date.day) - date
date += datetime.timedelta(days=delta.days * step)
amount -= step
return date
def set_day(date, day):
"""
Define o dia de um objeto date/datetime e, caso o dia seja inválido, efetua
algumas tentativas antes de falhar
>>> set_day(datetime.date(2012, 2, 1), 31)
datetime.date(2012, 2, 29)
>>> set_day(datetime.date(2012, 2, 1), -31)
datetime.date(2012, 2, 29)
>>> set_day(datetime.date(2012, 2, 1), 0.5)
datetime.date(2012, 2, 1)
>>> set_day(datetime.date(2012, 2, 1), "1")
datetime.date(2012, 2, 1)
>>> set_day(datetime.date(2012, 2, 1), True)
datetime.date(2012, 2, 1)
>>> set_day(datetime.date(2012, 2, 1), False)
datetime.date(2012, 2, 1)
>>> set_day(datetime.date(2012, 2, 1), "foo") # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for -: 'str' and 'int'
"""
try:
day = abs(int(day))
return date.replace(day=day)
except ValueError:
return set_day(date, day - 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment