time是与时间相关的模块,该模块提供了time,clock,sleep之类的脚本函数(或者叫做方法)。其中,time方法对应的C函数为time_time,clock方法对应的C函数为time_clock,以此类推。下面就对time模块提供的这些方法一一进行介绍...

    页面导航: 英文教程的下载地址:

    本篇文章是根据英文教程《Python Tutorial》来写的学习笔记。该英文教程的下载地址如下:

    百度盘地址:http://pan.baidu.com/s/1c0eXSQG

    DropBox地址:点此进入DropBox链接

    Google Drive:点此进入Google Drive链接

    这是学习笔记,不是翻译,因此,内容上会与英文原著有些不同。以下记录是根据英文教程的第十三章来写的。(文章中的部分链接,包括下载链接,可能需要通过代理访问!)

    本篇文章也会涉及到Python的C源代码,这些C源码都是2.7.8版本的。想使用gdb来调试python源代码的话,就需要按照前面"Python基本的操作运算符"文章中所说的,使用configure --with-pydebug命令来重新编译安装python。

    如果Python的官方网站取消了Python-2.7.8.tgz的源码包的话,可以在以下两个链接中下载到:

    DropBox:Python-2.7.8.tgz的DropBox网盘链接

    Google Drive:Python-2.7.8.tgz的Google Drive网盘链接

    文章里棕色的注释是作者额外添加的,在源码里并没有。本篇文章的例子主要是针对Linux系统下Python 2.7.8版本的。

time模块:

    time是与时间相关的模块,该模块的源码定义在C文件中:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> time
<module 'time' from '/usr/local/lib/python2.7/lib-dynload/time.so'>
>>> quit()
[email protected]:~$ cd /mnt/zenglOX/Python-2.7.8
[email protected]:/mnt/zenglOX/Python-2.7.8$ ls Modules/timemodule.c 
Modules/timemodule.c
[email protected]:/mnt/zenglOX/Python-2.7.8$ 


    当用import关键字引入time模块时,Python会自动去加载time.so的动态库文件,该库文件对应的C源码定义在Modules/timemodule.c文件里。timemodule.c文件中有一个time_methods数组,从该数组中就可以看到time模块对外提供的脚本函数:

static PyMethodDef time_methods[] = {
    {"time",            time_time, METH_NOARGS, time_doc},
#ifdef HAVE_CLOCK
    {"clock",           time_clock, METH_NOARGS, clock_doc},
#endif
    {"sleep",           time_sleep, METH_VARARGS, sleep_doc},
    {"gmtime",          time_gmtime, METH_VARARGS, gmtime_doc},
    {"localtime",       time_localtime, METH_VARARGS, localtime_doc},
    {"asctime",         time_asctime, METH_VARARGS, asctime_doc},
    {"ctime",           time_ctime, METH_VARARGS, ctime_doc},
#ifdef HAVE_MKTIME
    {"mktime",          time_mktime, METH_O, mktime_doc},
#endif
#ifdef HAVE_STRFTIME
    {"strftime",        time_strftime, METH_VARARGS, strftime_doc},
#endif
    {"strptime",        time_strptime, METH_VARARGS, strptime_doc},
#ifdef HAVE_WORKING_TZSET
    {"tzset",           time_tzset, METH_NOARGS, tzset_doc},
#endif
    {NULL,              NULL}           /* sentinel */
};


    可以看到,time模块提供了timeclocksleep之类的脚本函数(或者叫做方法)。其中,time方法对应的C函数为time_timeclock方法对应的C函数为time_clock,以此类推。

    从上面的代码里可以看到,只有在定义了HAVE_WORKING_TZSET宏的情况下(也就是只有当系统支持tzset时),time模块才会存在tzset方法。

    Linux或者Unix系统下,tzset可以正常工作,因此在这些系统里time模块存在tzset方法。

    但是,在windows环境下,tzset无法正常工作,由于系统不支持此方法,因此,windows环境下,time模块就不存在tzset方法了。

    下面就对time模块提供的这些方法一一进行介绍。

time方法:

    time方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> t = time.time()
>>> t
1440817406.098545
>>> time.localtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=29, tm_hour=11, tm_min=3, tm_sec=26, tm_wday=5, tm_yday=241, tm_isdst=0)
>>> time.localtime(0)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=8, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
>>> time.gmtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=29, tm_hour=3, tm_min=3, tm_sec=26, tm_wday=5, tm_yday=241, tm_isdst=0)
>>> time.gmtime(0)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
>>> time.time()
....................................................

