strftime,是一种C库函数,strftime() 函数根据区域设置格式化本地时间/日期,函数的功能将时间格式化,或者说格式化一个时间字符串。
strftime在头文件<time.h>中包含,首先看一下time.h的源代码(取自minix2.0版):
/* The <time.h> header is used by the procedures that deal with time.
* Handling time is surprisingly complicated, what with GMT, local time
* and other factors. Although the Bishop of Ussher (1581-1656) once
* calculated that based on the Bible, the world began on 12 Oct. 4004 BC
* at 9 o'clock in the morning, in the UNIX world time begins at midnight,
* 1 Jan. 1970 GMT. Before that, all was NULL and (void).
*/
#ifndef _TIME_H
#define _TIME_H
#define CLOCKS_PER_SEC 60 /* MINIX always uses 60 Hz, even in Europe */
#ifdef _POSIX_SOURCE
#define CLK_TCK CLOCKS_PER_SEC /* obsolescent name for CLOCKS_PER_SEC */
#endif
#define NULL ((void *)0)
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned int size_t;
#endif
#ifndef _TIME_T
#define _TIME_T
typedef long time_t; /* time in sec since 1 Jan 1970 0000 GMT */
#endif
#ifndef _CLOCK_T
#define _CLOCK_T
typedef long clock_t; /* time in ticks since process started */
#endif
struct tm {
int tm_sec; /* seconds after the minute [0, 59] */
int tm_min; /* minutes after the hour [0, 59] */
int tm_hour; /* hours since midnight [0, 23] */
int tm_mday; /* day of the month [1, 31] */
int tm_mon; /* months since January [0, 11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday [0, 6] */
int tm_yday; /* days since January 1 [0, 365] */
int tm_isdst; /* Daylight Saving Time flag */
};
extern char *tzname[];
/* Function Prototypes. */
#ifndef _ANSI_H
#include <ansi.h>
#endif
_PROTOTYPE( clock_t clock, (void) );
_PROTOTYPE( double difftime, (time_t _time1, time_t _time0) );
_PROTOTYPE( time_t mktime, (struct tm *_timeptr) );
_PROTOTYPE( time_t time, (time_t *_timeptr) );
_PROTOTYPE( char *asctime, (const struct tm *_timeptr) );
_PROTOTYPE( char *ctime, (const time_t *_timer) );
_PROTOTYPE( struct tm *gmtime, (const time_t *_timer) );
_PROTOTYPE( struct tm *localtime, (const time_t *_timer) );
_PROTOTYPE( size_t strftime, (char *_s, size_t _max, const char *_fmt,
const struct tm *_timep) );
#ifdef _POSIX_SOURCE
_PROTOTYPE( void tzset, (void) );
#endif
#ifdef _MINIX
_PROTOTYPE( int stime, (time_t *_top) );
#endif
#endif /* _TIME_H */
对上面的代码做几点解释:
1、typedef long time_t;
这个time_t表示从 1970.01.01 00:00 (格林尼治时间) 开始到现在的秒数
2、typedef long clock_t;
clock_t表示进程开始到现在的滴答数
3、结构体tm
struct tm {
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst为负。*/
};
下面具体看一下strftime函数的源代码(strftime.c):
/*
* strftime - convert a structure to a string, controlled by an argument
*/
/* $Header: strftime.c,v 1.3 91/04/22 13:21:03 ceriel Exp $ */
#include <time.h>
#include "loc_time.h"
/* The width can be -1 in both s_prnt() as in u_prnt(). This
* indicates that as many characters as needed should be printed.
*/
static char *
s_prnt(char *s, size_t maxsize, const char *str, int width)
{
while (width > 0 || (width < 0 && *str)) {
if (!maxsize) break;
*s++ = *str++;
maxsize--;
width--;
}
return s;
}
static char *
u_prnt(char *s, size_t maxsize, unsigned val, int width)
{
int c;
c = val % 10;
val = val / 10;
if (--width > 0 || (width < 0 && val != 0))
s = u_prnt(s, (maxsize ? maxsize - 1 : 0), val, width);
if (maxsize) *s++ = c + '0';
return s;
}
size_t
strftime(char *s, size_t maxsize,
const char *format, const struct tm *timeptr)
{
size_t n;
char *firsts, *olds;
if (!format) return 0;
_tzset(); /* for %Z conversion */
firsts = s;
while (maxsize && *format) {
while (maxsize && *format && *format != '%') {
*s++ = *format++;
maxsize--;
}
if (!maxsize || !*format) break;
format++;
olds = s;
switch (*format++) {
case 'a':
s = s_prnt(s, maxsize,
_days[timeptr->tm_wday], ABB_LEN);
maxsize -= s - olds;
break;
case 'A':
s = s_prnt(s, maxsize, _days[timeptr->tm_wday], -1);
maxsize -= s - olds;
break;
case 'b':
s = s_prnt(s, maxsize,
_months[timeptr->tm_mon], ABB_LEN);
maxsize -= s - olds;
break;
case 'B':
s = s_prnt(s, maxsize, _months[timeptr->tm_mon], -1);
maxsize -= s - olds;
break;
case 'c':
n = strftime(s, maxsize,
"%a %b %d %H:%M:%S %Y", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'd':
s = u_prnt(s, maxsize, timeptr->tm_mday, 2);
maxsize -= s - olds;
break;
case 'H':
s = u_prnt(s, maxsize, timeptr->tm_hour, 2);
maxsize -= s - olds;
break;
case 'I':
s = u_prnt(s, maxsize,
(timeptr->tm_hour + 11) % 12 + 1, 2);
maxsize -= s - olds;
break;
case 'j':
s = u_prnt(s, maxsize, timeptr->tm_yday + 1, 3);
maxsize -= s - olds;
break;
case 'm':
s = u_prnt(s, maxsize, timeptr->tm_mon + 1, 2);
maxsize -= s - olds;
break;
case 'M':
s = u_prnt(s, maxsize, timeptr->tm_min, 2);
maxsize -= s - olds;
break;
case 'p':
s = s_prnt(s, maxsize,
(timeptr->tm_hour < 12) ? "AM" : "PM", 2);
maxsize -= s - olds;
break;
case 'S':
s = u_prnt(s, maxsize, timeptr->tm_sec, 2);
maxsize -= s - olds;
break;
case 'U':
s = u_prnt(s, maxsize, /* ??? */
(timeptr->tm_yday + 7 - timeptr->tm_wday) / 7, 2);
maxsize -= s - olds;
break;
case 'w':
s = u_prnt(s, maxsize, timeptr->tm_wday, 1);
maxsize -= s - olds;
break;
case 'W':
s = u_prnt(s, maxsize, /* ??? */
(timeptr->tm_yday+7-(timeptr->tm_wday+6)%7)/7,2);
maxsize -= s - olds;
break;
case 'x':
n = strftime(s, maxsize, "%a %b %d %Y", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'X':
n = strftime(s, maxsize, "%H:%M:%S", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'y':
s = u_prnt(s, maxsize, timeptr->tm_year % 100, 2);
maxsize -= s - olds;
break;
case 'Y':
s = u_prnt(s, maxsize, timeptr->tm_year + YEAR0, -1);
maxsize -= s - olds;
break;
case 'Z':
s = s_prnt(s, maxsize,
_tzname[(timeptr->tm_isdst > 0)], -1);
maxsize -= s - olds;
break;
case '%':
*s++ = '%';
maxsize--;
break;
default:
/* A conversion error. Leave the loop. */
while (*format) format++;
break;
}
}
if (maxsize) {
*s = '\0';
return s - firsts;
}
return 0; /* The buffer is full */
}
有个函数_tzset()引起了我的注意,这个函数的源代码在misc.c中:
void
_tzset(void)
{
#if defined(__BSD4_2)
struct timeval tv;
struct timezone tz;
_gettimeofday(&tv, &tz);
_daylight = tz.tz_dsttime;
_timezone = tz.tz_minuteswest * 60L;
#elif !defined(_POSIX_SOURCE) && !defined(__USG)
#if !defined(_MINIX) /* MINIX has no ftime() */
struct timeb time;
_ftime(&time);
_timezone = time.timezone * 60L;
_daylight = time.dstflag;
#endif
#endif /* !_POSIX_SOURCE && !__USG */
parseTZ(getenv("TZ")); /* should go inside #if */
#if defined(__USG) || defined(_POSIX_SOURCE)
tzname[0] = _tzname[0];
tzname[1] = _tzname[1];
#if defined(__USG)
timezone = _timezone;
daylight = _daylight;
#endif
#endif /* __USG || _POSIX_SOURCE */
}
参见linux文档:http://www.man7.org/linux/man-pages/man3/tzset.3.html
The tzset() function initializes the tzname variable from the TZ environment variable. This function is automatically called by the other time conversion functions that depend on the timezone. In a System-V-like environment, it will also set the variables timezone (seconds West of UTC) and daylight (to 0 if this timezone does not have any daylight saving time rules, or to nonzero if there is a time during the year when daylight saving time applies).
可见这个函数的主要是起到初始化时区环境的作用,经常配合其他函数一起使用。知道这个就可以了,太深入的话非得扯到POSIX等等
经过我注释后的代码如下:
/*
* strftime - convert a structure to a string, controlled by an argument
*/
/* $Header: strftime.c,v 1.3 91/04/22 13:21:03 ceriel Exp $ */
#include <time.h>
#include "loc_time.h"
/* The width can be -1 in both s_prnt() as in u_prnt(). This
* indicates that as many characters as needed should be printed.
*/
//将字符串str中的width个字符复制到maxsize字符串数组中
//前提:width <= strlen(str)
//if(maxsize >= width)全部复制
//else 复制maxsize个字符
static char *
s_prnt(char *s, size_t maxsize, const char *str, int width)
{
while (width > 0 || (width < 0 && *str)) {
if (!maxsize) break;
*s++ = *str++;
maxsize--;
width--;
}
return s;
}
/*
val=256 width=5 maxsize=5
1 c=6 val=25 width=4 maxsize=4
2 c=5 val=2 width=3 maxsize=3
3 c=2 val=0 width=2 maxsize=2
4 c=0 val=0 width=1 maxsize=1
5 c=0 val=0 width=0 maxsize=0
*/
//运用递归,将val转化为宽度为width的字符
//val的位数<width,前面补0
static char *
u_prnt(char *s, size_t maxsize, unsigned val, int width)
{
int c;
c = val % 10; //保留val除法后的尾数
val = val / 10; //保留商
if (--width > 0 || (width < 0 && val != 0))
s = u_prnt(s, (maxsize ? maxsize - 1 : 0), val, width);
if (maxsize) *s++ = c + '0';
return s;
}
//我们可以根据format指向字符串中格式命令把timeptr中保存的时间信息放在s指向的字符串中,
//最多向s中存放maxsize个字符。该函数返回向s指向的字符串中放置的字符数。
size_t
strftime(char *s, size_t maxsize,
const char *format, const struct tm *timeptr)
{
size_t n;
char *firsts, *olds;
if (!format) return 0; //format为空,不显示
_tzset(); /* for %Z conversion */
firsts = s;
while (maxsize && *format) {
while (maxsize && *format && *format != '%') {
*s++ = *format++;
maxsize--;
}
if (!maxsize || !*format) break; //当max减为0或format结束的时候退出
format++; //确保上面的while循环是由于遇到format的%字符而退出
olds = s;
switch (*format++) { //遇到相关的字符做相应的处理
case 'a':
s = s_prnt(s, maxsize,
_days[timeptr->tm_wday], ABB_LEN);
maxsize -= s - olds;
break;
case 'A':
s = s_prnt(s, maxsize, _days[timeptr->tm_wday], -1);
maxsize -= s - olds;
break;
case 'b':
s = s_prnt(s, maxsize,
_months[timeptr->tm_mon], ABB_LEN);
maxsize -= s - olds;
break;
case 'B':
s = s_prnt(s, maxsize, _months[timeptr->tm_mon], -1);
maxsize -= s - olds;
break;
case 'c':
n = strftime(s, maxsize,
"%a %b %d %H:%M:%S %Y", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'd':
s = u_prnt(s, maxsize, timeptr->tm_mday, 2);
maxsize -= s - olds;
break;
case 'H':
s = u_prnt(s, maxsize, timeptr->tm_hour, 2);
maxsize -= s - olds;
break;
case 'I':
s = u_prnt(s, maxsize,
(timeptr->tm_hour + 11) % 12 + 1, 2);
maxsize -= s - olds;
break;
case 'j':
s = u_prnt(s, maxsize, timeptr->tm_yday + 1, 3);
maxsize -= s - olds;
break;
case 'm':
s = u_prnt(s, maxsize, timeptr->tm_mon + 1, 2);
maxsize -= s - olds;
break;
case 'M':
s = u_prnt(s, maxsize, timeptr->tm_min, 2);
maxsize -= s - olds;
break;
case 'p':
s = s_prnt(s, maxsize,
(timeptr->tm_hour < 12) ? "AM" : "PM", 2);
maxsize -= s - olds;
break;
case 'S':
s = u_prnt(s, maxsize, timeptr->tm_sec, 2);
maxsize -= s - olds;
break;
case 'U':
s = u_prnt(s, maxsize, /* ??? */
(timeptr->tm_yday + 7 - timeptr->tm_wday) / 7, 2);
maxsize -= s - olds;
break;
case 'w':
s = u_prnt(s, maxsize, timeptr->tm_wday, 1);
maxsize -= s - olds;
break;
case 'W':
s = u_prnt(s, maxsize, /* ??? */
(timeptr->tm_yday+7-(timeptr->tm_wday+6)%7)/7,2);
maxsize -= s - olds;
break;
case 'x':
n = strftime(s, maxsize, "%a %b %d %Y", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'X':
n = strftime(s, maxsize, "%H:%M:%S", timeptr);
if (n) maxsize -= n;
else maxsize = 0;
s += n;
break;
case 'y':
s = u_prnt(s, maxsize, timeptr->tm_year % 100, 2);
maxsize -= s - olds;
break;
case 'Y':
s = u_prnt(s, maxsize, timeptr->tm_year + YEAR0, -1);
maxsize -= s - olds;
break;
case 'Z':
s = s_prnt(s, maxsize,
_tzname[(timeptr->tm_isdst > 0)], -1);
maxsize -= s - olds;
break;
case '%':
*s++ = '%';
maxsize--;
break;
default:
/* A conversion error. Leave the loop. */
while (*format) format++;
break;
}
}
if (maxsize) {
*s = '\0';
return s - firsts;
}
return 0; /* The buffer is full */
}
#include<stdio.h>
#include<time.h>
int main()
{
time_t t;
struct tm *pCurrentTime;
char dateBuffer[32];
t = time(NULL);
pCurrentTime = localtime(&t);
strftime(dateBuffer, sizeof(dateBuffer), "[%Y-%m-%d %X]", pCurrentTime);
printf("%s\n", dateBuffer);
return 0;
}
输出结果如下:
[2015-11-26 16:49:14]

非常详细