datetime_truncate.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. from datetime import timedelta
  2. __all__ = [
  3. 'truncate',
  4. 'truncate_second',
  5. 'truncate_minute',
  6. 'truncate_hour',
  7. 'truncate_day',
  8. 'truncate_week',
  9. 'truncate_month',
  10. 'truncate_quarter',
  11. 'truncate_half_year',
  12. 'truncate_year',
  13. ]
  14. PERIODS = {
  15. 'second': dict(microsecond=0),
  16. 'minute': dict(microsecond=0, second=0),
  17. 'hour': dict(microsecond=0, second=0, minute=0),
  18. 'day': dict(microsecond=0, second=0, minute=0, hour=0,),
  19. 'month': dict(microsecond=0, second=0, minute=0, hour=0, day=1),
  20. 'year': dict(microsecond=0, second=0, minute=0, hour=0, day=1, month=1),
  21. }
  22. ODD_PERIODS = ['week', 'quarter', 'half_year']
  23. def truncate_second(datetime):
  24. ''' Sugar for :py:func:`truncate(datetime, 'second')` '''
  25. return truncate(datetime, 'second')
  26. def truncate_minute(datetime):
  27. ''' Sugar for :py:func:`truncate(datetime, 'minute')` '''
  28. return truncate(datetime, 'minute')
  29. def truncate_hour(datetime):
  30. ''' Sugar for :py:func:`truncate(datetime, 'hour')` '''
  31. return truncate(datetime, 'hour')
  32. def truncate_day(datetime):
  33. ''' Sugar for :py:func:`truncate(datetime, 'day')` '''
  34. return truncate(datetime, 'day')
  35. def truncate_week(datetime):
  36. '''
  37. Truncates a date to the first day of an ISO 8601 week, i.e. monday.
  38. :params datetime: an initialized datetime object
  39. :return: `datetime` with the original day set to monday
  40. :rtype: :py:mod:`datetime` datetime object
  41. '''
  42. datetime = truncate(datetime, 'day')
  43. return datetime - timedelta(days=datetime.isoweekday() - 1)
  44. def truncate_month(datetime):
  45. ''' Sugar for :py:func:`truncate(datetime, 'month')` '''
  46. return truncate(datetime, 'month')
  47. def truncate_quarter(datetime):
  48. '''
  49. Truncates the datetime to the first day of the quarter for this date.
  50. :params datetime: an initialized datetime object
  51. :return: `datetime` with the month set to the first month of this quarter
  52. :rtype: :py:mod:`datetime` datetime object
  53. '''
  54. datetime = truncate(datetime, 'month')
  55. month = datetime.month
  56. if 1 <= month <= 3:
  57. return datetime.replace(month=1)
  58. elif 4 <= month <= 6:
  59. return datetime.replace(month=4)
  60. elif 7 <= month <= 9:
  61. return datetime.replace(month=7)
  62. elif 10 <= month <= 12:
  63. return datetime.replace(month=10)
  64. def truncate_half_year(datetime):
  65. '''
  66. Truncates the datetime to the first day of the half year for this date.
  67. :params datetime: an initialized datetime object
  68. :return: `datetime` with the month set to the first month of this half year
  69. :rtype: :py:mod:`datetime` datetime object
  70. '''
  71. datetime = truncate(datetime, 'month')
  72. month = datetime.month
  73. if 1 <= month <= 6:
  74. return datetime.replace(month=1)
  75. elif 7 <= month <= 12:
  76. return datetime.replace(month=7)
  77. def truncate_year(datetime):
  78. ''' Sugar for :py:func:`truncate(datetime, 'year')` '''
  79. return truncate(datetime, 'year')
  80. def truncate(datetime, truncate_to='day'):
  81. '''
  82. Truncates a datetime to have the values with higher precision than
  83. the one set as `truncate_to` as zero (or one for day and month).
  84. Possible values for `truncate_to`:
  85. * second
  86. * minute
  87. * hour
  88. * day
  89. * week (iso week i.e. to monday)
  90. * month
  91. * quarter
  92. * half_year
  93. * year
  94. Examples::
  95. >>> truncate(datetime(2012, 12, 12, 12), 'day')
  96. datetime(2012, 12, 12)
  97. >>> truncate(datetime(2012, 12, 14, 12, 15), 'quarter')
  98. datetime(2012, 10, 1)
  99. >>> truncate(datetime(2012, 3, 1), 'week')
  100. datetime(2012, 2, 27)
  101. :params datetime: an initialized datetime object
  102. :params truncate_to: The highest precision to keep its original data.
  103. :return: datetime with `truncated_to` as the highest level of precision
  104. :rtype: :py:mod:`datetime` datetime object
  105. '''
  106. if truncate_to in PERIODS:
  107. return datetime.replace(**PERIODS[truncate_to])
  108. elif truncate_to in ODD_PERIODS:
  109. if truncate_to == 'week':
  110. return truncate_week(datetime)
  111. elif truncate_to == 'quarter':
  112. return truncate_quarter(datetime)
  113. elif truncate_to == 'half_year':
  114. return truncate_half_year(datetime)
  115. else:
  116. raise ValueError('truncate_to not valid. Valid periods: {}'.format(
  117. ', '.join(PERIODS.keys() + ODD_PERIODS)
  118. ))