Breakpoint 1, time_time (self=0x0, unused=0x0)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:131
131	    secs = floattime();
(gdb) n
132	    if (secs == 0.0) {
(gdb) p secs
$1 = 1440817877.400234
(gdb) c
Continuing.
1440817877.400234
>>> 


    time方法返回的是Unix时间戳,该时间戳是当前时间距离Epoch时间的秒数。

    Epoch是Unix系统的起始时间点。Epoch在UTC时区的时间为1970年1月1日 00:00:00(从上面的time.gmtime(0)脚本的执行结果里就可以看到这个时间),它在作者所在的UTC+8时区的时间则为1970年1月1日 08:00:00。

    因此,time方法所返回的时间戳在UTC时区,是距离1970年1月1日 00:00:00的秒数。而在UTC+8时区,则是距离1970年1月1日 08:00:00的秒数,如下图所示:


图1

    time方法返回的秒数,在Linux系统里的时钟精度为微秒,如上图的1440817406.098545里的.098545就表示98545微秒。在其他系统里,有的精度为毫秒,有的精度则为秒。具体的精度,是与time方法会调用的底层C库函数相关的。

    从前面的例子中可以看到,time方法在执行时,内部会调用的底层C函数为time_time,该函数定义在Modules/timemodule.c文件里:

static PyObject *
time_time(PyObject *self, PyObject *unused)
{
    double secs;
    // 通过下面的floattime函数
    // 来返回具体的秒数。
    secs = floattime();
    if (secs == 0.0) {
        PyErr_SetFromErrno(PyExc_IOError);
        return NULL;
    }
    return PyFloat_FromDouble(secs);
}

....................................................

/* Implement floattime() for various platforms */

// floattime会根据不同的系统平台,
// 调用不同的C库函数,以获取对应的时间戳。
static double
floattime(void)
{
    /* There are three ways to get the time:
      (1) gettimeofday() -- resolution in microseconds
      (2) ftime() -- resolution in milliseconds
      (3) time() -- resolution in seconds
      In all cases the return value is a float in seconds.
      Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
      fail, so we fall back on ftime() or time().
      Note: clock resolution does not imply clock accuracy! */
#ifdef HAVE_GETTIMEOFDAY
    {
        struct timeval t;
#ifdef GETTIMEOFDAY_NO_TZ
        // 如果系统支持gettimeofday库函数,
        // 则通过该库函数来获取时间戳,
        // 该库函数获取到的时间戳的精度为微秒。
        if (gettimeofday(&t) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#else /* !GETTIMEOFDAY_NO_TZ */
        if (gettimeofday(&t, (struct timezone *)NULL) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#endif /* !GETTIMEOFDAY_NO_TZ */
    }

#endif /* !HAVE_GETTIMEOFDAY */
    {
#if defined(HAVE_FTIME)
        struct timeb t;
        // 如果系统不支持前面提到的
        // gettimeofday库函数,
        // 那么如果系统支持ftime库函数,
        // 则通过ftime库函数来获取时间戳。
        // 该时间戳的精度为毫秒。
        ftime(&t);
        return (double)t.time + (double)t.millitm * (double)0.001;
#else /* !HAVE_FTIME */
        time_t secs;
        // 如果系统只支持time库函数,
        // 则通过time库函数来获取时间戳。
        // 该时间戳的精度为秒。
        time(&secs);
        return (double)secs;
#endif /* !HAVE_FTIME */
    }
}


    上面代码里涉及到的C库函数,在Linux里可以通过man命令来查看其详情:

[email protected]:~$ man gettimeofday
GETTIMEOFDAY(2)            Linux Programmer's Manual           GETTIMEOFDAY(2)

NAME
       gettimeofday, settimeofday - get / set time

SYNOPSIS
       #include <sys/time.h>

       int gettimeofday(struct timeval *tv, struct timezone *tz);

       int settimeofday(const struct timeval *tv, const struct timezone *tz);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       settimeofday(): _BSD_SOURCE

DESCRIPTION
       The  functions  gettimeofday()  and  settimeofday() can get and set the
       time as well as a timezone.  The tv argument is a  struct  timeval  (as
       specified in <sys/time.h>):
....................................................

[email protected]:~$ man ftime
FTIME(3)                   Linux Programmer's Manual                  FTIME(3)

NAME
       ftime - return date and time

SYNOPSIS
       #include <sys/timeb.h>

       int ftime(struct timeb *tp);

DESCRIPTION
       This  function  returns  the  current  time as seconds and milliseconds
       since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).  The time is returned
       in tp, which is declared as follows:

           struct timeb {
               time_t         time;
               unsigned short millitm;
               short          timezone;
               short          dstflag;
           };
....................................................

[email protected]:~$ man 2 time
TIME(2)                    Linux Programmer's Manual                   TIME(2)

NAME
       time - get time in seconds

SYNOPSIS
       #include <time.h>

       time_t time(time_t *t);

DESCRIPTION
       time()  returns  the  time  as  the  number of seconds since the Epoch,
       1970-01-01 00:00:00 +0000 (UTC).

       If t is non-NULL, the return value is also stored in the memory pointed
       to by t.

RETURN VALUE
       On  success,  the value of time in seconds since the Epoch is returned.
       On error, ((time_t) -1) is returned, and errno is set appropriately.
....................................................
[email protected]:~$ 


clock方法:

    clock方法在Linux与windows下的执行效果是不同的,先来看下Linux系统中,clock方法的使用:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.clock()
0.06
>>> def mytest():
...   for i in range(20000000):
...     a = 3 + 4 * 5
... 
>>> time.clock()
0.06
>>> mytest()
>>> time.clock()
21.31
>>> 


    linux系统里,clock方法得到的是当前进程所使用的CPU时间,上例在执行完mytest方法后,使用的CPU时间就变为21.31秒。我们可以用ps命令来查看到各进行所使用的CPU时间:

[email protected]:~$ ps -a -o cputime,etime,command
    TIME     ELAPSED COMMAND
00:00:00    04:52:35 /bin/sh /usr/bin/startx
00:00:00    04:52:35 xinit /root/.xinitrc -- /usr/bin/X :0 -auth /root/.serverauth.1862
00:00:00    04:52:33 sh /root/.xinitrc
00:00:00    04:52:33 ck-launch-session startxfce4
00:00:00    04:52:33 /bin/sh /etc/xfce/xdg/xfce4/xinitrc
00:00:00    04:52:32 /usr/bin/dbus-launch --sh-syntax --exit-with-session
00:00:00    04:52:32 ck-launch-session /usr/bin/xfce4-session
00:00:00    04:52:32 /usr/bin/xfce4-session
00:00:02    04:52:31 xfwm4 --display :0.0 --sm-client-id 2faf8d12a-d091-4543-aabe-a06905d3de88
00:00:00    04:52:31 xfsettingsd
00:00:12    04:52:30 Thunar --sm-client-id 2a60b624f-c588-4b0a-bc04-70d208efb069 --daemon
00:00:05    04:52:30 xfce4-panel --sm-client-id 2e02ec23c-5393-4d13-9594-80e5e86d1bf6
00:00:02    04:52:30 xfdesktop --display :0.0 --sm-client-id 296eea566-2eb2-411a-8a32-b948960fc782
00:00:00    04:52:30 xfce4-settings-helper --display :0.0 --sm-client-id 204fc904b-cbe6-40a3-9562-7b9c355618b2
00:00:00    04:52:29 /usr/libexec/xfce4/panel-plugins/xfce4-menu-plugin socket_id 18874393 name xfce4-menu id 5
00:00:51    04:52:15 gedit file:///mnt/zenglOX/python%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0/time_readme
00:00:27    04:35:07 /usr/bin/Terminal
00:00:00    04:35:06 gnome-pty-helper
00:00:00    04:34:34 -su
00:00:00    03:31:04 -su
00:00:00       02:13 gdb -q python
00:00:21       02:07 /usr/local/bin/python
00:00:00       00:00 ps -a -o cputime,etime,command
[email protected]:~$ 


    上面的第一列显示的就是各进程所使用的CPU时间,例如上面的00:00:21(采用"小时:分钟:秒数"的格式)就表示python进程所使用的CPU时间为21秒,这与前面例子中通过clock方法得到的结果是一致的,只不过ps只能显示到秒,不能显示到毫秒。

    上面的第二列显示的是各进程从启动时刻开始,到当前时刻所运行的总时间。可以看到,python进程虽然运行了27秒,但是该进程因为执行指令,而实际消耗的CPU时间只有21秒。

    linux进程的CPU时间,只是CPU在该进程中执行指令时所消耗的累积时间。当CPU切换到其他进程后,该进程就不再消耗CPU时间了。直到CPU又调度回该进程时,才会继续累积该进程的CPU时间。可以通过下面这个例子来加深理解:

[email protected]:~$ gdb -q python
....................................................
>>> import time
....................................................
>>> time.clock()
21.31
>>> def process():
...   t0 = time.clock()
...   time.sleep(2.5)
...   print time.clock() - t0
... 
>>> process()
0.0
>>> time.clock()
21.33


    可以看到,在当前进程通过time.sleep方法睡眠2.5秒后,它的clock方法所返回的CPU时间并没有发生明显的变化。这是因为,当前进程在睡眠时,CPU被调度到其他进程去执行了。因此,在睡眠期间,就没有累积当前进程的CPU时间。

    下面是windows系统里,clock方法的执行过程:

I:\Python27>python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] 
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> time.clock()
3.9111116077602044e-06
>>> time.clock()
1.5483805902705512
>>> time.clock()
2.2746312729690503
>>> time.clock()
2.9153194051199245
>>> time.clock()
3.731971800885308
>>> time.clock()
4.929970429202594
>>> def process():
...   t0 = time.clock()
...   time.sleep(2.5)
...   print time.clock() - t0
...
>>> process()
2.4993369269
>>> time.clock()
174.97200202819073
>>> 


    在windows下,python会将第一次执行clock方法的时刻作为起始点,之后执行的clock方法所返回的值都是距离该起始点的秒数,并且返回的秒数具有非常高的精确度,可以精确到微秒级别。

    windows里的clock方法返回的就不再是当前进程的CPU时间,而是系统的总的运行时间。因此,上面的process方法里,就可以利用clock方法将sleep睡眠的2.5秒给计算出来了。

    如果想让上面的process方法在不同的系统中,都能产生几乎一致的结果的话,可以使用如下代码:

....................................................
>>> import sys
>>> import time
>>> if sys.platform == 'win32':
...   # On Windows, the best timer is time.clock
...   default_timer = time.clock
... else:
...   # On most other platforms the best timer is time.time
...   default_timer = time.time
... 
>>> def process():
...   t0 = default_timer()
...   time.sleep(2.5)
...   print default_timer() - t0
... 
>>> process()
2.50257587433
>>> 


    上面这段代码的含义其实就是:如果是windows系统平台就使用time.clock方法,如果是其他系统平台(如Linux中)就使用time.time方法。这段代码在作者的Linux系统里的运行结果是2.50257587433,在作者的windows系统里的运行结果为2.4996724444,都约等于2.5秒,这与time.sleep(2.5)执行时睡眠的2.5秒非常接近,都达到了统计process方法的总的执行时间的效果。

    clock方法在Python里执行时,会调用的底层C函数为time_clock

[email protected]:~$ gdb -q python
....................................................
>>> import time
....................................................
>>> time.clock()
....................................................

Breakpoint 1, time_clock (self=0x0, unused=0x0) at
 /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:158
158	    return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
(gdb) c
Continuing.
21.35
>>> 


    time_clock也定义在Modules/timemodule.c文件里:

#ifdef HAVE_CLOCK

#ifndef CLOCKS_PER_SEC
#ifdef CLK_TCK
#define CLOCKS_PER_SEC CLK_TCK
#else
#define CLOCKS_PER_SEC 1000000
#endif
#endif

// 非windows系统,如Linux系统中,
// 会执行的time_clock代码。
static PyObject *
time_clock(PyObject *self, PyObject *unused)
{
    // linux系统里会通过clock库函数来获取
    // 当前进程所使用的CPU时间,
    // 并且,clock库函数返回的处理器时间还需要除以
    // CLOCKS_PER_SEC宏的值,才能得到对应的秒数。
    return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
}
#endif /* HAVE_CLOCK */

#if defined(MS_WINDOWS) && !defined(__BORLANDC__)
/* Due to Mark Hammond and Tim Peters */
// windows系统平台下,会执行的time_clock代码。
static PyObject *
time_clock(PyObject *self, PyObject *unused)
{
    static LARGE_INTEGER ctrStart;
    static double divisor = 0.0;
    LARGE_INTEGER now;
    double diff;

    if (divisor == 0.0) {
        LARGE_INTEGER freq;
        // QueryPerformanceCounter是windows系统平台
        // 所提供的API接口函数。
        // 它可以获取到执行计数器的当前值,
        // 该计数器里存储了非常高精度的
        // (小于1微秒)的时间计数值。
        // 下面会将第一次执行clock方法时,
        // 计数器里的值作为起始点。
        // 那么以后再执行clock方法时,
        // 就可以将当时的计数器值减去起始点,
        // 得到的差值再除以频率值,就可以计算出
        // 距离第一次clock方法的秒数了。
        QueryPerformanceCounter(&ctrStart);
        // QueryPerformanceFrequency也是windows系统
        // 提供的API接口函数。
        // 它可以获取到执行计数器的频率值,
        // 将执行计数器的值除以该频率值,
        // 就可以得到对应的秒数。
        if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
            /* Unlikely to happen - this works on all intel
               machines at least!  Revert to clock() */
            return PyFloat_FromDouble(((double)clock()) /
                                      CLOCKS_PER_SEC);
        }
        divisor = (double)freq.QuadPart;
    }
    // 得到当前时刻的执行计数器的值。
    QueryPerformanceCounter(&now);
    // 再将当前计数器的值减去起始点,以得到差值。
    diff = (double)(now.QuadPart - ctrStart.QuadPart);
    // 最后再将差值除以频率,就可以得到对应的秒数,
    // 将该秒数作为结果返回。
    return PyFloat_FromDouble(diff / divisor);
}

