channelping coming up to twenty-five past two in the morning

ProseClock an alternative to digital and analog time displays

#!/usr/local/bin/lua
-- ---------------------------------------------------------------------
--                                                                     -
-- ProseClock: an alternative to digital and analog formats            -
--                                                                     -
-- Copyright (c) 2006-Eternity Gerald Gold and channelping. All rights -
-- reserved. This class is free software; you may redistribute it      -
-- and/or modify it under the same terms as Lua itself.                -
--                                                                     -
-- USAGE:                                                              -
--                                                                     -
--   require('ProseClock')                                             -
--   pc = ProseClock:new()                                             -
--   print(pc:GetTime())                                               -
--                                                                     -
-- ---------------------------------------------------------------------

-- create class
ProseClock = {}

-- constructor
function ProseClock:new()

   setmetatable({}, self)
   self.__index = self

   -- initialize
   self:_set_phrases()

   return self
end

function ProseClock:GetTime()

   self:_get_time()
   self:_set_minute()
   self:_set_hour()

   -- assemble the text phrase
   local txt = self.min_phrase ..
      ' ' .. self.mul_phrase ..
      ' ' .. self.hour_phrase

   -- mul_phrase may be empty string, in which case there
   -- would be two consecutive spaces
   txt = string.gsub(txt, '%s+', ' ')

   return txt
end

function ProseClock:_set_hour()

   local hours = self.time.hours

   if self.mul >= 35 then
      if hours == 23 then
         hours = 0
      else
         hours = hours + 1
      end
   end

   -- In Lua, the index for the first array element is 1, not 0.
   -- That's why we add 1 to the index value
   self.hour_phrase = self.HourPhrases[hours + 1]

   if hours == 0 and self.time.minutes < 3 then
      self.mul_phrase = ''
   end

   return
end

function ProseClock:_set_minute()

   local minutes = self.time.minutes

   -- local remainder = minutes % 5 -- okay in Lua 5.1
   local remainder = math.mod(minutes, 5)

   self.mul = minutes - remainder

   -- switch frame of reference
   if remainder >= 3 then
      self.mul = self.mul + 5
   end

   -- In Lua, the index for the first array element is 1, not 0.
   -- That's why we add 1 to the index value
   self.min_phrase = self.MinutePhrases[remainder + 1]

   if self.Multiples[tostring(self.mul)] == nil then
      self.mul_phrase = ''
   else
      self.mul_phrase = self.Multiples[tostring(self.mul)]
   end

   return
end

function ProseClock:_get_time()
   local tm = os.date("*t")
   self.time = {}
   self.time.hours   = tm.hour
   self.time.minutes = tm.min
   return
end

function ProseClock:_set_phrases()

   self.MinutePhrases = {
      'exactly',
      'just after',
      'a little after',
      'coming up to',
      'almost',
   };

   -- Assignment of k/v pairs in this Lua dictionary
   -- requires the [] syntax because the keys are integers
   -- which are not conventionally indexed.
   self.Multiples = {
      ['0']  = '',
      ['5']  = 'five past',
      ['10'] = 'ten past',
      ['15'] = 'quarter past',
      ['20'] = 'twenty past',
      ['25'] = 'twenty-five past',
      ['30'] = 'half past',
      ['35'] = 'twenty-five to',
      ['40'] = 'twenty to',
      ['45'] = 'quarter to',
      ['50'] = 'ten to',
      ['55'] = 'five to',
   };

   self.HourPhrases = {
      'midnight',
      'one in the morning',
      'two in the morning',
      'three in the morning',
      'four in the morning',
      'five in the morning',
      'six in the morning',
      'seven in the morning',
      'eight in the morning',
      'nine in the morning',
      'ten in the morning',
      'eleven in the morning',
      'noon',
      'one in the afternoon',
      'two in the afternoon',
      'three in the afternoon',
      'four in the afternoon',
      'five in the afternoon',
      'six at night',
      'seven at night',
      'eight at night',
      'nine at night',
      'ten at night',
      'eleven at night',
   };

   return;
end

^