saytime.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/env python3
  2. # saytime.py by Bill Weinman [http://bw.org/]
  3. # Copyright 2010-2019 The BearHeart Gorup, LLC
  4. # updated 2019-12-02 for python 3.8
  5. import sys
  6. import time
  7. __version__ = '1.3.0'
  8. class numwords():
  9. '''
  10. return a number as words,
  11. e.g., 42 becomes 'forty-two'
  12. '''
  13. _words = {
  14. 'ones': (
  15. 'oh', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'
  16. ), 'tens': (
  17. '', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'
  18. ), 'teens': (
  19. 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
  20. ), 'quarters': (
  21. 'o\'clock', 'quarter', 'half'
  22. ), 'range': {
  23. 'hundred': 'hundred'
  24. }, 'misc': {
  25. 'minus': 'minus'
  26. }
  27. }
  28. _oor = 'OOR' # Out Of Range
  29. def __init__(self, n):
  30. self._number = n;
  31. def numwords(self, num = None):
  32. 'Return the number as words'
  33. n = self._number if num is None else num
  34. s = ''
  35. if n < 0: # negative numbers
  36. s += self._words['misc']['minus'] + ' '
  37. n = abs(n)
  38. if n < 10: # single-digit numbers
  39. s += self._words['ones'][n]
  40. elif n < 20: # teens
  41. s += self._words['teens'][n - 10]
  42. elif n < 100: # tens
  43. m = n % 10
  44. t = n // 10
  45. s += self._words['tens'][t]
  46. if m: s += '-' + numwords(m).numwords() # recurse for remainder
  47. elif n < 1000: # hundreds
  48. m = n % 100
  49. t = n // 100
  50. s += self._words['ones'][t] + ' ' + self._words['range']['hundred']
  51. if m: s += ' ' + numwords(m).numwords() # recurse for remainder
  52. else:
  53. s += self._oor
  54. return s
  55. def number(self, n = None):
  56. 'setter/getter'
  57. if n is not None:
  58. self._number = n
  59. return str(self._number);
  60. class saytime(numwords):
  61. '''
  62. return the time (from two parameters) as words,
  63. e.g., fourteen til noon, quarter past one, etc.
  64. '''
  65. _specials = {
  66. 'noon': 'noon',
  67. 'midnight': 'midnight',
  68. 'til': 'til',
  69. 'past': 'past'
  70. }
  71. def __init__(self, h = None, m = None):
  72. self.time(h, m)
  73. def time(self, h = None, m = None):
  74. if h is not None:
  75. self._hour = abs(int(h))
  76. if m is not None:
  77. self._min = abs(int(m))
  78. return (h, m)
  79. def time_t(self, t = None):
  80. if t is None:
  81. t = time.localtime()
  82. self._hour = t.tm_hour
  83. self._min = t.tm_min
  84. def words(self):
  85. h = self._hour
  86. m = self._min
  87. if h > 23: return self._oor # OOR errors
  88. if m > 59: return self._oor
  89. sign = self._specials['past']
  90. if self._min > 30:
  91. sign = self._specials['til']
  92. h += 1
  93. m = 60 - m
  94. if h > 23: h -= 24
  95. elif h > 12: h -= 12
  96. # hword is the hours word)
  97. if h == 0: hword = self._specials['midnight']
  98. elif h == 12: hword = self._specials['noon']
  99. else: hword = self.numwords(h)
  100. if m == 0:
  101. if h in (0, 12): return hword # for noon and midnight
  102. else: return "{} {}".format(self.numwords(h), self._words['quarters'][m])
  103. if m % 15 == 0:
  104. return "{} {} {}".format(self._words['quarters'][m // 15], sign, hword)
  105. return "{} {} {}".format(self.numwords(m), sign, hword)
  106. def digits(self):
  107. 'return the traditionl time, e.g., 13:42'
  108. return f'{self._hour:02}:{self._min:02}'
  109. class saytime_t(saytime): # wrapper for saytime to use time object
  110. '''
  111. set the time from a time object
  112. '''
  113. def __init__(self, t = None):
  114. self.time_t()
  115. def main():
  116. if len(sys.argv) > 1:
  117. if sys.argv[1] == 'test':
  118. test()
  119. else:
  120. try: print(saytime(*(sys.argv[1].split(':'))).words())
  121. except TypeError: print('Invalid time ({})'.format(sys.argv[1]))
  122. else:
  123. print(saytime_t().words())
  124. def test():
  125. st = saytime()
  126. print('\nnumbers test:')
  127. list = (
  128. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 19, 20, 30,
  129. 50, 51, 52, 55, 59, 99, 100, 101, 112, 900, 999, 1000
  130. )
  131. for l in list:
  132. st.number(l)
  133. print(l, st.numwords())
  134. print('\ntime test:')
  135. list = (
  136. (0, 0), (0, 1), (11, 0), (12, 0), (13, 0), (12, 29), (12, 30),
  137. (12, 31), (12, 15), (12, 30), (12, 45), (11, 59), (23, 15),
  138. (23, 59), (12, 59), (13, 59), (1, 60), (24, 0)
  139. )
  140. for l in list:
  141. st.time(*l)
  142. print(st.digits(), st.words())
  143. st.time_t() # set time to now
  144. print('\nlocal time is ' + st.words())
  145. if __name__ == '__main__': main()