#define HAVE_CLOCK /* So it gets included in the methods */
#endif /* MS_WINDOWS && !defined(__BORLANDC__) */


    上面代码里,linux系统下会调用的clock库函数,可以通过man命令来查看其详情:

[email protected]:~$ man 3 clock
CLOCK(3)                  Linux Programmer's Manual                 CLOCK(3)

NAME
       clock - Determine processor time

SYNOPSIS
       #include <time.h>

       clock_t clock(void);

DESCRIPTION
       The  clock() function returns an approximation of processor time used
       by the program.

RETURN VALUE
       The value returned is the CPU time used so far as a clock_t;  to  get
       the number of seconds used, divide by CLOCKS_PER_SEC.  If the proces‐
       sor time used is not available or its value  cannot  be  represented,
       the function returns the value (clock_t) -1.

....................................................

[email protected]:~$ 


    至于time_clock函数,在windows平台下,会调用的QueryPerformanceCounter与QueryPerformanceFrequency的API接口函数的使用详情,则请参考微软的官方手册(也可以在Google中搜索这些接口函数名)。

sleep方法:

    sleep方法可以将当前进程暂时挂起,暂停几秒再继续执行,该方法的使用如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.sleep(3.5)
....................................................

Breakpoint 1, time_sleep (self=0x0, args=0xb7ca36c4)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:204
204	    if (!PyArg_ParseTuple(args, "d:sleep", &secs))
(gdb) c
Continuing.

>>> 


    上面例子里,time.sleep(3.5)执行时就会将python所在的进程暂时挂起,在等待3.5秒后python才会继续执行。还可以看到,sleep方法在执行时会调用的底层C函数为time_sleep,该函数同样定义在Modules/timemodule.c文件里:

static PyObject *
time_sleep(PyObject *self, PyObject *args)
{
    double secs;
    if (!PyArg_ParseTuple(args, "d:sleep", &secs))
        return NULL;
    // 通过下面的floatsleep函数去完成
    // 具体的挂起进程的操作。
    if (floatsleep(secs) != 0)
        return NULL;
    Py_INCREF(Py_None);
    return Py_None;
}

....................................................

/* Implement floatsleep() for various platforms.
   When interrupted (or when another error occurs), return -1 and
   set an exception; else return 0. */

// floatsleep会根据不同的系统平台,
// 调用不同的库函数来完成挂起进程的操作。
static int
floatsleep(double secs)
{
/* XXX Should test for MS_WINDOWS first! */
#if defined(HAVE_SELECT) && !defined(__BEOS__) && !defined(__EMX__)
    struct timeval t;
    double frac;
    frac = fmod(secs, 1.0);
    secs = floor(secs);
    t.tv_sec = (long)secs;
    t.tv_usec = (long)(frac*1000000.0);
    Py_BEGIN_ALLOW_THREADS
    // linux系统中会通过select库函数
    // 去完成暂停进程的操作,该库函数
    // 的暂停时间的精度,可以达到微秒级别。
    if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
#ifdef EINTR
        if (errno != EINTR) {
#else
        if (1) {
#endif
            Py_BLOCK_THREADS
            PyErr_SetFromErrno(PyExc_IOError);
            return -1;
        }
    }
    Py_END_ALLOW_THREADS
    ................................................
}


    上面代码里涉及到的select库函数,在Linux系统里,可以通过man命令来查看其详情:

[email protected]:~$ man select
SELECT(2)                  Linux Programmer's Manual                 SELECT(2)

NAME
       select,  pselect,  FD_CLR,  FD_ISSET, FD_SET, FD_ZERO - synchronous I/O
       multiplexing

SYNOPSIS
       /* According to POSIX.1-2001 */
       #include <sys/select.h>

       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

....................................................

[email protected]:~$ 


gmtime与localtime方法:

    这两个方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> t = time.time()
>>> t
1440930064.635473
>>> time.gmtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=10, tm_min=21, tm_sec=4, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> time.localtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=18, tm_min=21, tm_sec=4, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,M5.1.0,M10.5.0'
>>> time.tzset()
>>> time.gmtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=10, tm_min=21, tm_sec=4, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> time.localtime(t)
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=19, tm_min=21, tm_sec=4, tm_wday=6, tm_yday=242, tm_isdst=1)
>>> 


    gmtime方法可以将时间戳转为UTC标准时区的时间,而localtime方法则会将时间戳转为本地所在时区的时间。

    例如上面的gmtime会将1440930064.635473的时间戳转为2015年08月30日 10:21:04的UTC标准时间。

    localtime则会将该时间戳转为2015年08月30日 18:21:04的UTC+8时区的时间。

    时间戳与相应时区的时间的关系,可以参考前面的图1

    此外,localtime返回的本地时间,还会受到夏令时的影响。

    例如上面在通过 os.environ['TZ'] = 'CST-08DST-09,M5.1.0,M10.5.0' 语句,人为将5月初到10月底设置为夏令时日后(DST-09表示夏令时相当于UTC+9时区的时间),由于8月处于设置的夏令时范围,因此,localtime就会返回夏令时的时间,本例中就是2015年08月30日 19:21:04的UTC+9的时间。

    os.environ['TZ']的设置格式会在后面进行介绍。

    夏令时的作用,简单来说就是:一般在天亮早的夏季,人为将时间提前一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。有关夏令时的详情请参考 http://baike.baidu.com/view/100246.htm 该链接对应的文章。

    从上面例子里可以看到,gmtime与localtime方法都会返回一个time.struct_time类型的对象,类似如下所示:

time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=19, tm_min=21, tm_sec=4, tm_wday=6, tm_yday=242, tm_isdst=1)

    time.struct_time类型的对象里包含了9个成员,前6个成员表示日期和时间,如上面的tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=19, tm_min=21, tm_sec=4就表示:2015年8月30日 19:21:04 。

    第7个tm_wday成员表示星期几,如上面的tm_wday=6就表示星期天(0表示星期一,1表示星期二,以此类推)。

    第8个tm_yday成员表示当前日期是一年中的第几天,如上面的tm_yday=242就表示2015年8月30日是2015年的第242天。

    最后一个tm_isdst成员表示当前日期是否是夏令时,如上面的tm_isdst=1就表示2015年8月30日正处于前面设置的夏令时范围,也就是该日期是夏令时。如果tm_isdst为0,则表示当前日期不是夏令时。

    前面例子里,我们为了测试,将5月初到10月底设置为了夏令时范围,在测试完后,我们需要通过下面的语句将时区的设置进行还原:

>>> os.environ['TZ'] = 'CST-08'
>>> time.tzset()
>>> time.localtime(time.time())
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=20, tm_min=34, tm_sec=55, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> 


    通过将os.environ['TZ']设置为'CST-08',来取消夏令时,并恢复原来的UTC+8的时区。通过time.tzset()方法让这一设置生效。os.environ['TZ']的设置格式以及tzset方法的使用,在后面会进行介绍。

    上面介绍的time.struct_time类型的对象,对应的内部C结构如下(该C结构定义在Include/structseq.h的头文件里):

typedef struct {
	PyObject_VAR_HEAD
	PyObject *ob_item[1];
} PyStructSequence;


    可以看到该结构与之前章节里介绍的元组类型的内部C结构非常相似,都有一个固定长度的ob_item数组,该数组里存储了time.struct_time类型对象的各成员的值。如:tm_year成员的值就存储在ob_item[0]里,tm_mon成员的值存储在ob_item[1]里,tm_mday成员的值存储在ob_item[2]里,以此类推。我们可以直接通过索引值来访问这些成员:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> tm = time.localtime(time.time())
