Websocket server implementing a clock handling alarms and timezones
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

clock.py 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import datetime
  2. import dateutil
  3. import dateutil.tz
  4. from .errors import AlarmNameError
  5. from .session import Session
  6. from .clock_alarm import ClockAlarm
  7. class Clock(object):
  8. """ Represents a timezone aware clock with programmable alarms """
  9. def __init__(self, session_id=None, tzname:str='UTC'):
  10. """ Instanciate a new clock
  11. @param tzname : the name of the timezone (UTC for UTC)
  12. """
  13. self.__session = Session.get(session_id)
  14. if 'tzname' in self.__session:
  15. tzname = self.__session['tzname']
  16. else:
  17. self.__session['tzname'] = tzname
  18. self.__tzname = tzname
  19. self.__tz = None
  20. if 'alarms' not in self.__session:
  21. self.__session['alarms'] = dict()
  22. self.alarms = self.__session['alarms'] # updated by reference
  23. self.set_tz(self.__tzname)
  24. @property
  25. def tz(self) -> datetime.tzinfo:
  26. """ Returns the clock tzinfo """
  27. return self.__tz
  28. @property
  29. def tzname(self) -> str:
  30. """ Returns the clock timezone name """
  31. tzn1 = datetime.datetime.now(tz=self.__tz).tzname()
  32. tzn2 = self.__tzname
  33. return tzn1 if tzn1 == tzn2 else '%s(%s)' % (tzn2, tzn1)
  34. @property
  35. def utcoffset(self) -> int:
  36. """ Returns utcoffset in seconds """
  37. return datetime.datetime.now(tz=self.__tz).utcoffset()
  38. @property
  39. def session_id(self) -> str:
  40. """ Returns the sesison id """
  41. return self.__session.session_id
  42. def now(self) -> datetime.datetime:
  43. """ Return the clock localtime """
  44. self.__session.tick()
  45. now_dt = datetime.datetime.now(tz=self.__tz).replace(microsecond=0)
  46. for alrm in self.alarms.values():
  47. alrm.is_ringing()
  48. return now_dt
  49. def set_tz(self, tzname:str) -> bool:
  50. """ Set the clock timezone from dateutil.tz.gettz
  51. @param tzname : the name of the timezone (UTC for UTC)
  52. @return True if timezone found else False
  53. """
  54. newtz = dateutil.tz.gettz(tzname)
  55. if newtz is None:
  56. return False
  57. self.__tzname = tzname
  58. self.__tz = dateutil.tz.gettz(tzname)
  59. self.__session['tzname'] = self.__tzname
  60. return True
  61. def alarm_add(self, name:str) -> None:
  62. """ Add an alarm to the clock
  63. @param name : alarm name,must be unique
  64. @throws AlarmNameError if name is not unique or empty
  65. """
  66. if name in self.alarms:
  67. raise AlarmNameError('There is allready an alarm %r' % name)
  68. self.alarms[name] = ClockAlarm()
  69. def alarm_del(self, name:str) -> None:
  70. """ Delete an alarm from the clock
  71. @param name : the alarm name
  72. @throws AlarmNameError if alarm not found
  73. """
  74. if name not in self.alarms:
  75. raise AlarmNameError('There is no alarm %r' % name)
  76. del self.alarms[name]
  77. def alarm_get(self, name:str) -> None:
  78. """ Return an alarm given its name
  79. @param name : the alarm name
  80. @throws AlarmNameError if alarm not found
  81. """
  82. if name not in self.alarms:
  83. raise AlarmNameError('There is no alarm %r' % name)
  84. return self.alarms[name]
  85. def alarm_rings(self) -> list:
  86. """ Return ringing alarm's names
  87. @return a list of strings
  88. """
  89. return [name for name, alrm in self.alarms.items()
  90. if alrm.is_ringing()]
  91. def alarm_snooze(self, minutes:float=15) -> None:
  92. """ Snooze all ringing alarms
  93. @param minutes : snooze for this amount of minutes
  94. """
  95. for name in self.alarm_rings():
  96. self.alarms[name].snooze(minutes)