Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: appengine/monorail/framework/timestr.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is govered by a BSD-style
3 # license that can be found in the LICENSE file or at
4 # https://developers.google.com/open-source/licenses/bsd
5
6 """Time-to-string and time-from-string routines."""
7
8 import datetime
9 import time
10
11
12 class Error(Exception):
13 """Exception used to indicate problems with time routines."""
14 pass
15
16
17 HTML_TIME_FMT = '%a, %d %b %Y %H:%M:%S GMT'
18
19 MONTH_YEAR_FMT = '%b %Y'
20 MONTH_DAY_FMT = '%b %d'
21 MONTH_DAY_YEAR_FMT = '%b %d %Y'
22
23 # We assume that all server clocks are synchronized within this amount.
24 MAX_CLOCK_SKEW_SEC = 30
25
26
27 def TimeForHTMLHeader(when=None):
28 """Return the given time (or now) in HTML header format."""
29 if when is None:
30 when = int(time.time())
31 return time.strftime(HTML_TIME_FMT, time.gmtime(when))
32
33
34 def FormatAbsoluteDate(
35 timestamp, clock=datetime.datetime.utcnow,
36 recent_format=MONTH_DAY_FMT, old_format=MONTH_YEAR_FMT):
37 """Format timestamp like 'Sep 5', or 'Yesterday', or 'Today'.
38
39 Args:
40 timestamp: Seconds since the epoch in UTC.
41 clock: callable that returns a datetime.datetime object when called with no
42 arguments, giving the current time to use when computing what to display.
43 recent_format: Format string to pass to strftime to present dates between
44 six months ago and yesterday.
45 old_format: Format string to pass to strftime to present dates older than
46 six months or more than skew_tolerance in the future.
47
48 Returns:
49 If timestamp's date is today, "Today". If timestamp's date is yesterday,
50 "Yesterday". If timestamp is within six months before today, return the
51 time as formatted by recent_format. Otherwise, return the time as formatted
52 by old_format.
53 """
54 ts = datetime.datetime.fromtimestamp(timestamp)
55 now = clock()
56 month_delta = 12 * now.year + now.month - (12 * ts.year + ts.month)
57 delta = now - ts
58
59 if ts > now:
60 # If the time is slightly in the future due to clock skew, treat as today.
61 skew_tolerance = datetime.timedelta(seconds=MAX_CLOCK_SKEW_SEC)
62 if -delta <= skew_tolerance:
63 return 'Today'
64 # Otherwise treat it like an old date.
65 else:
66 fmt = old_format
67 elif month_delta > 6 or delta.days >= 365:
68 fmt = old_format
69 elif delta.days == 1:
70 return 'Yesterday'
71 elif delta.days == 0:
72 return 'Today'
73 else:
74 fmt = recent_format
75
76 return time.strftime(fmt, time.localtime(timestamp)).replace(' 0', ' ')
77
78
79 def FormatRelativeDate(timestamp, recent_only=False, clock=None):
80 """Return a short string that makes timestamp more meaningful to the user.
81
82 Describe the timestamp relative to the current time, e.g., '4
83 hours ago'. In cases where the timestamp is more than 6 days ago,
84 we simply show the year, so that the combined absolute and
85 relative parts look like 'Sep 05, 2005'.
86
87 Args:
88 timestamp: Seconds since the epoch in UTC.
89 recent_only: If True, only return a description of recent relative
90 dates. Do not return the year, and do not put results inside parentheses.
91 clock: optional function to return an int time, like int(time.time()).
92
93 Returns:
94 String describing relative time.
95 """
96 if clock:
97 now = clock()
98 else:
99 now = int(time.time())
100
101 # TODO(jrobbins): i18n of date strings
102 delta = int(now - timestamp)
103 d_minutes = delta // 60
104 d_hours = d_minutes // 60
105 d_days = d_hours // 24
106 if recent_only:
107 if d_days > 6:
108 return ''
109 if d_days > 1:
110 return '%s days ago' % d_days # starts at 2 days
111 if d_hours > 1:
112 return '%s hours ago' % d_hours # starts at 2 hours
113 if d_minutes > 1:
114 return '%s minutes ago' % d_minutes
115 if d_minutes > 0:
116 return '1 minute ago'
117 if delta > -MAX_CLOCK_SKEW_SEC:
118 return 'moments ago'
119 return ''
120 else:
121 if d_days > 6:
122 return ', %s' % (time.localtime(timestamp))[0]
123 if d_days > 1:
124 return ' (%s days ago)' % d_days # starts at 2 days
125 if d_hours > 1:
126 return ' (%s hours ago)' % d_hours # starts at 2 hours
127 if d_minutes > 1:
128 return ' (%s minutes ago)' % d_minutes
129 if d_minutes > 0:
130 return ' (1 minute ago)'
131 if delta > -MAX_CLOCK_SKEW_SEC:
132 return ' (moments ago)'
133 # Only say something is in the future if it is more than just clock skew.
134 return ' (in the future)'
135
136
137 def GetHumanScaleDate(timestamp, now=None):
138 """Formats a timestamp to a course-grained and fine-grained time phrase.
139
140 Args:
141 timestamp: Seconds since the epoch in UTC.
142 now: Current time in seconds since the epoch in UTC.
143
144 Returns:
145 A pair (course_grain, fine_grain) where course_grain is a string
146 such as 'Today', 'Yesterday', etc.; and fine_grained is a string describing
147 relative hours for Today and Yesterday, or an exact date for longer ago.
148 """
149 if now is None:
150 now = int(time.time())
151
152 now_year = datetime.datetime.fromtimestamp(now).year
153 then_year = datetime.datetime.fromtimestamp(timestamp).year
154 delta = int(now - timestamp)
155 delta_minutes = delta // 60
156 delta_hours = delta_minutes // 60
157 delta_days = delta_hours // 24
158
159 if 0 <= delta_hours < 24:
160 if delta_hours > 1:
161 return 'Today', '%s hours ago' % delta_hours
162 if delta_minutes > 1:
163 return 'Today', '%s min ago' % delta_minutes
164 if delta_minutes > 0:
165 return 'Today', '1 min ago'
166 if delta > 0:
167 return 'Today', 'moments ago'
168 if 0 <= delta_hours < 48:
169 return 'Yesterday', '%s hours ago' % delta_hours
170 if 0 <= delta_days < 7:
171 return 'Last 7 days', time.strftime(
172 '%b %d, %Y', (time.localtime(timestamp)))
173 if 0 <= delta_days < 30:
174 return 'Last 30 days', time.strftime(
175 '%b %d, %Y', (time.localtime(timestamp)))
176 if delta > 0:
177 if now_year == then_year:
178 return 'Earlier this year', time.strftime(
179 '%b %d, %Y', (time.localtime(timestamp)))
180 return 'Older', time.strftime('%b %d, %Y', (time.localtime(timestamp)))
181 if delta > -MAX_CLOCK_SKEW_SEC:
182 return 'Today', 'moments ago'
183 # Only say something is in the future if it is more than just clock skew.
184 return 'Future', 'Later'
OLDNEW
« no previous file with comments | « appengine/monorail/framework/test/xsrf_test.py ('k') | appengine/monorail/framework/tokenrefresh.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698