>>> tm[0]
2015
>>> tm.tm_year
2015
>>> tm[1]
8
>>> tm.tm_mon
8
>>> tm[2]
30
>>> tm.tm_mday
30
>>> tm[3]
21
>>> tm.tm_hour
21
>>> 


    可以看到,tm[0]等效于tm.tm_year,tm[1]等效于tm.tm_mon,tm[2]等效于tm.tm_mday,tm[3]等效于tm.tm_hour,以此类推。

    gmtime与localtime方法在执行时,会调用的底层C函数如下:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> t = time.time()
>>> t
1440940220.677535
>>> time.gmtime(t)
....................................................

Breakpoint 2, time_gmtime (self=0x0, args=0xb7c9ff4c)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:320
320	    if (!parse_time_double_args(args, "|O:gmtime", &when))
(gdb) c
Continuing.
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=13, tm_min=10, tm_sec=20, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> time.localtime(t)
....................................................

Breakpoint 3, time_localtime (self=0x0, args=0xb7c9ff4c)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:336
336	    if (!parse_time_double_args(args, "|O:localtime", &when))
(gdb) c
Continuing.
time.struct_time(tm_year=2015, tm_mon=8, tm_mday=30, tm_hour=21, tm_min=10, tm_sec=20, tm_wday=6, tm_yday=242, tm_isdst=0)
>>> 


    可以看到gmtime方法会调用的底层C函数为time_gmtime,而localtime方法会调用的底层C函数则为time_localtime,这两个C函数都定义在Modules/timemodule.c文件里:

static PyObject *
time_gmtime(PyObject *self, PyObject *args)
{
    double when;
    // 从脚本参数里获取时间戳,如果没提供任何参数,
    // 则会使用当前时刻的时间戳来进行转换。
    if (!parse_time_double_args(args, "|O:gmtime", &when))
        return NULL;
    // 通过gmtime库函数将时间戳转为
    // UTC标准时区的时间,
    // time_convert会将库函数返回的结果,
    // 再转为Python的time.struct_time类型的对象。
    // 最后将该对象作为结果返回。
    return time_convert(when, gmtime);
}

....................................................

static PyObject *
time_localtime(PyObject *self, PyObject *args)
{
    double when;
    // 从脚本参数里获取时间戳,如果没提供任何参数,
    // 则会使用当前时刻的时间戳来进行转换。
    if (!parse_time_double_args(args, "|O:localtime", &when))
        return NULL;
    // 通过localtime库函数将时间戳转为
    // 本地所在时区的时间,
    // 如果处于夏令时,则转为夏令时对应的时间,
    // time_convert会将库函数返回的结果,
    // 再转为Python的time.struct_time类型的对象。
    // 最后将该对象作为结果返回。
    return time_convert(when, localtime);
}


    上面代码里所涉及到的gmtime与localtime这两个库函数的详情,在Linux系统里,可以通过man命令来查看到:

[email protected]:~$ man gmtime
CTIME(3)                   Linux Programmer's Manual                  CTIME(3)

NAME
       asctime,   ctime,   gmtime,   localtime,  mktime,  asctime_r,  ctime_r,
       gmtime_r, localtime_r - transform date and time to broken-down time  or
       ASCII

SYNOPSIS
       #include <time.h>

       char *asctime(const struct tm *tm);
       char *asctime_r(const struct tm *tm, char *buf);

       char *ctime(const time_t *timep);
       char *ctime_r(const time_t *timep, char *buf);

       struct tm *gmtime(const time_t *timep);
       struct tm *gmtime_r(const time_t *timep, struct tm *result);

       struct tm *localtime(const time_t *timep);
       struct tm *localtime_r(const time_t *timep, struct tm *result);

....................................................

[email protected]:~$ man localtime
CTIME(3)                   Linux Programmer's Manual                  CTIME(3)

NAME
       asctime,   ctime,   gmtime,   localtime,  mktime,  asctime_r,  ctime_r,
       gmtime_r, localtime_r - transform date and time to broken-down time  or
       ASCII

....................................................

[email protected]:~$ 


asctime方法:

    asctime方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> tm = time.localtime(time.time())
>>> tm
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=2, tm_hour=9, tm_min=17, tm_sec=37, tm_wday=2, tm_yday=245, tm_isdst=0)
>>> time.asctime(tm)
....................................................

Breakpoint 1, time_asctime (self=0x0, args=0xb7c9ff4c)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:564
564	    PyObject *tup = NULL;
(gdb) c
Continuing.
'Wed Sep  2 09:17:37 2015'
>>> 


    可以看到,localtime方法会将time方法返回的时间戳转为time.struct_time类型,而asctime方法则可以将time.struct_time类型转换为字符串格式。asctime方法会调用的底层C函数为time_asctime,该函数也定义在Modules/timemodule.c文件里:

static PyObject *
time_asctime(PyObject *self, PyObject *args)
{
    PyObject *tup = NULL;
    struct tm buf;
    char *p;
    // asctime方法最多只能接受一个脚本参数,
    // 当没提供任何脚本参数时,
    // 将会使用当前时刻来进行转换。
    // 提供给asctime方法的脚本参数可以是
    // time.struct_time类型的对象,
    // 也可以是元组或列表之类的对象。
    if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup))
        return NULL;
    if (tup == NULL) {
        // 当没提供任何脚本参数时,
        // 下面会使用当前时刻来进行转换。
        time_t tt = time(NULL);
        buf = *localtime(&tt);
        // 如果提供了脚本参数的话,
        // 则会通过gettmarg函数将脚本参数
        // 转换为struct tm类型的C结构体。
        // 因为下面的asctime的C标准库函数,
        // 需要使用该类型的结构体作为输入参数。
    } else if (!gettmarg(tup, &buf))
        return NULL;
    // 通过asctime库函数将参数转为字符串格式。
    p = asctime(&buf);
    if (p == NULL) {
        PyErr_SetString(PyExc_ValueError, "invalid time");
        return NULL;
    }
    if (p[24] == '\n')
        p[24] = '\0';
    // 最后将C语言字符串转换为Python字符串对象,
    // 再将该对象作为结果返回。
    return PyString_FromString(p);
}


    从上面的注释里可以看到,asctime方法还可以使用元组或列表来作为参数:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.asctime((2014,7,29,11,31,33,0,232,0))
'Mon Jul 29 11:31:33 2014'
>>> time.asctime([2015,5,28,12,32,34,0,232,0])
'Mon May 28 12:32:34 2015'
>>>


    asctime方法最终会通过asctime库函数去完成具体的转换操作,在Linux系统里可以通过man命令来查看到该库函数的详情:

[email protected]:~$ man asctime
CTIME(3)                   Linux Programmer's Manual                  CTIME(3)

NAME
       asctime,   ctime,   gmtime,   localtime,  mktime,  asctime_r,  ctime_r,
       gmtime_r, localtime_r - transform date and time to broken-down time  or
       ASCII

SYNOPSIS
       #include <time.h>

       char *asctime(const struct tm *tm);
       char *asctime_r(const struct tm *tm, char *buf);
       .............................................

DESCRIPTION
       .............................................
       The asctime() function converts the broken-down time value  tm  into  a
       null-terminated  string  with  the  same format as ctime().  The return
       value points to a statically allocated string which might be  overwrit‐
       ten  by  subsequent  calls  to any of the date and time functions.  The
       asctime_r() function does the same, but stores the string  in  a  user-
       supplied buffer which should have room for at least 26 bytes.

       .............................................

[email protected]:~$ 


ctime方法:

    ctime方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> t = time.time()
>>> t
1441167026.30304
>>> time.ctime(t)
'Wed Sep  2 12:10:26 2015'
>>> time.ctime(t)
....................................................

Breakpoint 2, time_ctime (self=0x0, args=0xb7ca1b5c)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:594
594	    PyObject *ot = NULL;
(gdb) c
Continuing.
'Wed Sep  2 12:10:26 2015'
>>> 


    ctime方法可以直接将时间戳转为字符串格式。该方法会调用的底层C函数为time_ctime,该函数定义在Modules/timemodule.c文件里:

static PyObject *
time_ctime(PyObject *self, PyObject *args)
{
    PyObject *ot = NULL;
    time_t tt;
    char *p;

    // 用户可以给ctime方法提供一个可选的
    // 时间戳参数,当没提供任何参数时,
    // 就会使用当前时刻对应的时间戳来进行转换。
    if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot))
        return NULL;
    // 当没提供任何参数时,
    // 或者提供的脚本参数是None对象时,
    // 就采用当前时刻对应的时间戳。
    if (ot == NULL || ot == Py_None)
        tt = time(NULL);
    else {
        double dt = PyFloat_AsDouble(ot);
        if (PyErr_Occurred())
            return NULL;
        // 将脚本参数转为time_t类型,
        // 因为后面的ctime库函数
        // 需要输入该类型的参数。
        tt = _PyTime_DoubleToTimet(dt);
        if (tt == (time_t)-1 && PyErr_Occurred())
            return NULL;
    }
    // 通过ctime库函数将参数转为字符串格式。
    p = ctime(&tt);
    if (p == NULL) {
        PyErr_SetString(PyExc_ValueError, "unconvertible time");
        return NULL;
    }
    if (p[24] == '\n')
        p[24] = '\0';
    // 最后将C语言字符串转为Python字符串对象,
    // 再将该对象作为结果返回。
    return PyString_FromString(p);
}


    从上面的代码里可以看到,当没提供任何脚本参数时,或者提供的脚本参数是None对象时,就会使用当前时刻对应的时间戳来进行转换:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.ctime()
