"""Date utils.""" import datetime from datetime import timedelta def get(string, date_format='%Y-%m-%d'): """Create a date from a string. Datetime offers strptime which takes a string and a format. In most cases, we use the format Year-Month-Day as a value, so this method creates a handy shortcut for this method. Example:: from utils import date current_date = date.get('2014-10-10') Args: string (str): the date as a string. date_format (str): the date format. Returns: datetime.datetime: date object that represents the string. """ return datetime.datetime.strptime(string, date_format) def month_difference(start_date, end_date): """Return the number of months between two dates. Args: start_date (datetime): the datetime object that contains the date informations. end_date (datetime): similar to start_date. Returns: int: Number of months between two dates. """ return ( (end_date.year - start_date.year) * 12 - start_date.month + end_date.month ) + 1 # +1 to include the last month def month_chunk(start_date, end_date, size=1): """Split a date range into tuples of x month(s). The goal of this method is to create chunk of date ranges that cover a period of time (defined by start date, end date). The size param defines the maximum number of months each date range should cover. Example:: for start_date, end_date in month_range('10/10/2014', '12/25/2014'): print(start_date, end_date) # prints: # (10/10/2014, 10/31/2014) # (11/1/2014, 12/1/2014) # (12/1/2014, 12/25/2014) # Using a size of 3 for start_date, end_date in month_range( '8/29/2014', '12/25/2014', size=3): print(start_date, end_date) # prints: # (8/29/2014, 10/31/2014) - 3 months (august, sept, oct) # (11/1/2014, 12/25/2014) - 2 remaining months (nov, dec) Args: start_date (datetime): the start date. end_date (datetime): the end date size (int): how many months should be in each chunk. Yield: tuple: first part contains the start date, second part contains the end date. """ date_range = dict(start_date=start_date) generator = generator_month_between_dates(start_date, end_date) # The first date returned by the generator is start_date, which is not # needed. generator.__next__() for i, current in enumerate(generator): date_range.update(end_date=current - timedelta(days=1)) if (i % size) + 1 == size: yield date_range.get('start_date'), date_range.get('end_date') date_range = dict(start_date=current) if date_range: yield date_range['start_date'], end_date def generator_month_between_dates(start_date, end_date): """Generator that returns each month between two dates. This generator comes handy for any operations that requires the list of two months between two dates. Args: start_date (datetime): the start date. end_date (datetime): the end date (included.) Yields: datetime: The current date + 1 month. """ current_year = start_date.year current_month = start_date.month current_date = start_date while current_date <= end_date: yield current_date current_month = current_month + 1 if current_month > 12: current_month = 1 current_year = current_year + 1 current_date = datetime.datetime(current_year, current_month, 1)