牌語備忘録 -pygo

あくまでもメモです。なるべくオフィシャルの情報を参照してください。

牌語備忘録 -pygo

Python で外部モジュールなどを使わずに翌月末日などを取ってみるメモ

(python==2.7)

arrow とか dateutil とか便利だけどあえて使わずにやってみる。

何となくメソッドチェーンっぽくやってみる

翌々月以降や前々月以前、月初と月末を取れるようにしてみる
month_date_utility.py

#!/usr/bin/env python
# *-# -*- coding: utf-8 -*-

import datetime
from calendar import monthrange


class MonthDateUtility:
    """
    >>> date = datetime.datetime.strptime('2013-09-10', '%Y-%m-%d')
    >>> today = MonthDateUtility(date)
    >>> today.datetime
    datetime.datetime(2013, 9, 10, 0, 0)
    >>> today.first().datetime
    datetime.datetime(2013, 9, 1, 0, 0)
    >>> today.last().datetime
    datetime.datetime(2013, 9, 30, 0, 0)
    >>> today.next_month().datetime
    datetime.datetime(2013, 10, 10, 0, 0)
    >>> today.next_month(3).datetime
    datetime.datetime(2013, 12, 9, 0, 0)
    >>> today.next_month(4).first().datetime
    datetime.datetime(2014, 1, 1, 0, 0)
    >>> today.next_month(5).last().datetime
    datetime.datetime(2014, 2, 28, 0, 0)
    >>> today.prev_month().datetime
    datetime.datetime(2013, 8, 11, 0, 0)
    >>> today.prev_month(3).datetime
    datetime.datetime(2013, 6, 12, 0, 0)
    >>> today.prev_month(9).first().datetime
    datetime.datetime(2012, 12, 1, 0, 0)
    >>> today.prev_month(10).last().datetimedi
    datetime.datetime(2012, 11, 30, 0, 0)
    """

    def __init__(self, date_time):
        self.original_datetime = self.datetime = date_time

    def first(self):
        self.datetime = datetime.datetime(self.datetime.year, self.datetime.month, 1)
        return self

    def last(self):
        day_of_week, last_day = monthrange(self.datetime.year, self.datetime.month)
        self.datetime = datetime.datetime(self.datetime.year, self.datetime.month, last_day)
        return self

    def month_delta(self, num, is_next):
        date = self.original_datetime
        year = date.year
        month = date.month

        increase_decrease_num = 1 if is_next else -1

        for i in range(num):
            _, days = monthrange(year, month)
            date = date + datetime.timedelta(days=days) * increase_decrease_num
        self.datetime = date

    def next_month(self, num=1):
        self.month_delta(num, is_next=True)
        return self

    def prev_month(self, num=1):
        self.month_delta(num, is_next=False)
        return self


if __name__ == '__main__':
    import doctest
    doctest.testmod()

こんな感じ?

翌月末日を取ってみる
>>> import datetime
>>> date = datetime.datetime.strptime('2013-09-10', '%Y-%m-%d')
>>> from month_date_utility import MonthDateUtility
>>> MonthDateUtility(date).next_month(1).last().datetime
datetime.datetime(2013, 10, 31, 0, 0)

ちなみに外部モジュールを使った例

dateutil
>>> from dateutil.relativedelta import relativedelta
>>> date + relativedelta(months=+1, day=99)
datetime.datetime(2013, 10, 31, 0, 0)
arrow
>>> import arrow
>>> arrow.get(date).replace(months=2, day=1, days=-1).datetime
datetime.datetime(2013, 10, 31, 0, 0, tzinfo=tzutc())