'Wed Sep  2 12:37:46 2015'
>>> time.ctime(None)
'Wed Sep  2 12:37:47 2015'
>>> 


    从前面的C源码中还可以看到,ctime方法最终会通过ctime库函数去进行具体的转换。在Linux系统里,可以通过man命令来查看到该库函数的详情:

[email protected]:~$ man ctime
CTIME(3)                   Linux Programmer's Manual                  CTIME(3)

NAME
       asctime,   ctime,   gmtime,   localtime,  mktime,  asctime_r,  ctime_r,
       gmtime_r, localtime_r - transform date and time to broken-down time  or
       ASCII

SYNOPSIS
       #include <time.h>

       char *asctime(const struct tm *tm);
       char *asctime_r(const struct tm *tm, char *buf);

       char *ctime(const time_t *timep);
       char *ctime_r(const time_t *timep, char *buf);

       .............................................

DESCRIPTION
       .............................................

       The call ctime(t) is equivalent to asctime(localtime(t)).  It  converts
       the calendar time t into a null-terminated string of the form

              "Wed Jun 30 21:49:08 1993\n"

       The  abbreviations  for  the  days of the week are "Sun", "Mon", "Tue",
       "Wed", "Thu", "Fri", and "Sat".  The abbreviations for the  months  are
       "Jan",  "Feb",  "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
       "Nov", and "Dec".  The return value points to  a  statically  allocated
       string  which  might  be  overwritten by subsequent calls to any of the
       date and time functions.  The function also sets the external variables
       tzname,  timezone,  and  daylight (see tzset(3)) with information about
       the current timezone.  The reentrant version ctime_r() does  the  same,
       but  stores the string in a user-supplied buffer which should have room
       for at least 26 bytes.  It need not set tzname, timezone, and daylight.

       .............................................

[email protected]:~$ 


    从上面的man输出里可以看到,ctime(t)等效于asctime(localtime(t)) 。因此,在Python脚本里,time.ctime(t)就等效于time.asctime(time.localtime(t)),这里的t表示时间戳参数。

    并且ctime返回的字符串都是固定的 "星期 月 日 时:分:秒 年份" 的格式,如 "Wed Jun 30 21:49:08 1993" 就表示"星期三 六月 30日 21:49:08 1993年"。

mktime方法:

    mktime方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> t = time.time()
>>> t
1441170976.040004
>>> tm = time.localtime(t)
>>> tm
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=2, tm_hour=13, tm_min=16, tm_sec=16, tm_wday=2, tm_yday=245, tm_isdst=0)
>>> time.mktime(tm)
1441170976.0
>>> time.mktime(tm)
....................................................

Breakpoint 3, time_mktime (self=0x0, tup=0xb7d49c40)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:633
633	    if (!gettmarg(tup, &buf))
(gdb) c
Continuing.
1441170976.0
>>> 


    从上面的输出里可以看到,localtime方法可以将时间戳转换为time.struct_time类型的对象(该对象里的时间是当地所在时区的时间),而mktime方法则可以反过来,将time.struct_time类型的对象转换为当地所在时区的时间戳,如下图所示:


图2

    mktime方法在执行时,内部会调用的底层C函数为time_mktime,该函数也定义在Modules/timemodule.c文件里:

static PyObject *
time_mktime(PyObject *self, PyObject *tup)
{
    struct tm buf;
    time_t tt;
    // 通过gettmarg函数将传递给mktime方法的
    // 脚本参数转换为struct tm类型的C结构体,
    // 因为后面的mktime库函数需要使用该类型的
    // 结构体作为输入参数。
    // 传递给mktime方法的脚本参数可以是
    // time.struct_time类型的对象,
    // 还可以是元组或列表之类的集合。
    if (!gettmarg(tup, &buf))
        return NULL;
    buf.tm_wday = -1;  /* sentinel; original value ignored */
    // 通过mktime库函数将参数转换为
    // 当地所在时区的时间戳。
    tt = mktime(&buf);
    /* Return value of -1 does not necessarily mean an error, but tm_wday
     * cannot remain set to -1 if mktime succeeded. */
    if (tt == (time_t)(-1) && buf.tm_wday == -1) {
        PyErr_SetString(PyExc_OverflowError,
                        "mktime argument out of range");
        return NULL;
    }
    // 将库函数返回的结果转换为Python的浮点数对象,
    // 并将该对象作为结果返回。
    return PyFloat_FromDouble((double)tt);
}


    从代码注释里可以看到,传递给mktime方法的脚本参数除了可以是time.struct_time类型的对象外,还可以是元组或列表之类的集合:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.mktime((2014,7,29,11,31,33,0,232,0))
1406604693.0
>>> time.mktime([2015,5,28,12,32,34,0,232,0])
1432787554.0
>>> 


    上面将 2015/5/28 12:32:34 以 [2015,5,28,12,32,34 ... ] 的列表形式传递给mktime方法,再由该方法将时间转为当地所在时区的时间戳。

    mktime方法最终会通过mktime的C标准库函数去完成具体的转换工作,该库函数的详情可以通过man命令来查看到:

[email protected]:~$ man mktime
CTIME(3)                   Linux Programmer's Manual                  CTIME(3)

NAME
       asctime,   ctime,   gmtime,   localtime,  mktime,  asctime_r,  ctime_r,
       gmtime_r, localtime_r - transform date and time to broken-down time  or
       ASCII

SYNOPSIS
       #include <time.h>

       .............................................

       time_t mktime(struct tm *tm);

       .............................................

DESCRIPTION
       .............................................

       The  mktime() function converts a broken-down time structure, expressed
       as local time, to calendar time representation.  The  function  ignores
       the  values  supplied  by the caller in the tm_wday and tm_yday fields.
       The value specified in the tm_isdst field informs mktime()  whether  or
       not  daylight  saving  time (DST) is in effect for the time supplied in
       the tm structure: a positive value means DST is in effect;  zero  means
       that  DST  is  not  in effect; and a negative value means that mktime()
       should (use timezone information and system databases  to)  attempt  to
       determine whether DST is in effect at the specified time.

       .............................................

[email protected]:~$ 


    从上面的man命令的输出里可以看到,mktime返回的时间戳会受到daylight  saving  time (DST)即夏令时的影响,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,M5.1.0,M10.5.0'
>>> time.tzset()
>>> time.mktime([2015,5,28,12,32,34,0,232,0])
1432787554.0
>>> time.mktime([2015,5,28,12,32,34,0,232,1])
1432783954.0
>>> time.mktime([2015,5,28,12,32,34,0,232,-1])
1432783954.0
>>> time.mktime([2015,4,28,12,32,34,0,232,-1])
1430195554.0
>>> os.environ['TZ'] = 'CST-08'
>>> time.tzset()
>>> time.mktime([2015,5,28,12,32,34,0,232,-1])
1432787554.0
>>> 


    通过将脚本参数的最后一个成员设置为0,可以让mktime生成非夏令时的时间戳。将该成员设置为1(或者其他的正数),则会生成夏令时的时间戳。将该成员设置为-1(或者其他的负数),则表示由mktime方法根据提供的日期,来自行检测是否需要生成夏令时的时间戳。

strftime方法:

    strftime方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> tm = time.localtime()
>>> time.strftime('%Y-%m-%d %H:%M:%S', tm)
'2015-09-02 20:20:01'
>>> time.strftime('%Y-%m-%d %H:%M:%S', tm)
....................................................

Breakpoint 4, time_strftime (self=0x0, args=0xb7d3ab94)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:395
395	    PyObject *tup = NULL;
(gdb) c
Continuing.
'2015-09-02 20:20:01'
>>> 


    上面通过strftime方法将localtime返回的time.struct_time类型的对象,转换为了指定格式的字符串。strftime方法会调用的底层C函数为time_strftime,该函数也定义在Modules/timemodule.c文件里:

