您的位置:首页 > 编程语言 > C语言/C++

C语言中对时间和日期的处理

2007-06-14 19:19 399 查看
ChuckAllison是盐湖城圣LatterDay教堂总部下耶稣教堂家族历史研究处的软件体系设计师。他拥有数学学士和数学硕士学位。他从1975年起开始编程,从1984年起他开始从事c语言的教学和开发。他目前的兴趣是面向对象的技术及其教育。他是X3J16,ANSIC++标准化委员会的一员。发送e-mail到allison@decus.org,或者拨打电话到(801)240-4510均可以与他取得联系。
大部分的操作系统有办法得到当前的日期和时间。通过定义在time.h的库函数,ANSIC能以许多不同的形式得到这个信息。函数time返回一个类型为time_t的值(通常为long),该函数在运行期间对当前的日期和时间进行编码。然后你可以将这个返回值传递给其他能对该值进行解码和格式化的函数。
Listing1中的程序使用函数time,localtime和strftime以不同的形式输出当前的日期和时间。函数localtime把已经编码的时间解码成如下的struct:
structtm

{

inttm_sec;/*(0-61)*/

inttm_min;/*(0-59)*/

inttm_hour;/*(0-23)*/

inttm_mday;/*(1-31)*/

inttm_mon;/*(0-11)*/

inttm_year;/*past1900*/

inttm_wday;/*(0-6)*/

inttm_yday;/*(0-365)*/

inttm_isdst;/*daylightsavingsflag*/

};

每次当你调用localtime的时候,它会重写一个静态的结构并返回该结构的地址(因此同一时刻在一个程序中只能取得一个这样的结构,而不能做明显的拷贝)。函数ctime返回一个指向静态字符串的指针,该字符串以标准的格式包含了完整的时间和日期。strftime根据用户的指定格式格式化字符串(例如,%A代表一周中每一天的名称)。Table1列出了格式描述符的完整列表。

时间/日期运算

