|
1 # |
|
2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net> |
|
3 # All Rights Reserved. |
|
4 # |
|
5 # This software is subject to the provisions of the Zope Public License, |
|
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
|
10 # FOR A PARTICULAR PURPOSE. |
|
11 # |
|
12 |
|
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 |
|
16 # import standard packages |
|
17 from datetime import datetime |
|
18 |
|
19 # import interfaces |
|
20 |
|
21 # import packages |
|
22 from pyams_utils.request import check_request |
|
23 from pyams_utils.timezone import gmtime, tztime |
|
24 from zope.datetime import parseDatetimetz |
|
25 |
|
26 from pyams_utils import _ |
|
27 |
|
28 |
|
29 def unidate(value): |
|
30 """Get specified date converted to unicode ISO format |
|
31 |
|
32 Dates are always assumed to be stored in GMT timezone |
|
33 |
|
34 @param value: input date to convert to unicode |
|
35 @type value: date or datetime |
|
36 @return: input date converted to unicode |
|
37 @rtype: unicode |
|
38 """ |
|
39 if value is not None: |
|
40 value = gmtime(value) |
|
41 return value.isoformat('T') |
|
42 return None |
|
43 |
|
44 |
|
45 def parse_date(value): |
|
46 """Get date specified in unicode ISO format to Python datetime object |
|
47 |
|
48 Dates are always assumed to be stored in GMT timezone |
|
49 |
|
50 @param value: unicode date to be parsed |
|
51 @type value: unicode |
|
52 @return: the specified value, converted to datetime |
|
53 @rtype: datetime |
|
54 """ |
|
55 if value is not None: |
|
56 return gmtime(parseDatetimetz(value)) |
|
57 return None |
|
58 |
|
59 |
|
60 def date_to_datetime(value): |
|
61 """Get datetime value converted from a date or datetime object |
|
62 |
|
63 @param value: a date or datetime value to convert |
|
64 @type value: date or datetime |
|
65 @return: input value converted to datetime |
|
66 @rtype: datetime |
|
67 """ |
|
68 if type(value) is datetime: |
|
69 return value |
|
70 return datetime(value.year, value.month, value.day) |
|
71 |
|
72 |
|
73 SH_DATE_FORMAT = _("%d/%m/%Y") |
|
74 SH_DATETIME_FORMAT = _("%d/%m/%Y - %H:%M") |
|
75 |
|
76 EXT_DATE_FORMAT = _("on %d/%m/%Y") |
|
77 EXT_DATETIME_FORMAT = _("on %d/%m/%Y at %H:%M") |
|
78 |
|
79 |
|
80 def format_date(value, format=EXT_DATE_FORMAT, request=None): |
|
81 """Format given date with the given format""" |
|
82 if request is None: |
|
83 request = check_request() |
|
84 localizer = request.localizer |
|
85 return datetime.strftime(tztime(value), localizer.translate(format)) |
|
86 |
|
87 |
|
88 def format_datetime(value, format=EXT_DATETIME_FORMAT, request=None): |
|
89 """Format given datetime with the given format""" |
|
90 return format_date(value, format, request) |
|
91 |
|
92 |
|
93 def get_age(value): |
|
94 """Get age of a given datetime (including timezone) compared to current datetime (in UTC) |
|
95 |
|
96 @param value: a datetime value, including timezone |
|
97 @type value: datetime |
|
98 @return: string representing value age |
|
99 @rtype: gettext translated string |
|
100 """ |
|
101 request = check_request() |
|
102 translate = request.localizer.translate |
|
103 now = gmtime(datetime.utcnow()) |
|
104 delta = now - value |
|
105 if delta.days > 60: |
|
106 return translate(_("%d months ago")) % int(round(delta.days * 1.0 / 30)) |
|
107 elif delta.days > 10: |
|
108 return translate(_("%d weeks ago")) % int(round(delta.days * 1.0 / 7)) |
|
109 elif delta.days > 2: |
|
110 return translate(_("%d days ago")) % delta.days |
|
111 elif delta.days == 2: |
|
112 return translate(_("the day before yesterday")) |
|
113 elif delta.days == 1: |
|
114 return translate(_("yesterday")) |
|
115 else: |
|
116 hours = int(round(delta.seconds * 1.0 / 3600)) |
|
117 if hours > 1: |
|
118 return translate(_("%d hours ago")) % hours |
|
119 elif delta.seconds > 300: |
|
120 return translate(_("%d minutes ago")) % int(round(delta.seconds * 1.0 / 60)) |
|
121 else: |
|
122 return translate(_("less than 5 minutes ago")) |
|
123 |
|
124 |
|
125 def get_duration(v1, v2=None, request=None): |
|
126 """Get delta as string between two dates |
|
127 |
|
128 >>> from datetime import datetime |
|
129 >>> from pyams_utils.date import get_duration |
|
130 >>> from pyramid.testing import DummyRequest |
|
131 >>> request = DummyRequest() |
|
132 >>> date1 = datetime(2015, 1, 1) |
|
133 >>> date2 = datetime(2014, 3, 1) |
|
134 >>> get_duration(date1, date2, request) |
|
135 '10 months' |
|
136 |
|
137 Dates order is not important: |
|
138 >>> get_duration(date2, date1, request) |
|
139 '10 months' |
|
140 >>> date2 = datetime(2014, 11, 10) |
|
141 >>> get_duration(date1, date2, request) |
|
142 '7 weeks' |
|
143 >>> date2 = datetime(2014, 12, 26) |
|
144 >>> get_duration(date1, date2, request) |
|
145 '6 days' |
|
146 |
|
147 For durations lower than 2 days, duration also display hours: |
|
148 >>> date1 = datetime(2015, 1, 1) |
|
149 >>> date2 = datetime(2015, 1, 2, 15, 10, 0) |
|
150 >>> get_duration(date1, date2, request) |
|
151 '1 day and 15 hours' |
|
152 >>> date2 = datetime(2015, 1, 2) |
|
153 >>> get_duration(date1, date2, request) |
|
154 '24 hours' |
|
155 >>> date2 = datetime(2015, 1, 1, 13, 12) |
|
156 >>> get_duration(date1, date2, request) |
|
157 '13 hours' |
|
158 >>> date2 = datetime(2015, 1, 1, 1, 15) |
|
159 >>> get_duration(date1, date2, request) |
|
160 '75 minutes' |
|
161 >>> date2 = datetime(2015, 1, 1, 0, 0, 15) |
|
162 >>> get_duration(date1, date2, request) |
|
163 '15 seconds' |
|
164 """ |
|
165 if v2 is None: |
|
166 v2 = datetime.utcnow() |
|
167 assert isinstance(v1, datetime) and isinstance(v2, datetime) |
|
168 if request is None: |
|
169 request = check_request() |
|
170 translate = request.localizer.translate |
|
171 v1, v2 = min(v1, v2), max(v1, v2) |
|
172 delta = v2 - v1 |
|
173 if delta.days > 60: |
|
174 return translate(_("%d months")) % int(round(delta.days * 1.0 / 30)) |
|
175 elif delta.days > 10: |
|
176 return translate(_("%d weeks")) % int(round(delta.days * 1.0 / 7)) |
|
177 elif delta.days >= 2: |
|
178 return translate(_("%d days")) % delta.days |
|
179 else: |
|
180 hours = int(round(delta.seconds * 1.0 / 3600)) |
|
181 if delta.days == 1: |
|
182 if hours == 0: |
|
183 return translate(_("24 hours")) |
|
184 else: |
|
185 return translate(_("%d day and %d hours")) % (delta.days, hours) |
|
186 else: |
|
187 if hours > 2: |
|
188 return translate(_("%d hours")) % hours |
|
189 else: |
|
190 minutes = int(round(delta.seconds * 1.0 / 60)) |
|
191 if minutes > 2: |
|
192 return translate(_("%d minutes")) % minutes |
|
193 else: |
|
194 return translate(_("%d seconds")) % delta.seconds |