static PyObject *
time_strftime(PyObject *self, PyObject *args)
{
    PyObject *tup = NULL;
    struct tm buf;
    const char *fmt;
    size_t fmtlen, buflen;
    char *outbuf = 0;
    size_t i;

    memset((void *) &buf, '\0', sizeof(buf));

    // strftime方法可以将时间根据
    // 指定的格式转换为相应的字符串对象。
    // 该方法最多可以接受两个脚本参数,
    // 其中第一个参数是必须的,
    // 用于指定需要生成的时间格式,
    // 而第二个参数则是可选的,
    // 用于表示需要进行转换的时间,
    // 第二个参数可以是time.struct_time类型的对象,
    // 还可以是元组或列表之类的集合。
    if (!PyArg_ParseTuple(args, "s|O:strftime", &fmt, &tup))
        return NULL;

    if (tup == NULL) {
        // 如果没提供第二个脚本参数的话,
        // 则会使用当前时刻来进行转换。
        time_t tt = time(NULL);
        buf = *localtime(&tt);
        // 如果提供了第二个脚本参数,
        // 则会通过gettmarg函数将该脚本参数
        // 转换为struct tm类型的C结构体。
        // 因为后面的strftime的C标准库函数,
        // 需要使用该类型的结构体作为输入参数。
    } else if (!gettmarg(tup, &buf))
        return NULL;

    ................................................

    /* I hate these functions that presume you know how big the output
     * will be ahead of time...
     */
    for (i = 1024; ; i += i) {
        outbuf = (char *)malloc(i);
        if (outbuf == NULL) {
            return PyErr_NoMemory();
        }
        // 通过strftime库函数将时间根据
        // 指定的格式转换为相应的字符串。
        buflen = strftime(outbuf, i, fmt, &buf);
        if (buflen > 0 || i >= 256 * fmtlen) {
            /* 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. */
            PyObject *ret;
            // 最后将生成的C语言字符串转为
            // Python字符串对象,再将该对象
            // 作为结果返回。
            ret = PyString_FromStringAndSize(outbuf, buflen);
            free(outbuf);
            return ret;
        }
        free(outbuf);
        ............................................

    }
}


    可以看到,strftime方法最终会通过strftime库函数去完成具体的转换工作,在Linux系统里可以通过man命令来查看到该库函数的详情:

[email protected]:~$ man strftime
STRFTIME(3)                Linux Programmer's Manual               STRFTIME(3)

NAME
       strftime - format date and time

SYNOPSIS
       #include <time.h>

       size_t strftime(char *s, size_t max, const char *format,
                       const struct tm *tm);

DESCRIPTION
       The  strftime()  function  formats the broken-down time tm according to
       the format specification format and places the result in the  character
       array s of size max.

       The  format  specification  is a null-terminated string and may contain
       special character sequences called conversion specifications,  each  of
       which  is  introduced  by  a '%' character and terminated by some other
       character known as a conversion specifier character.  All other charac‐
       ter sequences are ordinary character sequences.

       The  characters  of  ordinary  character  sequences (including the null
       byte) are copied verbatim from format to s. However, the characters  of
       conversion specifications are replaced as follows:

       %a     The abbreviated weekday name according to the current locale.

       %A     The full weekday name according to the current locale.

       %b     The abbreviated month name according to the current locale.

       .............................................

[email protected]:~$ 


    可以看到,该库函数支持各种时间格式,例如:%a,%A,%b,%Y,%m,%d等等。

    %a表示生成星期名的英文缩写,%A则表示生成星期名的英文全称,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%a')
'Wed'
>>> time.strftime('%A')
'Wednesday'
>>> 


    上面的Wed与Wednesday都表示当前时间是星期三,Wed是星期三的英文缩写,Wednesday则是星期三的英文全称。

    %b表示生成月份名的英文缩写,%B则表示生成月份名的英文全称,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%b', (2015, 9, 13, 10, 13, 13, 0, 215, 0))
'Sep'
>>> time.strftime('%B', (2015, 9, 13, 10, 13, 13, 0, 215, 0))
'September'
>>> 


    上面的Sep是九月份的英文缩写,September则是九月份的英文全称。

    %c表示生成标准的时间格式,该格式与之前介绍过的asctime方法所生成的时间格式是一样的,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%c', (2015, 9, 13, 10, 13, 13, 0, 215, 0))
'Mon Sep 13 10:13:13 2015'
>>> time.asctime((2015, 9, 13, 10, 13, 13, 0, 215, 0))
'Mon Sep 13 10:13:13 2015'
>>> 


    注意:这里的日期时间,还有星期几都是随意指定的。2015年9月13日其实是星期天,只不过上面的元组里的第7个成员是0(表示星期一),因此,结果就显示Mon来表示星期一了。这些方法不会对日期和星期数进行检查,你指定的星期几,就会显示星期几。

    %C会用两位整数来表示century number(世纪号),%Y表示生成带世纪号的年份,而%y则表示生成不带世纪号的年份,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%C', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'20'
