我正在尝试在python中编写一些预算程序。这是我写的第一个学习python的程序。第一步是根据今天的日期计算到第1天或第15天(发薪日)的天数。有人可以帮我一点吗?
答案 0 :(得分:6)
有趣的问题,这是一个完整的解决方案。我将从我的函数定义开始,我将它放在名为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.
"""
接下来我们需要一些测试。这是为了清楚地定义我们方法的行为。因为你是python的新手,我将全力以赴,给你一个使用单元测试的例子。
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
运行单元测试,它应该都是金色的。请注意,在我的测试中,我已经确定如果我检查发薪日的“下一个”发薪日是什么,它会返回它自己的一天。将其更改为返回“下一个”发薪日是留给读者的练习。
答案 1 :(得分:2)
我不想通过输入答案来完全破坏您的学习体验,但Python库使这很容易。查看datetime模块,尤其是date
和timedelta
类。
答案 2 :(得分:2)
datetime
模块中的类将有所帮助。
您只需要检查是否在本月15日之后。如果是,找到下个月的第一天。如果不是,请找到当月的第15个。
答案 3 :(得分:0)
丑陋没有文档字符串,但是比月底的whiledelta强制执行还要轻松一点......
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)
用法:
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
答案 4 :(得分:0)
这适用于任何合理的paydays
......排序,以及all(1 <= payday <= 28 for payday in paydays)
#其他工人每年二月的罢工。
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)