#!/usr/bin/env python """ tempo.py - Time Format Utilities Author: Sean B. Palmer, inamidst.com """ usage = '%prog [options] filename | command' options = { ('-q', '--quiet'): 'Suppress error messages', ('-s', '--single'): 'Guarantee a single line of output', ('-v', '--verbose'): 'Give more information' } examples = { '$ tempo 25th September 2006 in: $w3c': '2006-09-25', '$ tempo 2005-06-01 in: %y': '2005', '$ tempo 1947-02 to: 1954-04 in: %s': '764743652543', '$ tempo avg: 00:15 00:20': '17 minutes, 30 seconds', '$ tempo avg: 00:15 00:20 in: $mins': '17.5 minutes', '$ tempo 3pm minus: 2:15': '12:45pm', '$ tempo 2005-02-01 days: 2005-02-03': ['2005-02-01', '2005-02-02', '2005-02-03'], '$ tempo on: 2006-01-15 to: next: tuesday in: %m': '6547' } examples = { '$ tempo 25th September 2006 in w3c': '2006-09-25', '$ tempo 2005-06-01 in %y': '2005', '$ tempo 1947-02 to 1954-04 in %s': '764743652543', '$ tempo avg 00:15 00:20': '17 minutes, 30 seconds', '$ tempo avg 00:15 00:20 in mins': '17.5 minutes', '$ tempo 3pm minus 2:15': '12:45pm', '$ tempo 2005-02-01 days 2005-02-03': ['2005-02-01', '2005-02-02', '2005-02-03'], '$ tempo on 2006-01-15 to next tuesday in %m': '6547' } # Get the current time first! import time clock = time.clock() now = time.time() # Now do all that slow stuff import sys, datetime todo = """ in: Date | Duration, Format -> Date | Duration to: Date?, Date -> Duration avg: Duration+ -> Duration minus: Date?, Duration -> Date take: " plus: Date?, Duration -> Date add: " days: Date?, Date -> Date+ as: String, Format -> Date next: Date?, Milestone -> Date this: " last: Date?, Milestone -> Date on: Date -> Nothing '$ tempo (25th September 2006 in: $w3c)': '$ tempo (2005-06-01 in: %y)': '$ tempo ((1947-02 to: 1954-04) in: %s)': '$ tempo (avg: 00:15 00:20)': '$ tempo ((avg: 00:15 00:20) in: $mins)': '$ tempo (3pm minus: 2:15)': '$ tempo (2005-02-01 days: 2005-02-03)': '$ tempo (on: 2006-01-15) ((to: (next: tuesday)) in: %m)': start = ( on: arg )? statement statement = keyword args | arg keyword arg | arg keyword statement | statement keyword arg | keyword statement * * * 25th | 25th September | 25th September 2007 25th Sept | 25th Sep Datetime = Date Time Date = Year Month Day | Year Month | Month Day | Day Month Year | Month Year | Day Month | Year | Month | Day Year = e.g. 2007 | 2007 AD | 2007AD Month = e.g. January | Janu | Jan | 1 | 01 Day = e.g. 1st | 1 | 01 Time = Hour:Minutes:Seconds | Minutes:Seconds | Hour Part | HourPart | Hour:MinutesPart | Hour:Minutes Part e.g. 3pm | 3PM | 3 pm | 3 PM | 03 PM | 03:15pm Relative = Dayname | next Dayname | last Dayname Dayname = Mon | Tue | Wed | etc. Monday | Tuesday | Wednesday | etc. M | Tu | W | etc. 2007-05-03 [0]3May2007 now in as avg minus days to on plus + - """ class Parser(object): def __init__(self): self.tokens = 'on: 2006-01-15 to: next: tuesday in: %m'.split(' ') self.pos = 0 def current(self): try: return self.tokens[self.pos] except: return None def kind(self): current = self.current() if current is None: return None return current[-1] def eat(self): token = self.tokens[self.pos] self.pos += 1 return token def run(self, command, args): print 'RUN: %r %r' % (command, args) def parse(self): self.context() self.statement() def context(self): if self.current() == 'on:': command = self.eat() arglets = [] for i in xrange(len(self.tokens) - self.pos): if self.kind() == ':': break arglet = self.eat() arglets.append(arglet) self.run(command, ' '.join(arglets)) def statement(self, limit=0): if limit == 0: limit = len(self.tokens) print 'STATEMENT:', self.current(), self.tokens[limit - 1] if self.kind() == ':': # keyword args | keyword statement | statement keyword arg # command = self.eat() command_mask = [tok.endswith(':') for tok in self.tokens[self.pos:limit]] print 'MASKING:', self.tokens[self.pos:limit] commands = command_mask.count(True) print 'COMMANDS:', commands, command_mask if commands > 2: print '> 2' # statement keyword arg i = command_mask.index(True) j = command_mask[i+1:].index(True) limit = self.pos + i + j + 3 statement = self.statement(limit) command = self.eat() arglets = [] for i in xrange(len(self.tokens) - self.pos): if self.kind() == ':': break arglet = self.eat() arglets.append(arglet) self.run(command, [statement, ' '.join(arglets)]) return ' '.join([command, statement, ' '.join(arglets)]) elif commands > 1: print '> 1' # keyword statement command = self.eat() statement = self.statement(limit) self.run(command, statement) return ' '.join([command, statement]) else: # keyword args print '= 1' command = self.eat() args = [] print 'PEEK:', self.current(), limit, self.pos for i in xrange(limit - self.pos + 1): if self.kind() == ':': break args.append(self.eat()) self.run(command, args) return ' '.join([command, ' '.join(args)]) def main(): p = Parser() p.parse() if __name__ == '__main__': main()