>>> time.strftime('%Y', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'2015'
>>> time.strftime('%y', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'15'
>>> 


    上面的世纪号20,其实就是2015除以100的整数部分,也就是2015年的开头的两个数。使用%Y可以显示完整的年份,而使用%y则只会显示不带世纪号的年份。

    %d会用十进制来表示月份天数(即一个月的第几天),如果天数不足两位整数的,开头会用0补齐。%e也可以表示月份天数,只不过当月份天数不足两位整数时,开头会用空格来补齐,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%d', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'13'
>>> time.strftime('%e', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'13'
>>> time.strftime('%d', (2015, 9, 2, 10, 13, 13, 6, 256, 0))
'02'
>>> time.strftime('%e', (2015, 9, 2, 10, 13, 13, 6, 256, 0))
' 2'
>>> 


    上面%d格式所生成的'02'的开头会用0来补齐,而%e生成的' 2'的开头,则是用空格来补齐的。

    %m会用十进制来表示月份:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%m', (2015, 9, 13, 10, 13, 13, 6, 256, 0))
'09'
>>> 


    %H会用24小时制来表示小时数,%M会用十进制来表示分钟数,%S会用十进制来表示秒数:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strftime('%H', (2015, 9, 13, 10, 13, 15, 6, 256, 0))
'10'
>>> time.strftime('%M', (2015, 9, 13, 10, 13, 15, 6, 256, 0))
'13'
>>> time.strftime('%S', (2015, 9, 13, 10, 13, 15, 6, 256, 0))
'15'
>>> time.strftime('%H:%M:%S', (2015, 9, 13, 10, 13, 15, 6, 256, 0))
'10:13:15'
>>> 


    至于其他的时间格式,请参考前面提到的man strftime命令输出的帮助信息。

strptime方法:

    上面介绍的strftime方法可以将时间转为字符串。那么这里要介绍的strptime方法,则可以反过来,将字符串转为时间,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strptime('2015-1-8 13:14:15', '%Y-%m-%d %H:%M:%S')
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=8, tm_hour=13, tm_min=14, tm_sec=15, tm_wday=3, tm_yday=8, tm_isdst=-1)
>>> time.strptime('2015-1-8 13:14:15', '%Y-%m-%d %H:%M:%S')
....................................................

Breakpoint 1, time_strptime (self=0x0, args=0xb7d3a9d4)
    at /mnt/zenglOX/Python-2.7.8/Modules/timemodule.c:543
543	    PyObject *strptime_module = PyImport_ImportModuleNoBlock("_strptime");
(gdb) c
Continuing.
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=8, tm_hour=13, tm_min=14, tm_sec=15, tm_wday=3, tm_yday=8, tm_isdst=-1)
>>> 


    上面例子里,%Y表示年份,对应字符串里的2015

    %m表示月份,对应字符串里的1

    %d表示月份天数,对应字符串里的8

    %H表示小时数,对应字符串里的13

    %M表示分钟数,对应字符串里的14

    %S表示秒数,对应字符串里的15

    因此,得到的时间就是time.struct_time(tm_year=2015, tm_mon=1, tm_mday=8, tm_hour=13, tm_min=14, tm_sec=15, ...)了。

    还可以看到,strptime方法会调用的底层C函数为time_strptime,该函数同样定义在Modules/timemodule.c文件里:

static PyObject *
time_strptime(PyObject *self, PyObject *args)
{
    // 导入_strptime模块,该模块的Python源代码,
    // 定义在/usr/local/lib/python2.7/_strptime.py文件里。
    PyObject *strptime_module = PyImport_ImportModuleNoBlock("_strptime");
    PyObject *strptime_result;

    if (!strptime_module)
        return NULL;
    // 虽然C语言里存在strptime的标准库函数,
    // 但Python并没有使用该库函数来完成转换工作,
    // 而是使用的_strptime模块里的_strptime_time方法
    // 去完成具体的转换工作的。
    strptime_result = PyObject_CallMethod(strptime_module,
                                            "_strptime_time", "O", args);
    Py_DECREF(strptime_module);
    // 将_strptime_time方法返回的结果作为
    // 最终结果进行返回。
    return strptime_result;
}


    Python会通过_strptime模块里的_strptime_time方法来完成转换工作,该模块定义在/usr/local/lib/python2.7/_strptime.py文件里:

# _strptime_time方法最终会通过下面的
# _strptime方法去完成具体的转换工作。
def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
    """Return a time struct based on the input string and the format string."""
    ................................................
    for group_key in found_dict.iterkeys():
        ............................................
        # %y格式对应不带世纪号的年份。
        if group_key == 'y':
            year = int(found_dict['y'])
            # Open Group specification for strptime() states that a %y
            #value in the range of [00, 68] is in the century 2000, while
            #[69,99] is in the century 1900
            if year <= 68:
                year += 2000
            else:
                year += 1900
        # %Y格式对应带有世纪号的完整年份。
        elif group_key == 'Y':
            year = int(found_dict['Y'])
        # %m对应月份(用十进制整数来表示的)。
        elif group_key == 'm':
            month = int(found_dict['m'])
        # %B对应月份名的全称。
        elif group_key == 'B':
            month = locale_time.f_month.index(found_dict['B'].lower())
        # %b对应月份名的缩写。
        elif group_key == 'b':
            month = locale_time.a_month.index(found_dict['b'].lower())
        # %d对应月份天数。
        elif group_key == 'd':
            day = int(found_dict['d'])
        # %H对应小时数(24小时制)
        elif group_key == 'H':
            hour = int(found_dict['H'])
        # %I对应小时数(12小时制)
        elif group_key == 'I':
            hour = int(found_dict['I'])
            ampm = found_dict.get('p', '').lower()
            # If there was no AM/PM indicator, we'll treat this like AM
            if ampm in ('', locale_time.am_pm[0]):
                # We're in AM so the hour is correct unless we're
                # looking at 12 midnight.
                # 12 midnight == 12 AM == hour 0
                if hour == 12:
                    hour = 0
            # 如果存在%p,且%p对应为pm即下午时,
            # 那么,当%I对应的值不等于12时,
            # 就会将%I的值加上12,来得到24小时制
            # 的小时数。
            elif ampm == locale_time.am_pm[1]:
                # We're in PM so we need to add 12 to the hour unless
                # we're looking at 12 noon.
                # 12 noon == 12 PM == hour 12
                if hour != 12:
                    hour += 12
        # %M对应分钟数。
        elif group_key == 'M':
            minute = int(found_dict['M'])
        # %S对应秒数。
        elif group_key == 'S':
            second = int(found_dict['S'])
        # %f对于strptime方法的返回结果,
        # 暂时没什么太多的作用。
        elif group_key == 'f':
            s = found_dict['f']
            # Pad to always return microseconds.
            s += "0" * (6 - len(s))
            fraction = int(s)
        # %A对应星期名的全称。
        elif group_key == 'A':
            weekday = locale_time.f_weekday.index(found_dict['A'].lower())
        # %a对应星期名的缩写。
        elif group_key == 'a':
            weekday = locale_time.a_weekday.index(found_dict['a'].lower())
        # %w对应星期(用十进制整数来表示的)
        # 只不过这里需要注意的是,
        # %w对应的值如果是0则表示星期天,
        # 如果是1则表示星期一,以此类推。
        # 在返回的time.struct_time对象里,
        # 0会被转为6存储到tm_wday成员里,
        # 1会被转为0存储到tm_wday成员里,
        # 2会被转为1存储到tm_wday成员里,
        # 以此类推。
        # 因为strptime方法是与strptime的C标准
        # 库函数的用法相一致的,在strptime的
        # C库函数里,0表示星期天,1表示星期一,
        # 而在Python里,则规定的是6表示星期天,
        # 0表示星期一,因此,这里就需要进行转换。
        elif group_key == 'w':
            weekday = int(found_dict['w'])
            if weekday == 0:
                weekday = 6
            else:
                weekday -= 1
        # %j对应一年中的天数。
        elif group_key == 'j':
            julian = int(found_dict['j'])
        ............................................
        # %Z对应时区名,它可以影响返回的
        # time.struct_time对象里的最后一个
        # tm_isdst成员的值,如果%Z对应的时区名
        # 是非夏令时的时区名,则tm_isdst就会是0,
        # 如果是夏令时的时区名,
        # 则tm_isdst就会是1,
        # 在没提供%Z格式时,tm_isdst的默认值是-1。
        elif group_key == 'Z':
            # Since -1 is default value only need to worry about setting tz if
            # it can be something other than -1.
            found_zone = found_dict['Z'].lower()
            for value, tz_values in enumerate(locale_time.timezone):
                if found_zone in tz_values:
                    # Deal with bad locale setup where timezone names are the
                    # same and yet time.daylight is true; too ambiguous to
                    # be able to tell what timezone has daylight savings
                    if (time.tzname[0] == time.tzname[1] and
                       time.daylight and found_zone not in ("utc", "gmt")):
                        break
                    else:
                        tz = value
                        break
    ................................................

    return (time.struct_time((year, month, day,
                              hour, minute, second,
                              weekday, julian, tz)), fraction)

# strptime方法的缺省格式是"%a %b %d %H:%M:%S %Y"
# 也就是"星期名缩写 月份名缩写 月份天数 小时:分钟:秒数 年份"
# 的格式。
def _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"):
    return _strptime(data_string, format)[0]


    以下是strptime方法的完整的例子:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> time.strptime('15-3-9', '%y-%m-%d')
time.struct_time(tm_year=2015, tm_mon=3, tm_mday=9, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=68, 
  tm_isdst=-1)
>>> time.strptime('2015-4-6', '%Y-%m-%d')
time.struct_time(tm_year=2015, tm_mon=4, tm_mday=6, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=96, 
  tm_isdst=-1)
>>> time.strptime('2015-4-6 14:15:16', '%Y-%m-%d %H:%M:%S')
time.struct_time(tm_year=2015, tm_mon=4, tm_mday=6, 
  tm_hour=14, tm_min=15, tm_sec=16, tm_wday=0, tm_yday=96, 
  tm_isdst=-1)
>>> time.strptime('2015-4-6 3:15:16 pm', '%Y-%m-%d %I:%M:%S %p')
time.struct_time(tm_year=2015, tm_mon=4, tm_mday=6, 
  tm_hour=15, tm_min=15, tm_sec=16, tm_wday=0, tm_yday=96, 
  tm_isdst=-1)
>>> time.strptime('September 10 Mon', '%B %d %a')
time.struct_time(tm_year=1900, tm_mon=9, tm_mday=10, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=253, 
  tm_isdst=-1)
>>> time.strptime('Sep 13 Monday', '%b %d %A')
time.struct_time(tm_year=1900, tm_mon=9, tm_mday=13, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=256, 
  tm_isdst=-1)
>>> time.strptime('Sep 13 Sunday', '%b %d %A')
time.struct_time(tm_year=1900, tm_mon=9, tm_mday=13, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=256, 
  tm_isdst=-1)
>>> time.strptime('Sep 13 0', '%b %d %w')
time.struct_time(tm_year=1900, tm_mon=9, tm_mday=13, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=256, 
  tm_isdst=-1)
>>> time.strptime('Sep 13 1', '%b %d %w')
time.struct_time(tm_year=1900, tm_mon=9, tm_mday=13, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=256, 
  tm_isdst=-1)
>>> time.strptime('2015 Sep 13 256', '%Y %b %d %j')
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=13, 
  tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=256, 
  tm_isdst=-1)
>>> time.strptime('CST 2015-1-8 13:14:15', '%Z %Y-%m-%d %H:%M:%S')
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=8, 
  tm_hour=13, tm_min=14, tm_sec=15, tm_wday=3, tm_yday=8, 
  tm_isdst=0)
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,M5.1.0,M10.5.0'
>>> time.tzset()
>>> time.strptime('DST 2015-1-8 13:14:15', '%Z %Y-%m-%d %H:%M:%S')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/_strptime.py", line 467, in _strptime_time
    return _strptime(data_string, format)[0]
  File "/usr/local/lib/python2.7/_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data 'DST 2015-1-8 13:14:15' does not match format '%Z %Y-%m-%d %H:%M:%S'
>>> import _strptime
>>> _strptime._TimeRE_cache = _strptime.TimeRE()
>>> _strptime._regex_cache.clear()
>>> time.strptime('DST 2015-1-8 13:14:15', '%Z %Y-%m-%d %H:%M:%S')
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=8, 
  tm_hour=13, tm_min=14, tm_sec=15, tm_wday=3, tm_yday=8, 
  tm_isdst=1)
>>> time.strptime('Sun Sep 13 13:14:15 2015')
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=13, 
  tm_hour=13, tm_min=14, tm_sec=15, tm_wday=6, tm_yday=256, 
  tm_isdst=-1)
>>> 


    如果使用os.environ['TZ']重新设置了时区后,在使用%Z格式前,需要先将_strptime模块里的_TimeRE_cache_regex_cache两个全局缓存进行清理(或者重新初始化),才能得到正确的结果。否则就容易出现 ValueError: time data ... does not match format ... 的错误。

tzset方法与os.environ['TZ']:

    先来看个简单的例子:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,M5.1.0,M10.5.0'
