Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/framework/timestr.py b/framework/timestr.py
new file mode 100644
index 0000000..2b32e8c
--- /dev/null
+++ b/framework/timestr.py
@@ -0,0 +1,188 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""Time-to-string and time-from-string routines."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import calendar
+import datetime
+import time
+
+
+class Error(Exception):
+  """Exception used to indicate problems with time routines."""
+  pass
+
+
+HTML_TIME_FMT = '%a, %d %b %Y %H:%M:%S GMT'
+HTML_DATE_WIDGET_FORMAT = '%Y-%m-%d'
+
+MONTH_YEAR_FMT = '%b %Y'
+MONTH_DAY_FMT = '%b %d'
+MONTH_DAY_YEAR_FMT = '%b %d %Y'
+
+# We assume that all server clocks are synchronized within this amount.
+MAX_CLOCK_SKEW_SEC = 30
+
+
+def TimeForHTMLHeader(when=None):
+  """Return the given time (or now) in HTML header format."""
+  if when is None:
+    when = int(time.time())
+  return time.strftime(HTML_TIME_FMT, time.gmtime(when))
+
+
+def TimestampToDateWidgetStr(when):
+  """Format a timestamp int for use by HTML <input type="date">."""
+  return time.strftime(HTML_DATE_WIDGET_FORMAT, time.gmtime(when))
+
+
+def DateWidgetStrToTimestamp(val_str):
+  """Parse the HTML <input type="date"> string into a timestamp int."""
+  return int(calendar.timegm(time.strptime(val_str, HTML_DATE_WIDGET_FORMAT)))
+
+
+def FormatAbsoluteDate(
+    timestamp, clock=datetime.datetime.utcnow,
+    recent_format=MONTH_DAY_FMT, old_format=MONTH_YEAR_FMT):
+  """Format timestamp like 'Sep 5', or 'Yesterday', or 'Today'.
+
+  Args:
+    timestamp: Seconds since the epoch in UTC.
+    clock: callable that returns a datetime.datetime object when called with no
+      arguments, giving the current time to use when computing what to display.
+    recent_format: Format string to pass to strftime to present dates between
+      six months ago and yesterday.
+    old_format: Format string to pass to strftime to present dates older than
+      six months or more than skew_tolerance in the future.
+
+  Returns:
+    If timestamp's date is today, "Today". If timestamp's date is yesterday,
+    "Yesterday". If timestamp is within six months before today, return the
+    time as formatted by recent_format. Otherwise, return the time as formatted
+    by old_format.
+  """
+  ts = datetime.datetime.utcfromtimestamp(timestamp)
+  now = clock()
+  month_delta = 12 * now.year + now.month - (12 * ts.year + ts.month)
+  delta = now - ts
+
+  if ts > now:
+    # If the time is slightly in the future due to clock skew, treat as today.
+    skew_tolerance = datetime.timedelta(seconds=MAX_CLOCK_SKEW_SEC)
+    if -delta <= skew_tolerance:
+      return 'Today'
+    # Otherwise treat it like an old date.
+    else:
+      fmt = old_format
+  elif month_delta > 6 or delta.days >= 365:
+    fmt = old_format
+  elif delta.days == 1:
+    return 'Yesterday'
+  elif delta.days == 0:
+    return 'Today'
+  else:
+    fmt = recent_format
+
+  return time.strftime(fmt, time.gmtime(timestamp)).replace(' 0', ' ')
+
+
+def FormatRelativeDate(timestamp, days_only=False, clock=None):
+  """Return a short string that makes timestamp more meaningful to the user.
+
+  Describe the timestamp relative to the current time, e.g., '4
+  hours ago'.  In cases where the timestamp is more than 6 days ago,
+  we return '' so that an alternative display can be used instead.
+
+  Args:
+    timestamp: Seconds since the epoch in UTC.
+    days_only: If True, return 'N days ago' even for more than 6 days.
+    clock: optional function to return an int time, like int(time.time()).
+
+  Returns:
+    String describing relative time.
+  """
+  if clock:
+    now = clock()
+  else:
+    now = int(time.time())
+
+  # TODO(jrobbins): i18n of date strings
+  delta = int(now - timestamp)
+  d_minutes = delta // 60
+  d_hours = d_minutes // 60
+  d_days = d_hours // 24
+  if days_only:
+    if d_days > 1:
+      return '%s days ago' % d_days
+    else:
+      return ''
+
+  if d_days > 6:
+    return ''
+  if d_days > 1:
+    return '%s days ago' % d_days  # starts at 2 days
+  if d_hours > 1:
+    return '%s hours ago' % d_hours  # starts at 2 hours
+  if d_minutes > 1:
+    return '%s minutes ago' % d_minutes
+  if d_minutes > 0:
+    return '1 minute ago'
+  if delta > -MAX_CLOCK_SKEW_SEC:
+    return 'moments ago'
+  return ''
+
+
+def GetHumanScaleDate(timestamp, now=None):
+  """Formats a timestamp to a course-grained and fine-grained time phrase.
+
+  Args:
+    timestamp: Seconds since the epoch in UTC.
+    now: Current time in seconds since the epoch in UTC.
+
+  Returns:
+    A pair (course_grain, fine_grain) where course_grain is a string
+    such as 'Today', 'Yesterday', etc.; and fine_grained is a string describing
+    relative hours for Today and Yesterday, or an exact date for longer ago.
+  """
+  if now is None:
+    now = int(time.time())
+
+  now_year = datetime.datetime.fromtimestamp(now).year
+  then_year = datetime.datetime.fromtimestamp(timestamp).year
+  delta = int(now - timestamp)
+  delta_minutes = delta // 60
+  delta_hours = delta_minutes // 60
+  delta_days = delta_hours // 24
+
+  if 0 <= delta_hours < 24:
+    if delta_hours > 1:
+      return 'Today', '%s hours ago' % delta_hours
+    if delta_minutes > 1:
+      return 'Today', '%s min ago' % delta_minutes
+    if delta_minutes > 0:
+      return 'Today', '1 min ago'
+    if delta > 0:
+      return 'Today', 'moments ago'
+  if 0 <= delta_hours < 48:
+    return 'Yesterday', '%s hours ago' % delta_hours
+  if 0 <= delta_days < 7:
+    return 'Last 7 days', time.strftime(
+        '%b %d, %Y', (time.localtime(timestamp)))
+  if 0 <= delta_days < 30:
+    return 'Last 30 days', time.strftime(
+        '%b %d, %Y', (time.localtime(timestamp)))
+  if delta > 0:
+    if now_year == then_year:
+      return 'Earlier this year', time.strftime(
+          '%b %d, %Y', (time.localtime(timestamp)))
+    return ('Before this year',
+            time.strftime('%b %d, %Y', (time.localtime(timestamp))))
+  if delta > -MAX_CLOCK_SKEW_SEC:
+    return 'Today', 'moments ago'
+  # Only say something is in the future if it is more than just clock skew.
+  return 'Future', 'Later'