import math import os import select import sys try: import thread except: import dummy_thread as thread from ctypes import * import ctypes.util __doc__ = """This module provides various functions to manipulate time values. There are two standard representations of time. One is the number of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer or a floating point number (to represent fractions of seconds). The Epoch is system-defined; on Unix, it is generally January 1st, 1970. The actual value can be retrieved by calling gmtime(0). The other representation is a tuple of 9 integers giving local time. The tuple items are: year (four digits, e.g. 1998) month (1-12) day (1-31) hours (0-23) minutes (0-59) seconds (0-59) weekday (0-6, Monday is 0) Julian day (day in the year, 1-366) DST (Daylight Savings Time) flag (-1, 0 or 1) If the DST flag is 0, the time is given in the regular time zone; if it is 1, the time is given in the DST time zone; if it is -1, mktime() should guess based on the date and time. Variables: timezone -- difference in seconds between UTC and local standard time altzone -- difference in seconds between UTC and local DST time daylight -- whether local time should reflect DST tzname -- tuple of (standard time zone name, DST time zone name) Functions: time() -- return current time in seconds since the Epoch as a float clock() -- return CPU time since process start as a float sleep() -- delay for a number of seconds given as a float gmtime() -- convert seconds since Epoch to UTC tuple localtime() -- convert seconds since Epoch to local time tuple asctime() -- convert time tuple to string ctime() -- convert time in seconds to string mktime() -- convert local time tuple to seconds since Epoch strftime() -- convert time tuple to string according to format specification strptime() -- parse string to time tuple according to format specification tzset() -- change the local timezone""" _POSIX = os.name == "posix" _MS_WINDOWS = os.name == "nt" _FREEBSD = "freebsd" in sys.platform if _POSIX: _libc = cdll.LoadLibrary(ctypes.util.find_library("c")) elif _MS_WINDOWS: from ctypes import wintypes _libc = None class _timeval(Structure): _fields_ = [("tv_sec", c_long), ("tv_usec", c_long)] class _timeb(Structure): _fields_ = [("time", c_long), ("millitm", c_ushort), ("timezone", c_short), ("dstflag", c_short)] class _tm(Structure): _fields_ = [("tm_sec", c_int), ("tm_min", c_int), ("tm_hour", c_int), ("tm_mday", c_int), ("tm_mon", c_int), ("tm_year", c_int), ("tm_wday", c_int), ("tm_yday", c_int), ("tm_isdst", c_int), ("tm_gmtoff", c_long), ("tm_zone", c_char_p)] class _tzname_t(Structure): _fields_ = [("tzname_0", c_char_p), ("tzname_1", c_char_p)] class struct_time(object): def __init__(self, tup): if tup and len(tup) < 9: raise TypeError,\ "time.struct_time() takes a 9-sequence" if not tup: raise TypeError, "structseq() takes at least 1 argument (0 given)" self._tup = tup self.tm_year = self._tup[0] self.tm_mon = self._tup[1] self.tm_mday = self._tup[2] self.tm_hour = self._tup[3] self.tm_min = self._tup[4] self.tm_sec = self._tup[5] self.tm_wday = self._tup[6] self.tm_yday = self._tup[7] self.tm_isdst = self._tup[8] def __repr__(self): return "(%d, %d, %d, %d, %d, %d, %d, %d, %d)" %\ (self.tm_year, self.tm_mon, self.tm_mday, self.tm_hour, self.tm_min, self.tm_sec, self.tm_wday, self.tm_yday, self.tm_isdst) def __len__(self): return 9 def __getitem__(self, key): if not isinstance(key, (int, slice)): raise TypeError, "sequence index must be integer" return self._tup[key] def __cmp__(self, other): if isinstance(other, struct_time): return cmp(self._tup, other._tup) return cmp(self._tup, other) timezone = daylight = tzname = altzone = accept2dyear = None def _inittime(): global accept2dyear # accept 2-digit dates unless PYTHONY2K is set and non-empty accept2dyear = (1, 0)[bool(os.getenv("PYTHONY2K"))] _inittimezone() def _inittimezone(): global timezone, daylight, tzname, altzone if _MS_WINDOWS: cdll.msvcrt._tzset() timezone = c_long.in_dll(cdll.msvcrt, "_timezone").value if hasattr(cdll.msvcrt, "altzone"): altzone = c_long.in_dll(cdll.msvcrt, "altzone").value else: altzone = timezone - 3600 daylight = c_long.in_dll(cdll.msvcrt, "_daylight").value tzname = _tzname_t.in_dll(cdll.msvcrt, "_tzname") tzname = (tzname.tzname_0, tzname.tzname_1) else: YEAR = (365 * 24 + 6) * 3600 _libc.time.argtypes = [c_void_p] t = (((_libc.time(byref(c_long(0)))) / YEAR) * YEAR) _libc.localtime.argtypes = [c_void_p] _libc.localtime.restype = POINTER(_tm) t = c_long(t) p = _libc.localtime(byref(t)).contents janzone = -p.tm_gmtoff janname = (" ", p.tm_zone)[bool(p.tm_zone)] t = c_int(t.value + YEAR / 2) p = _libc.localtime(byref(t)).contents julyzone = -p.tm_gmtoff julyname = (" ", p.tm_zone)[bool(p.tm_zone)] if janzone < julyzone: # DST is reversed in the southern hemisphere timezone = julyzone altzone = janzone daylight = int(janzone != julyzone) tzname = (julyname, janname) else: timezone = janzone altzone = julyzone daylight = int(janzone != julyzone) tzname = (janname, julyname) def _floattime(): """ _floattime() -> computes time since the Epoch for various platforms. Since on some system gettimeofday may fail we fall back on ftime or time. gettimeofday() has a resolution in microseconds ftime() has a resolution in milliseconds and it never fails time() has a resolution in seconds """ if _MS_WINDOWS: return cdll.msvcrt.time(None) if hasattr(_libc, "gettimeofday"): t = _timeval() _libc.gettimeofday.argtypes = [c_void_p, c_void_p] if _libc.gettimeofday(byref(t), None) == 0: return float(t.tv_sec) + t.tv_usec * 0.000001 elif hasattr(_libc, "ftime"): t = _timeb() _libc.ftime.argtypes = [c_void_p] _libc.ftime(byref(t)) return float(t.time) + float(t.millitm) * 0.001 elif hasattr(_libc, "time"): t = c_long() _libc.time.argtypes = [c_void_p] _libc.time(byref(t)) return t.value def _floatsleep(secs): lock = thread.allocate_lock() # it seems only watcom has delay (uses milliseconds) if hasattr(_libc, "delay"): lock.acquire() _libc.delay.argtypes = [c_int] _libc.delay(int(secs * 1000 + 0.5)) lock.release() return if _POSIX: select.select([], [], [], secs) return elif _MS_WINDOWS: msecs = secs * 1000.0 if msecs > float(sys.maxint * 2 - 1): # ULONG_MAX raise OverflowError, "sleep length is too large" lock.acquire() ul_millis = c_ulong(long(msecs)) windll.kernel32.Sleep(ul_millis) lock.release() else: lock.acquire() _libc.sleep.argtypes = [c_int] _libc.sleep(int(secs)) lock.release() def _check_float(arg): try: float(arg) except ValueError: raise TypeError, "a float is required" def _time_convert(seconds, func): whent = c_long(long(seconds)) p = c_void_p() func.restype = POINTER(_tm) func.argtypes = [c_void_p] p = func(byref(whent)) if not p or p.contents == None: raise ValueError, _get_error_msg() return _tm_to_tuple(p.contents) def _tm_to_tuple(t): time_tuple = [] time_tuple.append(t.tm_year + 1900) time_tuple.append(t.tm_mon + 1) # want january == 1 time_tuple.append(t.tm_mday) time_tuple.append(t.tm_hour) time_tuple.append(t.tm_min) time_tuple.append(t.tm_sec) time_tuple.append((t.tm_wday + 6) % 7) # want monday == 0 time_tuple.append(t.tm_yday + 1) # want january, 1 == 1 time_tuple.append(t.tm_isdst) return struct_time(tuple(time_tuple)) def _get_time(func_name, seconds): if seconds == None: seconds = _floattime() else: _check_float(seconds) if _MS_WINDOWS: mod = cdll.msvcrt else: mod = _libc func = getattr(mod, func_name) return _time_convert(seconds, func) def _gettmarg(tup, buf): y = tup[0] buf.tm_mon = tup[1] buf.tm_mday = tup[2] buf.tm_hour = tup[3] buf.tm_min = tup[4] buf.tm_sec = tup[5] buf.tm_wday = tup[6] buf.tm_yday = tup[7] buf.tm_isdst = tup[8] if y < 1900: if not accept2dyear: raise ValueError, "year >= 1900 required" if 69 <= y <= 99: y += 1900 elif 0 <= y <= 68: y += 2000 else: raise ValueError, "year out of range" buf.tm_year = y - 1900 buf.tm_mon = buf.tm_mon - 1 buf.tm_wday = int(math.fmod((buf.tm_wday + 1), 7)) buf.tm_yday = buf.tm_yday - 1 return buf def _get_error_msg(): errno = c_int.in_dll(_libc, "errno") _libc.strerror.restype = c_char_p msg = _libc.strerror(errno) return msg def time(): """time() -> floating point number Return the current time in seconds since the Epoch. Fractions of a second may be present if the system clock provides them.""" secs = _floattime() if secs == 0.0: raise IOError, _get_error_msg() return float(secs) def sleep(seconds): """sleep(seconds) Delay execution for a given number of seconds. The argument may be a floating point number for subsecond precision.""" _check_float(seconds) _floatsleep(seconds) def clock(): """clock() -> floating point number Return the CPU time or real time since the start of the process or since the first call to clock(). This has as much precision as the system records.""" if _POSIX: if _FREEBSD: CLOCKS_PER_SEC = 128 else: CLOCKS_PER_SEC = 1000000 return float(float(_libc.clock()) / CLOCKS_PER_SEC) elif _MS_WINDOWS: divisor = 0.0 ctrStart = wintypes.LARGE_INTEGER() now = wintypes.LARGE_INTEGER() if divisor == 0.0: freq = wintypes.LARGE_INTEGER() windll.kernel32.QueryPerformanceCounter(byref(ctrStart)) res = windll.kernel32.QueryPerformanceCounter(byref(freq)) if not res or not freq: return float(windll.msvcrt.clock()) divisor = float(freq.value) windll.kernel32.QueryPerformanceCounter(byref(now)) diff = float(now.value - ctrStart.value) return float(diff / divisor) def ctime(seconds=None): """ctime(seconds) -> string Convert a time in seconds since the Epoch to a string in local time. This is equivalent to asctime(localtime(seconds)). When the time tuple is not present, current time as returned by localtime() is used.""" if seconds == None: seconds = _floattime() else: _check_float(seconds) tt = c_long(long(seconds)) p = c_char_p() if _MS_WINDOWS: _ctime = getattr(cdll.msvcrt, "ctime") else: _ctime = getattr(_libc, "ctime") _ctime.argtypes = [c_void_p] _ctime.restype = c_char_p p = _ctime(byref(tt)) if not p: raise ValueError, "unconvertible time" return p[:-1] # get rid of new line def gmtime(seconds=None): """gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a. GMT). When 'seconds' is not passed in, convert the current time instead.""" return _get_time("gmtime", seconds) def localtime(seconds=None): """localtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) Convert seconds since the Epoch to a time tuple expressing local time. When 'seconds' is not passed in, convert the current time instead.""" return _get_time("localtime", seconds) def mktime(tup): """mktime(tuple) -> floating point number Convert a time tuple in local time to seconds since the Epoch.""" if tup == None: raise TypeError, "argument must be 9-item sequence not None" if 1 < len(tup) < 9: raise TypeError,\ "argument must be a sequence of length 9, not %d" % len(tup) if _MS_WINDOWS: time = getattr(cdll.msvcrt, "time") localtime = getattr(cdll.msvcrt, "localtime") mktime = getattr(cdll.msvcrt, "mktime") else: time = getattr(_libc, "time") localtime = getattr(_libc, "localtime") mktime = getattr(_libc, "mktime") tt = c_long() time.argtypes = [c_void_p] tt = time(byref(tt)) localtime.argtypes = [c_void_p] localtime.restype = POINTER(_tm) tt = c_long(tt) buf = localtime(byref(tt)).contents buf = _gettmarg(tup, buf) mktime.argtypes = [POINTER(_tm)] tt = mktime(byref(buf)) if tt == -1: raise OverflowError, "mktime argument out of range" return float(tt) def asctime(*tup): """asctime([tuple]) -> string Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'. When the time tuple is not present, current time as returned by localtime() is used.""" try: tup_len = len(*tup) except: tup_len = 9 if len(tup) == 1 and tup[0] == None: raise TypeError, "argument must be 9-item sequence not None" if 1 < tup_len < 9: raise TypeError,\ "argument must be a sequence of length 9, not %d" % tup_len buf = None if _MS_WINDOWS: time = getattr(cdll.msvcrt, "time") localtime = getattr(cdll.msvcrt, "localtime") asctime = getattr(cdll.msvcrt, "asctime") else: time = getattr(_libc, "time") localtime = getattr(_libc, "localtime") asctime = getattr(_libc, "asctime") if not tup: time.argtypes = [c_void_p] tt = time(None) localtime.argtypes = [c_void_p] localtime.restype = POINTER(_tm) tt = c_long(tt) buf = localtime(byref(tt)).contents if len(tup) != 0: if not buf: buf = _tm() buf = _gettmarg(tup[0], buf) asctime.argtypes = [POINTER(_tm)] asctime.restype = c_char_p p = asctime(byref(buf)) return p[:-1] # get rid of new line if _POSIX: def tzset(): """tzset() Initialize, or reinitialize, the local timezone to the value stored in os.environ['TZ']. The TZ environment variable should be specified in standard Unix timezone format as documented in the tzset man page (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently fall back to UTC. If the TZ environment variable is not set, the local timezone is set to the systems best guess of wallclock time. Changing the TZ environment variable without calling tzset *may* change the local timezone used by methods such as localtime, but this behaviour should not be relied on""" _libc.tzset() # reset timezone, altzone, daylight and tzname _inittimezone() def strftime(format, *tup): """strftime(format[, tuple]) -> string Convert a time tuple to a string according to a format specification. See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.""" if not isinstance(format, str): raise TypeError, "strftime() argument 1 must be string" try: tup_len = len(*tup) except: tup_len = 9 if len(tup) == 1 and tup[0] == None: raise TypeError, "argument must be 9-item sequence not None" if 1 < tup_len < 9: raise TypeError,\ "argument must be a sequence of length 9, not %d" % tup_len buf = None if _MS_WINDOWS: time = getattr(cdll.msvcrt, "time") localtime = getattr(cdll.msvcrt, "localtime") strftime = getattr(cdll.msvcrt, "strftime") else: time = getattr(_libc, "time") localtime = getattr(_libc, "localtime") strftime = getattr(_libc, "strftime") if not tup: time.argtypes = [c_void_p] tt = time(None) localtime.argtypes = [c_void_p] localtime.restype = POINTER(_tm) tt = c_long(tt) buf = localtime(byref(tt)).contents if len(tup) != 0: if not buf: buf = _tm() buf = _gettmarg(tup[0], buf) # Checks added to make sure strftime() does not crash Python by # indexing blindly into some array for a textual representation # by some bad index (fixes bug #897625). # No check for year since handled in gettmarg(). if buf.tm_mon < 0 or buf.tm_mon > 11: raise ValueError, "month out of range" if buf.tm_mday < 1 or buf.tm_mday > 31: raise ValueError, "day of month out of range" if buf.tm_hour < 0 or buf.tm_hour > 23: raise ValueError, "hour out of range" if buf.tm_min < 0 or buf.tm_min > 59: raise ValueError, "minute out of range" if buf.tm_sec < 0 or buf.tm_sec > 61: raise ValueError, "seconds out of range" # tm_wday does not need checking of its upper-bound since taking # "% 7" in gettmarg() automatically restricts the range. if buf.tm_wday < 0: raise ValueError, "day of week out of range" if buf.tm_yday < 0 or buf.tm_yday > 365: raise ValueError, "day of year out of range" if buf.tm_isdst < -1 or buf.tm_isdst > 1: raise ValueError, "daylight savings flag out of range" i = 1024 while True: outbuf = create_string_buffer(i) buflen = strftime(outbuf, i, format, byref(buf)) if buflen > 0 or i >= 256 * len(format): # if the buffer is 256 times as long as the format, # it's probably not failing for lack of room! # More likely, the format yields an empty result, # e.g. an empty format, or %Z when the timezone # is unknown. return outbuf.value[:buflen] i += i def strptime(string, format="%a %b %d %H:%M:%S %Y"): """strptime(string, format) -> struct_time Parse a string to a time tuple according to a format specification. See the library reference manual for formatting codes (same as strftime()).""" import _strptime return _strptime.strptime(string, format) _inittime() __all__ = ["time", "sleep", "clock", "accept2dyear", "ctime", "gmtime", "localtime", "mktime", "asctime", "timezone", "daylight", "tzname", "altzone", "struct_time", "tzset", "strftime", "strptime"] if __name__ == "__main__": print "time():", time() print "sleeping...", sleep(1.2345) print "slept" print "clock():", clock() print "accept2dyear:", accept2dyear print "ctime():", ctime() print "gmtime():", gmtime() print "localtime():", localtime() print "mktime(localtime()):", mktime(localtime()) print "asctime(localtime()):", asctime(localtime()) print "timezone:", timezone print "daylight:", daylight print "tzname:", tzname print "altzone:", altzone try: tzset() except: pass print "strftime(%a, %d %b %Y %H:%M:%S):",\ strftime("%a, %d %b %Y %H:%M:%S") print "strptime(ctime()):", strptime(ctime())