>>> time.tzset()
>>> time.tzname
('CST', 'DST')
>>> time.timezone
-28800
>>> time.altzone
-32400
>>> time.daylight
1
>>> 


    上面的tzname,timezone,altzone以及daylight都是time模块里的常量。

    tzname元组里存储了时区名,元组的第一项为非夏令时的时区名,第二项为夏令时的时区名。如果没采用夏令时的话,那么这两项会是相同的值。由于os.environ['TZ']被设置为了'CST-08DST-09...',因此,非夏令时的时区名就是CST,夏令时的时区名则是DST

    timezone常量里存储了本地非夏令时的时区与UTC标准时区之间的差值(以秒为单位)。由于os.environ['TZ']被设置为了'CST-08...',也就是相差8个小时,因此,time.timezone = -8 * 3600 = -28800 。

    altzone常量里存储了本地夏令时的时区与UTC标准时区之间的差值(以秒为单位)。由于os.environ['TZ']被设置为了'...DST-09...',也就是相差9个小时,因此,time.altzone = -9 * 3600 = -32400 。

    daylight常量的值表示当前环境下,是否存在夏令时,daylight为1表示存在夏令时,为0则表示不存在夏令时。

    这几个常量的值都是在inittimezone的C函数里进行设置的,该函数也位于Modules/timemodule.c文件里:

static void
inittimezone(PyObject *m) {
    ................................................
#else /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
#ifdef HAVE_STRUCT_TM_TM_ZONE
    {
#define YEAR ((time_t)((365 * 24 + 6) * 3600))
        time_t t;
        struct tm *p;
        long janzone, julyzone;
        char janname[10], julyname[10];
        // 得到当前所在年份的起始点的时间戳。
        t = (time((time_t *)0) / YEAR) * YEAR;
        p = localtime(&t);
        janzone = -p->tm_gmtoff;
        strncpy(janname, p->tm_zone ? p->tm_zone : "   ", 9);
        janname[9] = '\0';
        // 得到当前所在年份的中间点的时间戳,
        // 如果os.environ['TZ']设置的夏令时范围,
        // 没有包含这一年的中间点所在的日期时
        // (可能是7月几号,也有可能是8月几号等),
        // daylight就不会被设置为1,也就不会认为
        // 当前环境存在夏令时,altzone也不会被
        // 设置为夏令时的差值,tzname里也不会
        // 包含夏令时相关的时区名。
        // 这种情况下,即便os.environ['TZ']设置了
        // 夏令时,daylight与altzone也不会存储
        // 与夏令时相关的数值,
        // 当然localtime之类的会调用
        // C标准库函数的方法,还是会受到
        // os.environ['TZ']环境变量设置的夏令时范围的影响。
        // 因此,如果想让Python脚本完全支持夏令时的话,
        // os.environ['TZ']设置的夏令时范围最好包含了
        // 这一年的中间点所对应的日期在内。
        t += YEAR/2;
        p = localtime(&t);
        julyzone = -p->tm_gmtoff;
        strncpy(julyname, p->tm_zone ? p->tm_zone : "   ", 9);
        julyname[9] = '\0';

        if( janzone < julyzone ) {
            /* DST is reversed in the southern hemisphere */
            PyModule_AddIntConstant(m, "timezone", julyzone);
            PyModule_AddIntConstant(m, "altzone", janzone);
            PyModule_AddIntConstant(m, "daylight",
                                    janzone != julyzone);
            PyModule_AddObject(m, "tzname",
                               Py_BuildValue("(zz)",
                                             julyname, janname));
        } else {
            PyModule_AddIntConstant(m, "timezone", janzone);
            PyModule_AddIntConstant(m, "altzone", julyzone);
            PyModule_AddIntConstant(m, "daylight",
                                    janzone != julyzone);
            PyModule_AddObject(m, "tzname",
                               Py_BuildValue("(zz)",
                                             janname, julyname));
        }
    }
#else
#endif /* HAVE_STRUCT_TM_TM_ZONE */
#ifdef __CYGWIN__
    tzset();
    PyModule_AddIntConstant(m, "timezone", _timezone);
    PyModule_AddIntConstant(m, "altzone", _timezone-3600);
    PyModule_AddIntConstant(m, "daylight", _daylight);
    PyModule_AddObject(m, "tzname",
                       Py_BuildValue("(zz)", _tzname[0], _tzname[1]));
#endif /* __CYGWIN__ */
#endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
}


    time模块的tzset方法在执行时,会自动调用上面这个inittimezone的C函数,对time模块里的timezone,altzone,daylight及tzname常量进行更新。因此,在设置了os.environ['TZ']的环境变量后,就有必要再调用tzset方法来将time模块里的各常量值进行更新。

    os.environ['TZ']的具体格式,如下所示:

std offset [dst [offset [,start[/time], end[/time]]]]

    std表示本地非夏令时的时区名。

    std后面的offset则表示本地非夏令时的时区与UTC标准时区之间的偏移值,offset的格式为 hh[:mm[:ss]] 也就是"小时:分:秒"的格式,其中,分、秒是可选的。在offset前面加上'-'的前缀时,就表示当前时区是本初子午线以东的时区,否则就是本初子午线以西的时区。

    dst表示本地夏令时的时区名。

    dst后面的offset表示本地夏令时的时区与UTC标准时区之间的偏移值,其格式与std后面的offset的格式一致。如果没提供dst的offset的话,默认情况下,夏令时会比非夏令时快一个小时。

    start[/time], end[/time]表示从start开始到end为止,这段时间为夏令时。start与end有以下几种时间格式:

    1) 在字母J后面接一个整数(整数是1到365的范围),用于表示一年中的第几天。这里不考虑闰年,即在所有年份里,2月28日都是第59天,3月1日则都是第60天。如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,J59,J247'
>>> time.tzset()
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=3, tm_hour=19, tm_min=29, tm_sec=53, tm_wday=3, tm_yday=246, tm_isdst=1)
>>> 


    上面的os.environ['TZ'] = 'CST-08DST-09,J59,J247',就是将这一年的第59天到第247天之间的这段时间,设置为夏令时。

    2) 直接用整数来表示一年中的第几天(整数是0到365的范围,0表示这一年的第一天)。这种方式可以把闰年也考虑进去。如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,58,246'
>>> time.tzset()
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=3, tm_hour=19, tm_min=36, tm_sec=55, tm_wday=3, tm_yday=246, tm_isdst=1)
>>> 


    当直接使用整数时,由于0表示第一天。因此,上面的os.environ['TZ'] = 'CST-08DST-09,58,246',也表示将这一年的第59天到第247天之间的这段时间设置为夏令时。

    3) Mm.n.d的格式,该格式里的M是固定的前缀字符。

    m表示月份(1 <= m <= 12)。

    n表示该月份里的第几个星期。n的范围是1到5的数。1表示第一个星期,5表示该月的最后一个星期(如果一个月有4个星期,就表示第4个星期。如果一个月有5个星期,就表示第5个星期)。

    d表示星期几。d的范围是0到6的数:0表示星期天,1表示星期一,2表示星期二,以此类推。

    如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,M5.1.1,M9.1.5'
>>> time.tzset()
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=3, tm_hour=20, tm_min=56, tm_sec=24, tm_wday=3, tm_yday=246, tm_isdst=1)
>>> 


    上面的os.environ['TZ'] = 'CST-08DST-09,M5.1.1,M9.1.5'表示将5月4日到9月4日这段时间设置为夏令时。5月4日是2015年5月份的第一个星期里的星期一,与M5.1.1的定义相一致,而9月4日则是2015年9月份的第一个星期里的星期五,与M9.1.5的定义一致。

    以上就是start与end的三种格式,此外,start与end后面还可以接一个可选的time来表示当天的确切时间,time也是"时:分:秒"的格式。如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> import time
>>> import os
>>> os.environ['TZ'] = 'CST-08DST-09,J59/2:00:00,J246/22:00:00'
>>> time.tzset()
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=9, tm_mday=3, tm_hour=21, tm_min=15, tm_sec=18, tm_wday=3, tm_yday=246, tm_isdst=1)
>>> 


    上面的os.environ['TZ'] = 'CST-08DST-09,J59/2:00:00,J246/22:00:00' 表示从第59天的2:00:00开始,到第246天的22:00:00为止,这段时间会被设置为夏令时。

    如果没在start或end后面提供time的话,默认是2:00:00 。

结束语:

    以上就是和time模块相关的内容。

    月落乌啼霜满天,江枫渔火对愁眠。

    姑苏城外寒山寺,夜半钟声到客船。


——  枫桥夜泊
 
上下篇

下一篇: Python的calendar模块

上一篇: Python词典相关的脚本函数及方法

相关文章

Python的基本语法

Python元组类型及相关函数

Python基本的操作运算符

Python定义和使用模块

Python字符串相关的函数

Python的安装与使用