diff --git a/da/tools/general.py b/da/tools/general.py
index 2d5363ea3cea4d7bdf7fb15a7c32d2f360e205bb..1167cab04af45474af9a50eeddbf879c322c8295 100755
--- a/da/tools/general.py
+++ b/da/tools/general.py
@@ -17,6 +17,22 @@ import shutil
 import datetime
 import re
 
+from dateutil.rrule import rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY, \
+     MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY
+
+HOURS_PER_DAY = 24.
+MINUTES_PER_DAY  = 60.*HOURS_PER_DAY
+SECONDS_PER_DAY =  60.*MINUTES_PER_DAY
+MUSECONDS_PER_DAY = 1e6*SECONDS_PER_DAY
+SEC_PER_MIN = 60
+SEC_PER_HOUR = 3600
+SEC_PER_DAY = SEC_PER_HOUR * 24
+SEC_PER_WEEK = SEC_PER_DAY * 7
+MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY = (
+    MO, TU, WE, TH, FR, SA, SU)
+WEEKDAYS = (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY)
+
+
 def validate_rc(rcfile, needed_items):
     """ validate the contents of an rc-file given a dictionary of required keys """
 
@@ -165,5 +181,86 @@ def name_convert(name=None, to=None):
             return ""
         return "%s_%s-%s_%d" % (code, platform[0], strategy[0], lab_num)
 
+def _to_ordinalf(dt):
+    """
+    Convert :mod:`datetime` to the Gregorian date as UTC float days,
+    preserving hours, minutes, seconds and microseconds.  Return value
+    is a :func:`float`.
+    """
+
+    if hasattr(dt, 'tzinfo') and dt.tzinfo is not None:
+        delta = dt.tzinfo.utcoffset(dt)
+        if delta is not None:
+            dt -= delta
+
+    base =  float(dt.toordinal())
+    if hasattr(dt, 'hour'):
+        base += (dt.hour/HOURS_PER_DAY + dt.minute/MINUTES_PER_DAY +
+                 dt.second/SECONDS_PER_DAY + dt.microsecond/MUSECONDS_PER_DAY
+                 )
+    return base
+
+def _from_ordinalf(x, tz=None):
+    """
+    Convert Gregorian float of the date, preserving hours, minutes,
+    seconds and microseconds.  Return value is a :class:`datetime`.
+    """
+    if tz is None: tz = _get_rc_timezone()
+    ix = int(x)
+    dt = datetime.datetime.fromordinal(ix)
+    remainder = float(x) - ix
+    hour, remainder = divmod(24*remainder, 1)
+    minute, remainder = divmod(60*remainder, 1)
+    second, remainder = divmod(60*remainder, 1)
+    microsecond = int(1e6*remainder)
+    if microsecond<10: microsecond=0 # compensate for rounding errors
+    dt = datetime.datetime(
+        dt.year, dt.month, dt.day, int(hour), int(minute), int(second),
+        microsecond, tzinfo=UTC).astimezone(tz)
+
+    if microsecond>999990:  # compensate for rounding errors
+        dt += datetime.timedelta(microseconds=1e6-microsecond)
+
+    return dt
+
+def date2num(d):
+    """
+    *d* is either a :class:`datetime` instance or a sequence of datetimes.
+
+    Return value is a floating point number (or sequence of floats)
+    which gives the number of days (fraction part represents hours,
+    minutes, seconds) since 0001-01-01 00:00:00 UTC, *plus* *one*.
+    The addition of one here is a historical artifact.  Also, note
+    that the Gregorian calendar is assumed; this is not universal
+    practice.  For details, see the module docstring.
+    """
+    try: 
+	return np.asarray([_to_ordinalf(val) for val in d])
+    except:
+        return _to_ordinalf(d)
+
+
+def num2date(x, tz=None):
+    """
+    *x* is a float value which gives the number of days
+    (fraction part represents hours, minutes, seconds) since
+    0001-01-01 00:00:00 UTC *plus* *one*.
+    The addition of one here is a historical artifact.  Also, note
+    that the Gregorian calendar is assumed; this is not universal
+    practice.  For details, see the module docstring.
+
+    Return value is a :class:`datetime` instance in timezone *tz* (default to
+    rcparams TZ value).
+
+    If *x* is a sequence, a sequence of :class:`datetime` objects will
+    be returned.
+    """
+    if tz is None: tz = _get_rc_timezone()
+    try: 
+        return [_from_ordinalf(val, tz) for val in x]
+    except:
+        return _from_ordinalf(x, tz)
+
+
 if __name__ == "__main__":
     pass