#!/usr/bin/env python3 # saytime.py by Bill Weinman [http://bw.org/] # Copyright 2010-2019 The BearHeart Gorup, LLC # updated 2019-12-02 for python 3.8 import sys import time __version__ = '1.3.0' class numwords(): ''' return a number as words, e.g., 42 becomes 'forty-two' ''' _words = { 'ones': ( 'oh', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine' ), 'tens': ( '', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' ), 'teens': ( 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' ), 'quarters': ( 'o\'clock', 'quarter', 'half' ), 'range': { 'hundred': 'hundred' }, 'misc': { 'minus': 'minus' } } _oor = 'OOR' # Out Of Range def __init__(self, n): self._number = n; def numwords(self, num = None): 'Return the number as words' n = self._number if num is None else num s = '' if n < 0: # negative numbers s += self._words['misc']['minus'] + ' ' n = abs(n) if n < 10: # single-digit numbers s += self._words['ones'][n] elif n < 20: # teens s += self._words['teens'][n - 10] elif n < 100: # tens m = n % 10 t = n // 10 s += self._words['tens'][t] if m: s += '-' + numwords(m).numwords() # recurse for remainder elif n < 1000: # hundreds m = n % 100 t = n // 100 s += self._words['ones'][t] + ' ' + self._words['range']['hundred'] if m: s += ' ' + numwords(m).numwords() # recurse for remainder else: s += self._oor return s def number(self, n = None): 'setter/getter' if n is not None: self._number = n return str(self._number); class saytime(numwords): ''' return the time (from two parameters) as words, e.g., fourteen til noon, quarter past one, etc. ''' _specials = { 'noon': 'noon', 'midnight': 'midnight', 'til': 'til', 'past': 'past' } def __init__(self, h = None, m = None): self.time(h, m) def time(self, h = None, m = None): if h is not None: self._hour = abs(int(h)) if m is not None: self._min = abs(int(m)) return (h, m) def time_t(self, t = None): if t is None: t = time.localtime() self._hour = t.tm_hour self._min = t.tm_min def words(self): h = self._hour m = self._min if h > 23: return self._oor # OOR errors if m > 59: return self._oor sign = self._specials['past'] if self._min > 30: sign = self._specials['til'] h += 1 m = 60 - m if h > 23: h -= 24 elif h > 12: h -= 12 # hword is the hours word) if h == 0: hword = self._specials['midnight'] elif h == 12: hword = self._specials['noon'] else: hword = self.numwords(h) if m == 0: if h in (0, 12): return hword # for noon and midnight else: return "{} {}".format(self.numwords(h), self._words['quarters'][m]) if m % 15 == 0: return "{} {} {}".format(self._words['quarters'][m // 15], sign, hword) return "{} {} {}".format(self.numwords(m), sign, hword) def digits(self): 'return the traditionl time, e.g., 13:42' return f'{self._hour:02}:{self._min:02}' class saytime_t(saytime): # wrapper for saytime to use time object ''' set the time from a time object ''' def __init__(self, t = None): self.time_t() def main(): if len(sys.argv) > 1: if sys.argv[1] == 'test': test() else: try: print(saytime(*(sys.argv[1].split(':'))).words()) except TypeError: print('Invalid time ({})'.format(sys.argv[1])) else: print(saytime_t().words()) def test(): st = saytime() print('\nnumbers test:') list = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 19, 20, 30, 50, 51, 52, 55, 59, 99, 100, 101, 112, 900, 999, 1000 ) for l in list: st.number(l) print(l, st.numwords()) print('\ntime test:') list = ( (0, 0), (0, 1), (11, 0), (12, 0), (13, 0), (12, 29), (12, 30), (12, 31), (12, 15), (12, 30), (12, 45), (11, 59), (23, 15), (23, 59), (12, 59), (13, 59), (1, 60), (24, 0) ) for l in list: st.time(*l) print(st.digits(), st.words()) st.time_t() # set time to now print('\nlocal time is ' + st.words()) if __name__ == '__main__': main()