通过改变tm结构里的值,可对时间/日期进行运算。Listing2中的程序展示了如何计算将来某天的日期和以秒为单位所计算出的程序执行时间。注意函数time的语法(参数time_t由地址传入,并非作为函数的返回值)。函数mktime改变tm结构的值,以便日期和时间在一个合适的范围内,之后day-of-week(tm_wday)和day-of-year(tm_yday)域进行相应的更新。mktime将tm结构中日期和时间的值置于合适的范围之内,相应的更新dayofweek(tm-wday)和dayofyear(tm-yday)的值。这种情况发生在当一个日期超出了你的实现能够支持的范围的时候。例如,我的MS-DOS的编译器不能编码1970年1月份之前的日期。函数asctime返回tm参数所描述时间的标准字符串(因此ctime(&tval)与asctime(localtime(&tval)是相等的)。函数difftime返回用秒做单位的两个time_t的差。
如果需要处理超出系统范围的日期,或者需要计算两个日期的间隔又不是用秒来做单位,那你需要设计自己的date编码。Listing3到Listing5中的应用程序通过使用一个简单的month-day-year结构,展示了确定两个日期间隔的年数、月份数和天数的技术。日期的相减就像你在小学里做的减法那样(例如,首先进行天数的相减,如果需要就向月份数借位,以此类推)。注意跳过的年份都被计算进去了。为了简略起见,date_interval函数假设日期都是有效的,并且第一个日期在第二个日期之前。函数返回一个指向静态Date结构的指针,该结构包含了我们想要的答案。

文件时间/日期戳

大多数操作系统为文件维护时间/日期戳。至少你能得知一个文件最后被修改的时间。(常用的make工具使用这一信息来决定一个文件是否需要被重新编译,或者一个应用程序是否需要被重新连接)。由于文件系统在不同平台上有所不同,没有什么通用的函数得到一个文件的时间/日期戳,因此ANSI标准没有定义这样的函数。然而,大多数流行的操作系统(包括MS-DOS和VAX/VMS)提供了UNIX函数stat,该函数返回相关的文件信息,包括用time_t表示的最后修改时间。
Listing6中的程序使用stat和difftime来确定是否time1.c比time2.c更新(例如,是否最近被修改过)。
如果你需要更新一个文件的时间/日期戳到当前时间,可简单的重写文件的第一个字节。虽然实际内容并未改变,但你的文件系统会认为文件已经被改变了,并且会相应的更新时间/日期戳。(知道你的文件系统!在VAX/VMS下,当你得到一个文件的新版本的时候,旧的版本仍会被保留)。这种技术叫做“‘touching’一个文件”。Listing7中touch的实现在指定文件不存在的时候会创建一个新文件。注意文件以“binary”模式打开(在打开模式字符串中由字符b决定—在将来的专栏中我会详细讨论文件处理的问题)。

表1:strftime的格式描述符

CodeSampleOutput

---------------------------------------------

%aWed

%AWednesday

%bOct

%BOctober

%cWedOct0713:24:271992

%d07(dayofmonth[01-31])

%H13(hourin[00-23])

%I01(hourin[01-12])

%j281(dayofyear[001-366])

%m10(month[01-12])

%M24(minute[00-59])

%pPM

%S27(second[00-59])

%U40(Sundayweekofyear[00-52])

%w3(dayofweek[0-6])

%W40(Mondayweekofyear[00-52])

%xWedOct7,1992

%X13:24:27

%y92

%Y1992

%ZEDT(daylightsavingsindicator)

Listing1time1.c—采用不同格式输出当前的日期和时间

#include<stdio.h>

#include<time.h>


#defineBUFSIZE128


main()

{

time_ttval;

structtm*now;

charbuf[BUFSIZE];

char*fancy_format=

"Orgettingreallyfancy:/n"

"%A,%B%d,day%jof%Y./n"

"Thetimeis%I:%M%p.";


/*Getcurrentdateandtime*/

tval=time(NULL);

now=localtime(&tval);

printf("Thecurrentdateandtime:/n"

"%d/%02d/%02d%d:%02d:%02d/n/n",

now->tm_mon+1,now->tm_mday,now->tm_year,

now->tm_hour,now->tm_min,now->tm_sec);

printf("Orindefaultsystemformat:/n%s/n",

ctime(&tval));

strftime(buf,sizeofbuf,fancy_format,now);

puts(buf);


return0;

}


/*Output

Thecurrentdateandtime:

10/06/9212:58:00


Orindefaultsystemformat:

TueOct0612:58:001992


Orgettingreallyfancy:

Tuesday,October06,day280of1992.

Thetimeis12:58PM.

*/


/*EndofFile*/

Listing2time2.c—展示如何计算将来某一天的日期以及以秒为单位计算出的执行时间

#include<stdio.h>

#include<stdlib.h>

#include<time.h>


main()

{

time_tstart,stop;

structtm*now;

intndays;


/*Getcurrentdateandtime*/

time(&start);

now=localtime(&start);


/*Enteranintervalindays*/

fputs("Howmanydaysfromnow?",stderr);

if(scanf("%d",&ndays)!=1)

returnEXIT_FAILURE;

now->tm_mday+=ndays;

if(mktime(now)!=-1)

printf("Newdate:%s",asctime(now));

else

puts("Sorry.Can'tencodeyourdate.");


/*Calculateelapsedtime*/

time(&stop);

printf("Elapsedprogramtimeinseconds:%f/n",

difftime(stop,start));


returnEXIT_SUCCESS;

}


/*Output

Howmanydaysfromnow?45

Newdate:FriNov2012:40:321992

Elapsedprogramtimeinseconds:1.000000

*/


/*EndofFile*/

Listing3date.h—一个简单的日期结构

structDate

{

intday;

intmonth;

intyear;

};

typedefstructDateDate;


Date*date_interval(constDate*,constDate*);

/*EndofFile*/

Listing4date_int.c—计算两个日期的间隔

/*date_int.c:Computedurationbetweentwodates*/


#include"date.h"


#defineisleap(y)/

((y)%4==0&&(y)%100!=0||(y)%400==0)


staticintDtab[2][13]=

{

{0,31,28,31,30,31,30,31,31,30,31,30,31},

{0,31,29,31,30,31,30,31,31,30,31,30,31}

};


Date*date_interval(constDate*d1,constDate*d2)

{

staticDateresult;

intmonths,days,years,prev_month;


/*Computetheinterval-assumed1precedesd2*/

years=d2->year-d1->year;

months=d2->month-d1->month;

days=d2->day-d1->day;


/*Doobviouscorrections(daysbeforemonths!)

*

*Thisisaloopincasethepreviousmonthis

*February,anddays<-28.

*/

prev_month=d2->month-1;

while(days<0)

{

/*Borrowfromthepreviousmonth*/

if(prev_month==0)

prev_month=12;

--months;

days+=Dtab[isleap(d2->year)][prev_month--];

}


if(months<0)

{

/*Borrowfromthepreviousyear*/

--years;

months+=12;

}


/*Prepareoutput*/

result.month=months;

result.day=days;

result.year=years;

return&result;

}

/*EndofFile*/

Listing5tdate.c—举例说明日期间隔函数的使用

/*tdate.c:Testdate_interval()*/


#include<stdio.h>

#include<stdlib.h>

#include"date.h"


main()

{

Dated1,d2,*result;

intnargs;


/*Readintwodates-assume1stprecedes2nd*/

fputs("Enteradate,MM/DD/YY>",stderr);

nargs=scanf("%d/%d/%d%*c",&d1.month,

&d1.day,&d1.year);

if(nargs!=3)

returnEXIT_FAILURE;


fputs("Enteralaterdate,MM/DD/YY>",stderr);

nargs=scanf("%d/%d/%d%*c",&d2.month,

&d2.day,&d2.year);

if(nargs!=3)

returnEXIT_FAILURE;


/*Computeintervalinyears,months,anddays*/

result=date_interval(&d1,&d2);

printf("years:%d,months:%d,days:%d/n",

result->year,result->month,result->day);

returnEXIT_SUCCESS;


}

/*SampleExecution:

Enteradate,MM/DD/YY>10/1/51

Enteralaterdate,MM/DD/YY>10/6/92

years:41,months:0,days:5*/

/*EndofFile*/

Listing6ftime.c—确定是否time1.c比time2.c更新

/*ftime.c:Comparefiletimestamps*/


#include<stdio.h>

#include<stdlib.h>

#include<sys/stat.h>

#include<time.h>


main()

{

structstatfs1,fs2;


if(stat("time1.c",&fs1)==0&&

stat("time2.c",&fs2)==0)

{

doubleinterval=

difftime(fs2.st_mtime,fs1.st_mtime);


printf("time1.c%snewerthantime2.c/n",

(interval<0.0)?"is":"isnot");

returnEXIT_SUCCESS;

}

else

returnEXIT_FAILURE;

}

/*Output

time1.cisnotnewerthantime2.c*/

/*EndofFile*/

Listing7touch.c—通过覆盖旧文件或者创建一个新的文件来更新时间戳

/*touch.c:Updateafile'stimestamp*/


#include<stdio.h>


voidtouch(char*fname)

{

FILE*f=fopen(fname,"r+b");

if(f!=NULL)

{

charc=getc(f);

rewind(f);

putc(c,f);

}

else

fopen(fname,"wb");


fclose(f);

}


/*EndofFile*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: