2010-04-30 86 views
3

我想在python中編寫一個小預算程序。這是我寫的第一個學習python的程序。第一步是根據今天的日期計算直到第一天或第十五天(工資日)爲止的天數。有人能幫我一點嗎?計算時間,直到本月的第1或第15個月python

+0

正如他們在下面所說的,datetime是繼續進行的方式,但這已成爲削減你的牙齒的一個更加複雜的模塊。這並不複雜,因爲它寫得很差,只是公曆和球形地球有很多屬性。 – msw 2010-04-30 06:08:46

回答

2

我不想通過輸入答案來完全破壞你的學習體驗,但是Python庫使得這很容易。查看datetime模塊,特別是datetimedelta類。

2

datetime模塊中的類將有所幫助。

你只需要檢查是否在本月15號之後。如果是,找到下個月的第一個。如果不是,找到當前月份的第15個。

+0

另一種方法是找到兩者並返回較短的一個 – 2010-04-30 04:56:49

+0

@Carson Myers,顯然是更好的。你需要找到更短的AND正數,否則。具體來說,找到當前月份的第十五個tdelta,如果積極,很好,並且全部完成;否則,請在下個月的第一天返回tdelta。 – Dingle 2010-04-30 19:39:59

+0

是的,你是對的,我正在考慮沿着「找到下一個1和接下來的15個,並返回更接近的一個」的路線,但我想你不能找到接下來的15個,你必須檢查在幾個月內。 – 2010-04-30 20:45:25

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的新手,所以我會全力以赴,給你一個使用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運行它。這應該立即失敗,各種錯誤消息,因爲我們還沒有寫好正確的代碼。

經過一段日期時間日期的工作後,我已經制定出: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

+1進行完整的解釋和單元測試。但是,實際的解決方案可能更加優雅 - 這是一種蠻力方法。此外,OP希望從今天開始計算天數,而不是實際支付日期(當然,微不足道)。 – EMP 2010-04-30 06:56:40

+0

並且它不能運行... 1s/nexy/next/ – 2010-04-30 07:30:30

+1

如果答案錯了。編輯它。有測試,只要確保他們通過。 :) – Jerub 2010-05-11 05:11:46

0

醜陋,沒有文檔字符串,但相當多的比在本月結束while循環timedelta暴力破解打火機...

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 
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) 
相關問題