moved datehelper in place
This commit is contained in:
4
lms/lib/datehelper/README.md
Normal file
4
lms/lib/datehelper/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
datehelper
|
||||||
|
==========
|
||||||
|
|
||||||
|
This Python module contains some useful date-related methods inspired by rails.
|
||||||
1
lms/lib/datehelper/__init__.py
Normal file
1
lms/lib/datehelper/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from time_ago_in_words import *
|
||||||
151
lms/lib/datehelper/time_ago_in_words.py
Normal file
151
lms/lib/datehelper/time_ago_in_words.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from dateutil.tz import tzlocal
|
||||||
|
import calendar
|
||||||
|
|
||||||
|
# only used for testing
|
||||||
|
def _timedelta(**kwargs):
|
||||||
|
kwargs['days'] = kwargs.get('days', 0)
|
||||||
|
if kwargs.get('years', False):
|
||||||
|
# not really a good solution since ignoring leap years
|
||||||
|
# but this is only for test anyways
|
||||||
|
kwargs['days'] += kwargs['years'] * 365
|
||||||
|
del kwargs['years']
|
||||||
|
if kwargs.get('months', False):
|
||||||
|
kwargs['days'] += kwargs['months'] * 30
|
||||||
|
del kwargs['months']
|
||||||
|
return timedelta(**kwargs)
|
||||||
|
|
||||||
|
def time_ago_in_words(from_time, include_seconds=False):
|
||||||
|
return distance_of_time_in_words(from_time, datetime.now(tzlocal()), include_seconds=False)
|
||||||
|
|
||||||
|
distance_of_time_in_words_to_now = time_ago_in_words
|
||||||
|
|
||||||
|
def _time_in_words(before_text, unit):
|
||||||
|
if before_text:
|
||||||
|
before_text += ' '
|
||||||
|
def time_in_words_generator(count):
|
||||||
|
if count <= 1:
|
||||||
|
if before_text == 'less than ':
|
||||||
|
if unit == 'hour':
|
||||||
|
count = 'an'
|
||||||
|
else:
|
||||||
|
count = 'a'
|
||||||
|
return '{0}{1} {2}'.format(before_text, count, unit)
|
||||||
|
else:
|
||||||
|
return '{0}{1} {2}s'.format(before_text, count, unit)
|
||||||
|
return time_in_words_generator
|
||||||
|
|
||||||
|
def distance_of_time_in_words(from_time, to_time=0, include_seconds=False, options = {}):
|
||||||
|
"""Return a rough description of the time interval between from_time and to_time.
|
||||||
|
This is a direct translation from rails in ActionView::Helpers::DateHelper.
|
||||||
|
Reference:
|
||||||
|
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-distance_of_time_in_words
|
||||||
|
|
||||||
|
>>> from_time = datetime.now(tzlocal())
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(minutes=50))
|
||||||
|
'about 1 hour'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(seconds=15))
|
||||||
|
'less than a minute'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(seconds=15), True)
|
||||||
|
'less than 20 seconds'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(years=3))
|
||||||
|
'about 3 years'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(hours=60))
|
||||||
|
'3 days'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(seconds=45), True)
|
||||||
|
'less than a minute'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(seconds=-45), True)
|
||||||
|
'less than a minute'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(seconds=76))
|
||||||
|
'1 minute'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(years=1, days=3))
|
||||||
|
'about 1 year'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(years=3, months=6))
|
||||||
|
'over 3 years'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time + _timedelta(years=4, days=9, minutes=30, seconds=5))
|
||||||
|
'about 4 years'
|
||||||
|
>>> to_time = from_time + _timedelta(years=6, days=19)
|
||||||
|
>>> distance_of_time_in_words(from_time, to_time, True)
|
||||||
|
'about 6 years'
|
||||||
|
>>> distance_of_time_in_words(to_time, from_time, True)
|
||||||
|
'about 6 years'
|
||||||
|
>>> distance_of_time_in_words(from_time, from_time)
|
||||||
|
'less than a minute'
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(from_time, int):
|
||||||
|
from_time = datetime.fromtimestamp(time.time()+from_time)
|
||||||
|
if isinstance(to_time, int):
|
||||||
|
to_time = datetime.fromtimestamp(time.time()+to_time)
|
||||||
|
|
||||||
|
distance_in_minutes = int(round(abs((to_time - from_time).total_seconds()) / 60))
|
||||||
|
distance_in_seconds = int(round(abs((to_time - from_time).total_seconds())))
|
||||||
|
|
||||||
|
less_than_x_minutes = _time_in_words('less than', 'minute')
|
||||||
|
less_than_x_seconds = _time_in_words('less than', 'second')
|
||||||
|
half_a_minute = 'half a minute'
|
||||||
|
x_minutes = _time_in_words('', 'minute')
|
||||||
|
about_x_hours = _time_in_words('about', 'hour')
|
||||||
|
x_days = _time_in_words('', 'day')
|
||||||
|
about_x_months = _time_in_words('about', 'month')
|
||||||
|
x_months = _time_in_words('', 'month')
|
||||||
|
about_x_years = _time_in_words('about', 'year')
|
||||||
|
over_x_years = _time_in_words('over', 'year')
|
||||||
|
almost_x_years = _time_in_words('almost', 'year')
|
||||||
|
|
||||||
|
if 0 <= distance_in_minutes <= 1:
|
||||||
|
if not include_seconds:
|
||||||
|
if distance_in_minutes == 0:
|
||||||
|
return less_than_x_minutes(1)
|
||||||
|
else:
|
||||||
|
return x_minutes(distance_in_minutes)
|
||||||
|
else:
|
||||||
|
if 0 <= distance_in_seconds <= 4:
|
||||||
|
return less_than_x_seconds(5)
|
||||||
|
elif 5 <= distance_in_seconds <= 9:
|
||||||
|
return less_than_x_seconds(10)
|
||||||
|
elif 10 <= distance_in_seconds <= 19:
|
||||||
|
return less_than_x_seconds(20)
|
||||||
|
elif 20 <= distance_in_seconds <= 39:
|
||||||
|
return half_a_minute
|
||||||
|
elif 40 <= distance_in_seconds <= 59:
|
||||||
|
return less_than_x_minutes(1)
|
||||||
|
else:
|
||||||
|
return x_minutes(1)
|
||||||
|
elif 2 <= distance_in_minutes <= 44:
|
||||||
|
return x_minutes(distance_in_minutes)
|
||||||
|
elif 45 <= distance_in_minutes <= 89:
|
||||||
|
return about_x_hours(1)
|
||||||
|
elif 90 <= distance_in_minutes <= 1439:
|
||||||
|
return about_x_hours(int(round(float(distance_in_minutes) / 60.0)))
|
||||||
|
elif 1440 <= distance_in_minutes <= 2519:
|
||||||
|
return x_days(1)
|
||||||
|
elif 2520 <= distance_in_minutes <= 43199:
|
||||||
|
return x_days(int(round(float(distance_in_minutes) / 1440.0)))
|
||||||
|
elif 43200 <= distance_in_minutes <= 86399:
|
||||||
|
return about_x_months(1)
|
||||||
|
elif 86400 <= distance_in_minutes <= 525599:
|
||||||
|
return x_months(int(round(float(distance_in_minutes) / 43200.0)))
|
||||||
|
else:
|
||||||
|
fyear = from_time.year
|
||||||
|
if from_time.month >= 3:
|
||||||
|
fyear += 1
|
||||||
|
tyear = to_time.year
|
||||||
|
if to_time.month < 3:
|
||||||
|
tyear -= 1
|
||||||
|
leap_years = 0 if fyear > tyear else len([x for x in range(fyear, tyear + 1) if calendar.isleap(x)])
|
||||||
|
minute_offset_for_leap_year = leap_years * 1440
|
||||||
|
# Discount the leap year days when calculating year distance.
|
||||||
|
# e.g. if there are 20 leap year days between 2 dates having the same day
|
||||||
|
# and month then the based on 365 days calculation
|
||||||
|
# the distance in years will come out to over 80 years when in written
|
||||||
|
# english it would read better as about 80 years.
|
||||||
|
minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
|
||||||
|
remainder = (minutes_with_offset % 525600)
|
||||||
|
distance_in_years = (minutes_with_offset / 525600)
|
||||||
|
if remainder < 131400:
|
||||||
|
return about_x_years(distance_in_years)
|
||||||
|
elif remainder < 394200:
|
||||||
|
return over_x_years(distance_in_years)
|
||||||
|
else:
|
||||||
|
return almost_x_years(distance_in_years + 1)
|
||||||
Reference in New Issue
Block a user