Calculating time before 1st or 15th of a month in python

I am trying to write a small budget program in python. This is my first program that I write to learn python. The first step is to calculate how many days are up to the 1st or the 15th (paydays) depending on today's date. Can someone help me a little?

+3
source share
5 answers

An interesting question, and here is a complete solution. I will start by defining my function, I put it in a file with the name payday.py:

def nexypayday(fromdate=None):
    """
    @param fromdate: An instance of datetime.date that is the day to go from. If
                     not specified, todays date is used.
    @return: The first payday on or after the date specified.
    """

Next, we need some tests. This should clearly define the behavior of our method. Since you are new to python, I am going out of my way and give you an example of using unittests.

from unittest import TestCase, main
import payday
import datetime

class TestPayday(TestCase):
    def test_first_jan(self):
        self.assertEqual(payday.nextpayday(datetime.date(2010, 1, 1)),
                         datetime.date(2010, 1, 1))

    def test_second_jan(self):
        self.assertEqual(payday.nextpayday(datetime.date(2010, 1, 2)),
                         datetime.date(2010, 1, 15))

    def test_fifteenth_jan(self):
        self.assertEqual(payday.nextpayday(datetime.date(2010, 1, 15)),
                         datetime.date(2010, 1, 15))

    def test_thirty_one_jan(self):
        self.assertEqual(payday.nextpayday(datetime.date(2010, 1, 31)),
                         datetime.date(2010, 2, 1))

    def test_today(self):
        self.assertTrue(payday.nextpayday() >= datetime.date.today())

if __name__ == '__main__':
    main()

python. test_payday.py python test_payday.py. , .

datetime.date : mydatetime.day - , mydatetime + datetime.timedelta(days=1) datetime . , payday.py.

import datetime

def nextpayday(fromdate=None):
    """
    @param fromdate: An instance of datetime.date that is the day to go from. If
                     not specified, todays date is used.
    @return: The first payday on or after the date specified.
    """
    if fromdate is None:
        fromdate = datetime.date.today()

    # while the day of the month isn't 1 or 15, increase the day by 1
    while fromdate.day not in (1, 15):
        fromdate = fromdate + datetime.timedelta(days=1)

    return fromdate

, . , , , "" , . "" .

+6

, , Python . datetime, date timedelta.

+2

datetime .

You just need to check if this happened after the 15th of the month. If so, find the 1st of the next month. If not, find the 15th of the current month.

+2
source

Ugly, without dockstrings, but a little easier than rough-forcing with timedelta in a while loop at the end of the month ...

import datetime
from itertools import cycle

PAYDAYS = (1, 8, 15, 22, 20, 25, 30)

def calculate_days_difference(date_, day=None, next_month=False):
    day = day or date_.day
    year = date_.year
    month = date_.month
    if next_month:
        if month == 12:
            year = year + 1
            month = 1
        else:
            month = month + 1    
    return (datetime.date(year, month, day) - date_).days

def calculate_days_to_payday(date_, paydays=PAYDAYS):
    day = date_.day
    if day in paydays:
        return 0
    if day > max(paydays):
        return calculate_days_difference(date_, paydays[0], True)
    for payday in cycle(paydays):
        if (day > payday):
            continue
        return calculate_days_difference(date_, payday)

Using:

test_data = (
    ((2010,04,28), 2),
    ((2010,04,01), 0),
    ((2010,04,30), 0),
)

for _input, _output in test_data:
    d = datetime.date(*input)
    for i in xrange(1000000):
        assert calculate_days_to_payday(d) == _output
0
source

This will work with any reasonable paydays... sorted and all(1 <= payday <= 28 for payday in paydays)# other work strikes every February.

from datetime import date

def calculate_days_to_payday(start_date=None, paydays=(1, 15)):
    if start_date is None:
        start_date = date.today()
    day = start_date.day
    for payday in paydays:
        if payday >= day:
            return payday - day
    # next payday is in next month
    month = start_date.month + 1
    year = start_date.year
    if month == 13:
        month = 1
        year += 1
    return (date(year, month, paydays[0]) - start_date).days

if __name__ == "__main__":
    tests = (
        (1, 12, 0),
        (2, 12, 13),
        (14, 12, 1),
        (15, 12, 0),
        (16, 12, 16),
        (31, 12, 1),
        )
    for d, m, expected in tests:
        actual = calculate_days_to_payday(date(2009, m, d))
        print "%5s" * 5 % (d, m, expected, actual, actual == expected)
0
source

Source: https://habr.com/ru/post/1743445/


All Articles