- Now tzfile() will unpickle to the updated file.
- Adding tzwin.py, contributed by Jeffrey Harris.
- Minor tweaks in setup.py.
- Adding README and example.py.
- Putting old scheduler.py in the sandbox.
diff --git a/sandbox/scheduler.py b/sandbox/scheduler.py
new file mode 100644
index 0000000..681f442
--- /dev/null
+++ b/sandbox/scheduler.py
@@ -0,0 +1,157 @@
+"""
+Copyright (c) 2003  Gustavo Niemeyer <niemeyer@conectiva.com>
+
+This module offers extensions to the standard python 2.3+
+datetime module.
+"""
+__author__ = "Gustavo Niemeyer <niemeyer@conectiva.com>"
+__license__ = "PSF License"
+
+import datetime
+import thread
+import signal
+import time
+
+class sched:
+
+    def __init__(self, rrule,
+                 tolerance=None, last=None,
+                 execute=None, args=None, kwargs=None):
+        self._rrule = rrule
+        if tolerance:
+            self._tolerance = datetime.timedelta(seconds=tolerance)
+        else:
+            self._tolerance = None
+        self._last = last
+        self._execute = execute
+        self._args = args or ()
+        self._kwargs = kwargs or {}
+
+    def last(self):
+        return self._last
+
+    def next(self, now=None):
+        if not now:
+            now = datetime.datetime.now()
+        return self._rrule.after(now)
+
+    def check(self, now=None, readonly=False):
+        if not now:
+            now = datetime.datetime.now()
+        item = self._rrule.before(now, inc=True)
+        if (item is None or item == self._last or
+            (self._tolerance and item+self._tolerance < now)):
+            return None
+        if not readonly:
+            self._last = item
+            if self._execute:
+                self._execute(*self._args, **self._kwargs)
+        return item
+
+
+class schedset:
+    def __init__(self):
+        self._scheds = []
+
+    def add(self, sched):
+        self._scheds.append(sched)
+
+    def next(self, now=None):
+        if not now:
+            now = datetime.datetime.now()
+        res = None
+        for sched in self._scheds:
+            next = sched.next(now)
+            if next and (not res or next < res):
+                res = next
+        return res
+
+    def check(self, now=None, readonly=False):
+        if not now:
+            now = datetime.datetime.now()
+        res = False
+        for sched in self._scheds:
+            if sched.check(now, readonly):
+                res = True
+        return res
+
+
+class schedthread:
+    
+    def __init__(self, sched, lock=None):
+        self._sched = sched
+        self._lock = lock
+        self._running = False
+
+    def running(self):
+        return self._running
+
+    def run(self):
+        self._running = True
+        thread.start_new_thread(self._loop, ())
+        
+    def stop(self):
+        self._running = False
+
+    def _loop(self):
+        while self._running:
+            if self._lock:
+                self._lock.acquire()
+            now = datetime.datetime.now()
+            self._sched.check(now)
+            if self._lock:
+                self._lock.release()
+            seconds = _seconds_left(self._sched.next(now))
+            if seconds is None:
+                self._running = False
+                break
+            if self._running:
+                time.sleep(seconds)
+
+
+class schedalarm:
+    
+    def __init__(self, sched, lock=None):
+        self._sched = sched
+        self._lock = lock
+        self._running = False
+
+    def running(self):
+        return self._running
+
+    def run(self):
+        self._running = True
+        signal.signal(signal.SIGALRM, self._handler)
+        self._handler(None, None)
+        
+    def stop(self):
+        self._running = False
+
+    def _handler(self, sig, frame):
+        while self._running:
+            if self._lock:
+                self._lock.acquire()
+            now = datetime.datetime.now()
+            self._sched.check(now)
+            if self._lock:
+                self._lock.release()
+            if self._running:
+                seconds = _seconds_left(self._sched.next(now))
+                if seconds:
+                    signal.alarm(seconds)
+                    break
+                elif seconds is None:
+                    self._running = False
+                    break
+
+
+def _seconds_left(next):
+    if not next:
+        return None
+    now = datetime.datetime.now()
+    delta = next-now
+    seconds = delta.days*86400+delta.seconds
+    if seconds < 0:
+        seconds = 0
+    return seconds
+