`
isiqi
  • 浏览: 16487145 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Linux环境(三)--日期与时间

阅读更多
时间与日期

通常对于一个程序来说可以确定时间与日期是十分用的。也许他要记录其运行的时间,或者是他要一个特定的时间改变其形为。例如,一个游戏程序也许不会在工作时间运行,或者是一个备份调度会在启动自动备份之前等待早些的工作完成。

所有的Unix系统对于时间与日期都使用相同的起始点:1970年1月1日午午夜GMT。这是Unix的创世纪,而Linux也不例外。而在Linux系统中所有的时间都是以秒记量的。这与MS-DOS处理时间的方式相似,所不同是MS-DOS是由1980年开始的。其他的系统使用其他的记时起始时间。

时间是使用一个定义的time_t类型来处理。这是一个足够大的整数类型来包含以秒计的日期与时间值。在Linux系统上,他是一个长整数,其定义以及相关的操作函数都定义在头文件time.h中。

不要认为时间是32位的。在Unix以及Linux系统上使用一个32位的time_t类型,而这个时间会在2038年重叠。到那时,我们希望这些系统都使用一个大于32位的time_t类型。

#include <time.h>
time_t time(time_t *tloc);

我们可以调用time函数来得到一个底层的时间值,这个函数会返回由纪元起点开始的秒数。如果tloc不为空指针,函数就会将返回值写入tloc所指的变量中。

试验--时间

这里是一个简单的时间程序,envtime.c,来演示time函数:

#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
time_t the_time;
for(i = 1; i <= 10; i++) {
the_time = time((time_t *)0);
printf(“The time is %ld\n”, the_time);
sleep(2);
}
exit(0);
}

当我们运行这个程序时,他会每隔2秒打印出底层时间值。

$ ./envtime
The time is 1044695820
The time is 1044695822
The time is 1044695824
The time is 1044695826
The time is 1044695828
The time is 1044695830
The time is 1044695832
The time is 1044695834
The time is 1044695836
The time is 1044695838

工作原量

这个程序使用一个空指针参数来调用time函数,这个函数会返回以秒计的时间与日期值。程序会休眠2秒,并且重复调用time函数10次。

使用由1970年开始的以秒计的时间与日期值对于估量某件事持续多少时间是十分有用的。我们只需要简单的使用两个由time调用得到的时间进行减法操作即可。然而结过仔细的考虑,ISO/ANSIC C标准委员会并没有说时time_t类型要用于计量以秒计的时间间隔值,所以他们开发了一个函数,difftime,这个函数会计算两个time_t值之间的间隔,并且返回一个double类型:

#include <time.h>
double difftime(time_t time1, time_t time2);

difftime函数计算两个时间值之间的间隔,并且返回time1-time2的浮点值。对于Linux系统而言,由time返回的值是秒数,并且可以进行操作,但是为了移植考虑,我们应使用difftime函数。

为了以更为有意义的方式来表示时间与日期,我们需要将时间值转换为可以识别的时间与日期。这有标准的函数可以帮助我们做到。

gmtime函数将底层的时间值分隔并且存放到包含更为通用域的一个结构中:

#include <time.h>
struct tm *gmtime(const time_t timeval);

tm结构的定义至少包含下列成员:

成员 描述
int tm_sec 秒,0-61
int tm_min 分,0-59
int tm_hour 时,0-23
int tm_mday 一月中的天,1-31
int tm_mon 一年中的月,0-11(一月为0)
int tm_year 由1900年起的年数
int tm_wday 一星期中的天,0-6(星期日为0)
int tm_yday 一年中的天,0-365
int tm_isdst 有效的白天数

试验--gmtime

这里有一个程序,gmtime.c,使用tm结构与gmtime函数打印当前时间与日期:

#include <time.h>
#include <stdio.h>
int main()
{
struct tm *tm_ptr;
time_t the_time;
(void) time(&the_time);
tm_ptr = gmtime(&the_time);
printf(“Raw time is %ld\n”, the_time);
printf(“gmtime gives:\n”);
printf(“date: %02d/%02d/%02d\n”,
tm_ptr->tm_year, tm_ptr->tm_mon+1, tm_ptr->tm_mday);
printf(“time: %02d:%02d:%02d\n”,
tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);
exit(0);
}

当我们运行这个程序时,我们会得到更可读的时间与日期值:

$ ./gmtime; date
Raw time is 1044696004
gmtime gives:
date: 103/02/08
time: 09:20:04
Sat Feb 8 09:20:04 GMT 2003

工作原理

这个程序调用time函数得到一个底层的时间值,然后调用gmtime将其转换为一个具有时间与日期值的结构。程序会使用printf函数打印输出。严格来讲,我们不应使用这种方式打印原始时间,因为并不能保证在所有的系统他都是一个long类型。在gmtime函数之后,我们立即运行date命令来比较其输出。

然而,在这里我们一个小问题。如果我们在一个不使用格林尼治时间的时区运行这个程序,或者是我们本地的白天存储时间是有效的(问题?),我们就会注意到这个时间并不正确。这是因为gmtime是使用GMT返回时间。Linux与Unix系统这样做,从而世界上的程序与系统都是同步的。不同时区在同一时间创建的文件会显示出具有相同的创建时间。要查看本地时间,我们需要使用localtime函数来代替。

#include <time.h>
struct tm *localtime(const time_t *timeval);

localtime函数与gmtime相同,所不同的是他会返回一个包含为本地时区进行过调整后的结构。如果我们再次试验gmtime程序,但是使用localtime函数来替换gmtime,我们就会看到一个正确的时间与日期报告。

要将一个打乱的tm结构转换为一个原始的time_t值,我们可以使用mktime函数:

#include <time.h>
time_t mktime(struct tm *timeptr);

如果结构不可以表示为一个time_t值,mktime函数会返回-1。

与date程序所提供的时间与日期等机器值相反,为了友好,我们可以使用asctime与ctime函数:

#include <time.h>
char *asctime(const struct tm *timeptr);
char *ctime(const time_t *timeval);

asctime函数返回一个代表tm结构timeptr给出的时间与日期的字符串。返回的字符串的格式如下:

Sun Jun 6 12:30:34 1999\n\0

他总是26个字符长的固定格式。函数ctime与下面的函数调用等同:

asctime(localtime(timeval))

他使用一个原始时间值作为参数,并将其转换为一个更可读的本地时间。

试验--ctime

让我们使用下面的代码来实际的看一下ctime:

#include <time.h>
#include <stdio.h>
int main()
{
time_t timeval;
(void)time(&timeval);
printf(“The date is: %s”, ctime(&timeval));
exit(0);
}

将其保存为ctim.c,编译运行,我们应可以看到下面的输出:

$ ./ctime
The date is: Sat Feb 8 09:21:17 2003

工作原理

ctime.c程序调用time函数来得到一个底层的时间值,然后让ctime来完成所有的困难工作,将其转换为一个可读的字符串并打印输出。

为了可以对实际的时间与日期字符串进行更多的控制,Linux与现代的类Unix系统提供了strftime函数。这与用在日期与时间上的sprintf函数相类似,且其工作方式也相似:

#include <time.h>
size_t strftime(char *s, size_t maxsize, const char *format, struct tm *timeptr);

strftime函数会格式化由timeptr指向的tm结构表示的时间与日期,并将其结构放在字符串s中。字符串被指明至少maxsize字符长。format字符串用来控制写入字符串的字符。与printf相似,他包含要传递到字符串的通常字符与格式化时间与日期元素的转义说明。转义说明包括:

转义符 描述
%a 简写的星期名
%A 全写的星期名
%b 简写的月名
%B 全写的月名
%c 日期与时间
%d 一月中的天,01-31
%H 时,00-23
%I 12小时时钟表示的小时,01-12
%j 一年中的天,001-366
%m 一年中的月,01-12
%M 分,00-59
%P a.m或p.m
%S 秒,00-61
%u 星期中的天,1-7(星期1为1)
%U 一年中的星期,01-53(星期日为一个星期的第一天)
%V 一年中的星期,01-53(星期一为一个星期的第一天)
%w 一个星期中的天,0-6(星期日为0)
%x 本地格式日期
%X 本地格式时间
%y 小于1900的年号
%Y 年
%Z 时区名字
%% A%字符

所以,由date程序所指定的通常日期对应于strftime中的格式化字符串为

“%a %b %d %H:%M:%S %Y”

为了有助于读取日期,我们可以使用strptime函数,这个函数会将一个表示日期与时间的字符串作为参数,并且创建一个表示同样日期与时间tm结构:

#include <time.h>
char *strptime(const char *buf, const char *format, struct tm *timeptr);

format字符串的组成与strftime的格式化字符串完全相同。strptime的动作形为与sscanf相似,因为他们都搜索字符串,查找标识的域,然后将他们写入变量。在这里的变量为依据格式化字符串要填充的tm结构的成员。然而,与strftime的转义字符比起来,strptime的转义字符是不严密的,因为strptime会在天与月上允许简写与全名两种形式。每一个表示都会匹配strptime中的一个%a说明符。strftime总是在小于10的数字上添加0,而strptime会将其看作可选的。

strptime会返回一个指向转换操作中最后一个处理字符之后的字符的指针。如果遇到不可以转换的字符,转换操作就简单的在那里停止。调用程序需要检测以确保所传递的字符都是可以写入tm结构的有意义的字符。

试验--strftime与strptime

下面我们看一下下面的程序中所使用的转义字符:

#include <time.h>
#include <stdio.h>
int main()
{
struct tm *tm_ptr, timestruct;
time_t the_time;
char buf[256];
char *result;
(void) time(&the_time);
tm_ptr = localtime(&the_time);
strftime(buf, 256, “%A %d %B, %I:%S %p”, tm_ptr);
printf(“strftime gives: %s\n”, buf);
strcpy(buf,”Sat 26 July 2003, 17:53 will do fine”);
printf(“calling strptime with: %s\n”, buf);
tm_ptr = &timestruct;
result = strptime(buf,”%a %d %b %Y, %R”, tm_ptr);
printf(“strptime consumed up to: %s\n”, result);
printf(“strptime gives:\n”);
printf(“date: %02d/%02d/%02d\n”,
tm_ptr->tm_year % 100, tm_ptr->tm_mon+1, tm_ptr->tm_mday);
printf(“time: %02d:%02d\n”,
tm_ptr->tm_hour, tm_ptr->tm_min);
exit(0);
}

当我们运行这个程序strftime.c时,我们会得到下面的输出:

$ ./strftime
strftime gives: Sunday 06 June, 11:55 AM
calling strptime with: Sat 26 July 2003, 17:53 will do fine
strptime consumed up to: will do fine
strptime gives:
date: 03/07/26
time: 17:53

工作原理

strftime程序通过调用time与localtime函数得到当前的本地时间。然后他通过使用一个合适的格式化字符串作为参数来调用strftime将其转换为可读的格式。为了演示strptime的用法,程序设置了一个包含日期与时间的字符串,然后调用strptime来得到原始的时间与日期值,并且打印输出。转义字符%R是strptime中%H:%M的简写形式。

在这里要注意的一点就是,为了可以成功的搜索一个日期,strptime函数需要一个精确的格式化字符串。通常,他并不会精确的搜索由用户读取的时间,除非这个格式是非常严格的。

也许当我们编译strftime.c时,编译器会提出警告。这是因为GNU库默认并没有声明strftime。这个问题的修正方法就是通过在包含time.h之前添加下面的行来显示的请求X/Open标准特征:

#define _XOPEN_SOURCE
分享到:
评论

相关推荐

    arm-linux-gcc-4.5.1-v6-vfp-20101103

    日期“20101103”表明这是2010年11月3日发布的产品,意味着它包含了那个时间点的最新技术。 交叉编译器是开发嵌入式系统中的关键工具,因为通常嵌入式设备的处理能力不足以在其上直接进行编译。arm-linux-gcc是针对...

    arm-linux-gcc-4.5.1-v6-vfp-20101103.gz

    5. **20101103**: 这个日期可能代表了编译器的发布或打包日期,通常用于区分不同时间点的编译器版本。 6. **博客中的qt移植**: 提到的博客内容可能涉及到使用这个交叉编译器将Qt(一个流行的跨平台应用程序开发框架...

    p27734982_112040_Linux-x86-64.zip

    2. 验证环境:确认系统是64位的Linux,并且已经安装了p13390677_112040补丁。 3. 应用补丁:根据“PatchSearch.xml”中的指示执行补丁,可能需要运行特定的脚本或命令。 4. 检查结果:应用补丁后,系统通常会进行...

    Linux环境OpenJDK8U-jdk-x64-linux-hotspot-8u372b07.tar.gz

    标题中的"Linux环境OpenJDK8U-jdk-x64-linux-hotspot-8u372b07.tar.gz"指的是在Linux操作系统环境下使用的OpenJDK 8的更新版本(Update 372,Build 7)的HotSpot虚拟机实现。OpenJDK是一个开源的Java开发工具包,它...

    p6880880_112000_Linux-x86-64.zip

    5. 完成后,OPatch会生成一个名为`opatch_output_&lt;日期&gt;.log`的日志文件,记录了整个安装过程的详细信息。务必保存此日志以备后续排查问题。 6. 重新启动Oracle服务,以使新补丁生效。 在安装补丁后,可以通过...

    android-sdk_r24.4.1-linux+jdk-8u144-linux-x64.rar

    还有默认方法,允许在接口中添加非抽象方法的实现,以及新的日期/时间API,提供了更强大和灵活的日期处理功能。对于Android开发,JDK 1.8是必需的,因为它是构建和运行Android应用的基础。 接下来是“android-sdk_r...

    p6880880_122010_Linux-x86-64.zip

    - 对于生产环境,应在非工作时间进行补丁应用,减少对业务的影响。 - 记录所有操作步骤和结果,以便于故障排查和审计。 5. **补丁的重要性:** - **安全增强:** 补丁能修复已知的安全漏洞,防止黑客攻击。 - *...

    linux-0.11-040327-rh9.diff.gz

    6. **应用补丁**:在Linux环境中,要应用这个补丁,首先需要使用`gunzip`命令解压缩,然后使用`patch`命令,指定原始的源代码文件和这个.diff文件,来将补丁应用到源代码上。 7. **版本控制**:在开源社区,这样的...

    Linux-JDK-1.8.zip

    - Date/Time API的增强:新的`java.time`包替代了原有的`java.util.Date`和`java.util.Calendar`,提供了更好的日期和时间处理功能。 **4. Hadoop与JDK** Hadoop是一个分布式文件系统(HDFS)和MapReduce计算框架,...

    jdk8 java8 linux版 jdk-8u162-linux-x64.tar.zip

    4. **Date和Time API改进**:全新的java.time包提供了更强大、更直观的日期和时间处理功能。 5. **方法引用**:可以引用类中的静态方法、实例方法或者构造函数,简化代码。 6. **Optional类**:用于表示可能为null...

    最新版linux jdk-8u291-linux-x64.tar.gz

    此外,JDK 8u291支持Java 8的特性,比如Lambda表达式、Stream API、新的日期和时间API等,这些都是现代Java开发中的关键元素。这些特性使得代码更加简洁、易读,并且提高了开发效率。 为了保持系统安全性并获取最新...

    jdk-8u211-linux-arm64-vfp-hflt.tar.gz aarch64 chroot linuxdeploy 64位linux

    总结来说,这个压缩包包含了一个针对64位ARM架构(aarch64)的Java 8更新211版本,它在Linux环境下,特别是CentOS 7的aarch64系统上,可以与"linuxdeploy"工具配合使用,用于在ARM设备上构建和部署应用程序。...

    最新版linux logstash-7.10.1-linux-x86_64.tar.gz

    总之,Logstash 7.10.1 是一个强大的日志管理和分析工具,尤其在Linux环境中,它能够帮助用户轻松收集、处理并发送日志数据,是构建企业级日志解决方案的关键组件。通过合理配置和优化,Logstash 可以显著提高日志...

    最新版linux jdk-8u251-linux-x64.tar.gz

    它引入了许多新特性,如Lambda表达式、函数式接口、Stream API和新的日期时间API,极大地提高了代码的简洁性和效率。因此,即便是发布多年后,JDK 1.8仍然是许多企业级应用的首选版本。 2. **Linux环境下的JDK安装*...

    jdk-8u261-linux-arm64-vfp-hflt.tar.gz

    日期与时间API的改进则使得处理日期和时间更加方便,避免了旧API中的复杂性和易错性。 在压缩包内,"jdk1.8.0_261"目录包含了所有必要的文件和子目录,如bin、conf、include、jre、lib等。其中,bin目录包含了可...

    最新版linux jdk-8u301-linux-x64.tar.gz

    在Linux环境下,开发者还可以利用JDK的命令行工具,如`jps`查看Java进程,`jstat`监控JVM统计信息,`jmap`用于内存映射,以及`jstack`用于生成线程堆栈跟踪,这些都是进行性能调优和问题排查的重要工具。 总的来说...

    qt-opensource-linux-x64-5.7.1.run.7z

    8. **国际化和本地化(i18n)**:Qt 5.7.1提供了完善的国际化支持,包括多语言资源管理和日期/时间格式化。 9. **信号和槽(Signals & Slots)机制**:这是Qt的核心特性之一,允许对象间安全、便捷地通信。 10. **...

    java-jdk1.8-jdk-8u181-linux-x64.zip

    在Linux环境下安装JDK 1.8步骤如下: 1. 首先,解压下载的zip文件。在终端中,你可以使用`unzip`命令来完成: ``` unzip java-jdk1.8-jdk-8u181-linux-x64.zip ``` 2. 解压后,你会看到一个名为`jdk-8u181-...

    jdk-8u40-linux-x64

    4. **日期和时间API**:取代了过时的java.util.Date和Calendar类,新的java.time包提供了更强大、更易用的日期和时间API,符合ISO-8601标准。 5. **默认方法**:接口中可以定义带实现的默认方法,允许不破坏向后...

    jdk-8u91-linux-x64.tar.gz

    - Date和Time API的改进:提供了一套新的日期和时间API,使得处理日期和时间更加方便和精确。 - Type接口:允许泛型擦除后的类型信息在运行时可获取。 7. **使用场景**: - 开发Java桌面应用、Web应用、移动应用...

Global site tag (gtag.js) - Google Analytics