diff -r 16d47bd81d84 -r 3f89629b9e54 src/pyams_utils/date.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_utils/date.py Thu Feb 19 00:46:48 2015 +0100 @@ -0,0 +1,194 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard packages +from datetime import datetime + +# import interfaces + +# import packages +from pyams_utils.request import check_request +from pyams_utils.timezone import gmtime, tztime +from zope.datetime import parseDatetimetz + +from pyams_utils import _ + + +def unidate(value): + """Get specified date converted to unicode ISO format + + Dates are always assumed to be stored in GMT timezone + + @param value: input date to convert to unicode + @type value: date or datetime + @return: input date converted to unicode + @rtype: unicode + """ + if value is not None: + value = gmtime(value) + return value.isoformat('T') + return None + + +def parse_date(value): + """Get date specified in unicode ISO format to Python datetime object + + Dates are always assumed to be stored in GMT timezone + + @param value: unicode date to be parsed + @type value: unicode + @return: the specified value, converted to datetime + @rtype: datetime + """ + if value is not None: + return gmtime(parseDatetimetz(value)) + return None + + +def date_to_datetime(value): + """Get datetime value converted from a date or datetime object + + @param value: a date or datetime value to convert + @type value: date or datetime + @return: input value converted to datetime + @rtype: datetime + """ + if type(value) is datetime: + return value + return datetime(value.year, value.month, value.day) + + +SH_DATE_FORMAT = _("%d/%m/%Y") +SH_DATETIME_FORMAT = _("%d/%m/%Y - %H:%M") + +EXT_DATE_FORMAT = _("on %d/%m/%Y") +EXT_DATETIME_FORMAT = _("on %d/%m/%Y at %H:%M") + + +def format_date(value, format=EXT_DATE_FORMAT, request=None): + """Format given date with the given format""" + if request is None: + request = check_request() + localizer = request.localizer + return datetime.strftime(tztime(value), localizer.translate(format)) + + +def format_datetime(value, format=EXT_DATETIME_FORMAT, request=None): + """Format given datetime with the given format""" + return format_date(value, format, request) + + +def get_age(value): + """Get age of a given datetime (including timezone) compared to current datetime (in UTC) + + @param value: a datetime value, including timezone + @type value: datetime + @return: string representing value age + @rtype: gettext translated string + """ + request = check_request() + translate = request.localizer.translate + now = gmtime(datetime.utcnow()) + delta = now - value + if delta.days > 60: + return translate(_("%d months ago")) % int(round(delta.days * 1.0 / 30)) + elif delta.days > 10: + return translate(_("%d weeks ago")) % int(round(delta.days * 1.0 / 7)) + elif delta.days > 2: + return translate(_("%d days ago")) % delta.days + elif delta.days == 2: + return translate(_("the day before yesterday")) + elif delta.days == 1: + return translate(_("yesterday")) + else: + hours = int(round(delta.seconds * 1.0 / 3600)) + if hours > 1: + return translate(_("%d hours ago")) % hours + elif delta.seconds > 300: + return translate(_("%d minutes ago")) % int(round(delta.seconds * 1.0 / 60)) + else: + return translate(_("less than 5 minutes ago")) + + +def get_duration(v1, v2=None, request=None): + """Get delta as string between two dates + + >>> from datetime import datetime + >>> from pyams_utils.date import get_duration + >>> from pyramid.testing import DummyRequest + >>> request = DummyRequest() + >>> date1 = datetime(2015, 1, 1) + >>> date2 = datetime(2014, 3, 1) + >>> get_duration(date1, date2, request) + '10 months' + + Dates order is not important: + >>> get_duration(date2, date1, request) + '10 months' + >>> date2 = datetime(2014, 11, 10) + >>> get_duration(date1, date2, request) + '7 weeks' + >>> date2 = datetime(2014, 12, 26) + >>> get_duration(date1, date2, request) + '6 days' + + For durations lower than 2 days, duration also display hours: + >>> date1 = datetime(2015, 1, 1) + >>> date2 = datetime(2015, 1, 2, 15, 10, 0) + >>> get_duration(date1, date2, request) + '1 day and 15 hours' + >>> date2 = datetime(2015, 1, 2) + >>> get_duration(date1, date2, request) + '24 hours' + >>> date2 = datetime(2015, 1, 1, 13, 12) + >>> get_duration(date1, date2, request) + '13 hours' + >>> date2 = datetime(2015, 1, 1, 1, 15) + >>> get_duration(date1, date2, request) + '75 minutes' + >>> date2 = datetime(2015, 1, 1, 0, 0, 15) + >>> get_duration(date1, date2, request) + '15 seconds' + """ + if v2 is None: + v2 = datetime.utcnow() + assert isinstance(v1, datetime) and isinstance(v2, datetime) + if request is None: + request = check_request() + translate = request.localizer.translate + v1, v2 = min(v1, v2), max(v1, v2) + delta = v2 - v1 + if delta.days > 60: + return translate(_("%d months")) % int(round(delta.days * 1.0 / 30)) + elif delta.days > 10: + return translate(_("%d weeks")) % int(round(delta.days * 1.0 / 7)) + elif delta.days >= 2: + return translate(_("%d days")) % delta.days + else: + hours = int(round(delta.seconds * 1.0 / 3600)) + if delta.days == 1: + if hours == 0: + return translate(_("24 hours")) + else: + return translate(_("%d day and %d hours")) % (delta.days, hours) + else: + if hours > 2: + return translate(_("%d hours")) % hours + else: + minutes = int(round(delta.seconds * 1.0 / 60)) + if minutes > 2: + return translate(_("%d minutes")) % minutes + else: + return translate(_("%d seconds")) % delta.seconds