【2017-09-19】數字日期與時間(二)

日期與時間

  • 簡單的日期轉化與計算
    執行不同時間的轉換與計算,通常用到datetime模塊,不可忽略的是其中timedelta。順便插播一段,時間的處理在日常工作中經常用到,記得最開始的時候,都是自定義一個方法通過時間戳來進行時間計算,直到最近給男朋友寫爬蟲時,結合之前了解到的datetime模塊,才發現timedelta的好處。
>>> a=timedelta(days=2, hours=6)
>>> b = timedelta(hours=4.5)
>>> c=a+b
>>> c.days
2
>>> c.seconds
37800
>>> c.total_seconds()
210600.0
>>> 

?? 上述提到的爬蟲,需求:有一個網站,需要輸入起始時間和結束時間以及其他信息,點擊下一頁、下一頁...,提取出每頁的內容。
?? 上述需求暫僅考慮時間部分,為了實現最大自動化,用戶可決定下載幾天數據。‘幾天’就需要用到時間的計算,給出一個當前日期,向前或者向后進行推送。

>>> start_time=datetime(2012, 3, 1)
>>> start_time
datetime.datetime(2012, 3, 1, 0, 0)
>>> next_time=start_time+timedelta(days=1)
>>> next_time
datetime.datetime(2012, 3, 2, 0, 0)
>>> 

?? 在進行計算時,datetime 會自動處理閏年

>>> a = datetime(2012, 3, 1)
>>> b = datetime(2012, 2, 28)
>>> a-b
datetime.timedelta(2)
>>> (a-b).days
2
>>> c = datetime(2013, 3, 1)
>>> d = datetime(2013, 2, 28)
>>> (c - d).days
1
>>> 

??使用timedelta可以很方便的在日期上做days,hours,seconds等時間計算,如果要計算月份則需要另外的辦法。
??更加復雜的日期處理,可使用dateutil模塊,許多類似的時間計算可以使用 dateutil.relativedelta()函數代替

  • 計算最后一個周五的日期
    你需要查找星期中某一天最后出現的日期,比如星期五
    示例:求出指定星期幾最后出現的日期
    ??先將開始日期和目標日期映射到星期數組的位置上 (星期一索引為 0),然后通過模運算計算出目標日期要經過多少天才能到達開始日期。然后用開始日期減去那個時間差即得到結果日期。
>>> weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
>>> def get_previous_byday(dayname, start_date=None):
    if start_date is None:
        start_date = datetime.today()
        day_num = start_date.weekday()
        day_num_target = weekdays.index(dayname)
        days_ago = (7 + day_num - day_num_target) % 7
        if days_ago == 0:
            days_ago = 7
        target_date = start_date - timedelta(days=days_ago)
        return target_date

    
>>> get_previous_byday('Monday')
datetime.datetime(2017, 9, 18, 11, 6, 2, 863482)
>>> get_previous_byday('Tuesday')
datetime.datetime(2017, 9, 12, 11, 6, 24, 398482)
>>> 
  • 計算當前月份的日期范圍
    問題:在當前月份中循環每一天,想找到一個計算這個日期范圍的高效方法。
    解決方案:
    ??在這樣的日期上循環并需要事先構造一個包含所有日期的列表。關鍵是先計算出開始日期和結束日期,然后在你步進的時候使用 datetime.timedelta 對象遞增這個日期變量即可。
>>> import calendar
>>> def get_month_range(start_date=None):
    if start_date is None:
        start_date = date.today().replace(day=1)
        _, days_in_month = calendar.monthrange(start_date.year, start_date.month)
    end_date = start_date + timedelta(days=days_in_month)
    return (start_date, end_date)

>>> first_day, last_day = get_month_range()
>>> first_day
datetime.date(2017, 9, 1)
>>> last_day
datetime.date(2017, 10, 1)

??使用 calendar.monthrange() 函數來找出該月的總天數。任何時候只要你想獲得日歷信息,那么 calendar 模塊就非常有用了。 monthrange() 函數會返回包含星期和該月天數的元組。

>>> calendar.monthrange(start_date.year, start_date.month)
(4, 30)
>>> 

??一旦該月的天數已知了,那么結束日期就可以通過在開始日期上面加上這個天數獲得。值得注意的是結束日期并不包含在這個日期范圍內 (事實上它是下個月的開始日期)。這個和 Python 的 slice 與 range 操作行為保持一致,同樣也不包含結尾。可以創建類似內置range()的函數。

>>> for d in date_range(datetime(2012, 9, 1), datetime(2012,10,1),
timedelta(hours=6)):
    print(d)

    
2012-09-01 00:00:00
2012-09-01 06:00:00
2012-09-01 12:00:00
2012-09-01 18:00:00
2012-09-02 00:00:00
2012-09-02 06:00:00
...
  • 字符串轉換為日期
    執行 datetime 對象轉化成日期字符串或者日期字符串轉化成datetime對象
    datetime模塊提供了strptime()和strftime()方法供使用,但是考慮到性能,當涉及到處理大量日期的時候,strptime()不建議使用,因為它是使用純 Python 實現,并且必須處理所有的系統本地設置,性能比想象中差很多。可自定義一個方法代替,比如:
from datetime import datetime
def parse_ymd(s):
year_s, mon_s, day_s = s.split('-')
return datetime(int(year_s), int(mon_s), int(day_s))
  • 結合時區的日期處理
    示例:
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> central = timezone('US/Central')
>>> loc_d = central.localize(d)
>>> d
datetime.datetime(2012, 12, 21, 9, 30)
>>> loc_d
datetime.datetime(2012, 12, 21, 9, 30, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>)
>>> 

上述關鍵是類似US/Central怎么得到?
為了查找,可以使用 ISO 3166 國家代碼作為關鍵字去查閱字典pytz.country timezones

>>> import pytz
>>> pytz.country_timezones['IN']
['Asia/Kolkata']
>>> pytz.country_timezones['AE']
['Asia/Dubai']
>>> 
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容