#!/usr/bin/env python # # Humandate - a web service to humanize dates with Yahoo! Pipes # MS-potilas 2012. See http://yabtb.blogspot.com/2012/05/extending-yahoo-pipes-with-google-app.html # from google.appengine.ext import webapp from google.appengine.ext.webapp import util import simplejson # # MS-potilas: time humanizing code begins, borrowed from Django's "contrib.humanize". # import time from datetime import datetime, timedelta, date def _now(): return datetime.now() def abs_timedelta(delta): """Returns an "absolute" value for a timedelta, always representing a time distance.""" if delta.days < 0: now = _now() return now - (now + delta) return delta def date_and_delta(value): """Turn a value into a date and a timedelta which represents how long ago it was. If that's not possible, return (None, value).""" now = _now() if isinstance(value, datetime): date = value delta = now - value elif isinstance(value, timedelta): date = now - value delta = value else: try: value = int(value) delta = timedelta(seconds=value) date = now - delta except (ValueError, TypeError): return (None, value) return date, abs_timedelta(delta) def naturaldelta(value, months=True, onlyoneyear=True): """Given a timedelta or a number of seconds, return a natural representation of the amount of time elapsed. This is similar to ``naturaltime``, but does not add tense to the result. If ``months`` is True, then a number of months (based on 30.5 days) will be used for fuzziness between years. MS-potilas: if ``onlyoneyear`` is True, no fuzziness between years 1-2. Changed "an hour" to "1 hour" etc. (don't change "a moment"!) """ date, delta = date_and_delta(value) if date is None: return value use_months = months seconds = abs(delta.seconds) days = abs(delta.days) years = days // 365 days = days % 365 months = int(days // 30.5) if not years and days < 1: if seconds == 0: return "a moment" elif seconds == 1: return "1 second" elif seconds < 60: return "%d seconds" % (seconds) elif 60 <= seconds < 120: return "1 minute" elif 120 <= seconds < 3600: return "%d minutes" % (seconds // 60) elif 3600 <= seconds < 3600*2: return "1 hour" elif 3600 < seconds: return "%d hours" % (seconds // 3600) elif years == 0: if days == 1: return "1 day" if not use_months: return "%d days" % days else: if not months: return "%d days" % days elif months == 1: return "1 month" else: return "%d months" % months elif years == 1: if onlyoneyear: return "1 year" if not months and not days: return "1 year" elif not months: return "1 year, %d days" % days elif use_months: if months == 1: return "1 year, 1 month" else: return "1 year, %d months" % months else: return "1 year, %d days" % days else: return "%d years" % years def naturaltime(value, future=False, months=True): """Given a datetime or a number of seconds, return a natural representation of that time in a resolution that makes sense. This is more or less compatible with Django's ``naturaltime`` filter. ``future`` is ignored for datetimes, where the tense is always figured out based on the current time. If an integer is passed, the return value will be past tense by default, unless ``future`` is set to True.""" now = _now() date, delta = date_and_delta(value) if date is None: return value # determine tense by value only if datetime/timedelta were passed if isinstance(value, (datetime, timedelta)): future = date > now ago = 'from now' if future else 'ago' delta = naturaldelta(delta) if delta == "a moment": return "now" return "%s %s" % (delta, ago) # # MS-potilas: time humanizing code ends. # class MainHandler(webapp.RequestHandler): def get(self): try: utime = int(self.request.get("unixtime")) if utime > 0: dt = datetime.fromtimestamp(utime) self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(naturaltime(dt)) except: self.response.headers.add_header("Cache-Control", "public, max-age=14400") self.response.out.write('