#!/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(\'<html><head><link rel="shortcut icon" href="/favicon.ico" /><title>Humanized Dates Web Service</title></head><body>Works either as Yahoo! Pipes <a target="_blank" href="http://pipes.yahoo.com/pipes/docs?doc=operators#WebService">web service</a>: makes a new field "when" based on "y:published.utime",<br />or by giving url parameter unixtime, <a href="/?unixtime=1337752504">example</a>. By MS-potilas 2012. See <a href="http://yabtb.blogspot.com/2012/05/extending-yahoo-pipes-with-google-app.html">yabtb.blogspot.com</a>.\')
self.response.out.write(\'</body></html>\')
return 0;
def post(self):
try:
data = self.request.get("data")
items = simplejson.loads(data)
items = items["items"]
for item in items:
utime = int(item[\'y:published\'][\'utime\'])
dt = datetime.fromtimestamp(utime)
item[\'when\'] = naturaltime(dt)
self.response.content_type = "application/json"
simplejson.dump(items, self.response.out)
finally:
return 0;
def main():
application = webapp.WSGIApplication([(\'/\', MainHandler)],
debug=True)
util.run_wsgi_app(application)
if __name__ == \'__main__\':
main()