La marca de tiempo Unix (Unix timestamp), también conocida como tiempo Unix (Unix time) o tiempo POSIX (POSIX time), es una forma de representar el tiempo, definida como el número total de segundos transcurridos desde las 00:00:00 del 01 de enero de 1970, hora de Greenwich, hasta el presente. La marca de tiempo Unix no solo se utiliza en sistemas Unix y sistemas tipo Unix, sino que también ha sido adoptada en muchos otros sistemas operativos.
Actualmente, una parte considerable de los sistemas operativos utilizan números binarios de 32 bits para representar el tiempo. La marca de tiempo Unix de dichos sistemas puede usarse como máximo hasta las 03:14:07 del 19 de enero de 2038, hora de Greenwich (binario: 01111111 11111111 11111111 11111111). Un segundo después, el número binario se convierte en 10000000 00000000 00000000 00000000, produciéndose un error de desbordamiento, lo que provoca que el sistema interprete erróneamente el tiempo como las 20:45:52 del 13 de diciembre de 1901. Esto puede causar fallos de software e incluso la parálisis del sistema. Los sistemas que utilizan números binarios de 64 bits para representar el tiempo (que pueden usarse como máximo hasta las 15:30:08 del 4 de diciembre de 292.277.026.596, hora de Greenwich) básicamente no encontrarán este tipo de problema de desbordamiento.
Primero comprendamos los conceptos relacionados con el tiempo y sus diferencias. Los conceptos de tiempo que necesitamos conocer son:
- Hora local (locale time)
- Hora de Greenwich (Greenwich Mean Time GMT)
- Tiempo Universal Coordinado (Universal Time Coordinated UTC)
La hora local, obviamente, no necesita explicación.
Primero veamos los estándares de tiempo:
(1) Tiempo universal
El tiempo universal fue el primer estándar de tiempo. En 1884, internacionalmente se determinó que 1s es 1/8.64×10^4 de la duración media diaria del año. El sistema de tiempo formado con este estándar se denomina tiempo universal, es decir, UT1. En 1972, la comunidad internacional comenzó a utilizar la escala de tiempo atómico internacional. Desde entonces, el tiempo que pasa por el meridiano de Greenwich del antiguo Observatorio de Greenwich se llama tiempo universal, es decir, UT2, o hora de Greenwich (GMT), que es el tiempo universal corregido por las diferencias periódicas en la velocidad de rotación de la Tierra.
(2) Tiempo atómico
En 1967, aprovechando la característica de que el período de oscilación del átomo de cesio es extremadamente regular, se desarrollaron relojes atómicos de alta precisión, y se definió como 1s el tiempo que tarda la radiación de transición de nivel de energía del átomo de cesio en completar 9.192.631.770 ciclos. El tiempo utilizado actualmente es el tiempo atómico internacional definido en octubre de 1971, que se obtiene comparando alrededor de más de 200 relojes atómicos en el mundo y luego procesando los datos en la oficina de tiempo de la Oficina Internacional de Pesas y Medidas, obteniendo un tiempo atómico unificado, abreviado como TAI.
(3) Tiempo Universal Coordinado
El tiempo universal coordinado es un estándar de tiempo basado en la rotación de la Tierra. Debido a que la velocidad de rotación de la Tierra no es uniforme, no todos los días son exactamente 86400 segundos atómicos, lo que provoca un error de 1 segundo cada 18 meses entre el tiempo de rotación y el tiempo universal. Para corregir este error, el Instituto Internacional de Rotación de la Tierra ajusta la hora de Greenwich sumando o restando segundos intercalares según la situación real de la rotación terrestre, y junto con la oficina de tiempo de la Oficina Internacional de Pesas y Medidas publica la hora estándar al mundo. Esto es el llamado tiempo universal coordinado (UTC: CoordinatdeUniversalTime). La forma de representación de UTC es: año (y), mes (m), día (d), hora (h), minuto (min), segundo (s), todos expresados con números.
En el sistema GPS hay dos tipos de tiempo: uno es UTC, el otro es LT (hora local). La diferencia entre ambos es la zona horaria. UTC es el tiempo del huso horario 0; la hora local es el tiempo local. Por ejemplo, si en Beijing son las ocho de la mañana (zona horaria UTC+8), la hora UTC sería las cero horas, ocho horas más tarde que la hora de Beijing. Con esto se puede calcular. Con lo anterior, podemos considerar que la hora de Greenwich es el tiempo universal coordinado (GMT = UTC). Tanto la hora de Greenwich como la hora UTC se calculan en segundos.
Y en nuestro trabajo diario, la mayoría de las horas que vemos en los registros de computadora se calculan usando la hora UTC. Entonces, ¿cómo podemos convertir la hora UTC en hora local para facilitar la revisión de los registros, y al desarrollar programas, cómo convertir la hora local en hora UTC?
A continuación presentamos una herramienta simple y práctica: usar el comando date de linux/unix para convertir entre la hora local y la hora UTC.
Como todos sabemos, el tiempo UTC que se ve en la computadora se calcula en segundos desde (01 de enero de 1970 0:00:00). El tiempo UTC que se ve es cuántos segundos han transcurrido desde ese punto en 1970 hasta el momento específico.
En la programación, a menudo usamos el tiempo, por ejemplo, obtener la hora del sistema (obtener año, mes, día, hora, minuto, segundo, día de la semana, etc. del sistema), o hacer algo después de un intervalo de tiempo, por lo que utilizamos algunas funciones de tiempo.
En Linux, hay dos formas comunes de almacenar el tiempo: una es cuántos segundos han pasado desde 1970 hasta ahora, y la otra es usar una estructura para almacenar por separado año, mes, día, hora, minuto, segundo.
El tipo time_t se utiliza para almacenar cuántos segundos han pasado desde 1970 hasta ahora. Si se quiere más precisión, se puede usar la estructura struct timeval, que tiene precisión de microsegundos.
struct timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
Y la estructura que almacena directamente año, mes, día es:
struct tm
{
int tm_sec; /*秒,正常范围0-59, 但允许至61*/
int tm_min; /*分钟,0-59*/
int tm_hour; /*小时, 0-23*/
int tm_mday; /*日,即一个月中的第几天,1-31*/
int tm_mon; /*月, 从一月算起,0-11*/ 1+p->tm_mon;
int tm_year; /*年, 从1900至今已经多少年*/ 1900+ p->tm_year;
int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
int tm_isdst; /*日光节约时间的旗标*/
};
Debemos tener especial cuidado: el año es cuántos años han transcurrido desde 1900 hasta el presente, no almacena directamente un año como 2011; el mes comienza desde 0, 0 representa enero; el día de la semana también comienza desde 0, 0 representa domingo, 1 representa lunes.
A continuación presentamos las funciones de tiempo que usamos comúnmente:
#include <time.h> char *asctime(const struct tm* timeptr);
Convierte la información de la estructura en el tiempo del mundo real, mostrándolo en forma de cadena.
char *ctime(const time_t *timep);
Convierte timep al tiempo del mundo real, mostrándolo como cadena. Su diferencia con asctime es que la forma de los parámetros pasados es diferente.
double difftime(time_t time1, time_t time2);
Devuelve la diferencia en segundos entre dos tiempos.
int gettimeofday(struct timeval *tv, struct timezone *tz);
Devuelve el número de segundos y microsegundos transcurridos desde 1970 hasta el presente; el parámetro tz es la zona horaria, generalmente no se usa.
struct tm* gmtime(const time_t *timep);
Convierte el tiempo representado por time_t en tiempo UTC sin conversión de zona horaria; es un puntero a estructura struct tm.
stuct tm* localtime(const time_t *timep);
Es similar a gmtime, pero es un tiempo que ha pasado por la conversión de zona horaria.
time_t mktime(struct tm* timeptr);
Convierte el tiempo de la estructura struct tm al número de segundos desde 1970 hasta el presente.
time_t time(time_t *t);
Obtiene el número de segundos desde el 1 de enero de 1970 hasta el presente.
Lo anterior es una introducción simple. A continuación, veamos el uso de estas funciones en la práctica:
/*gettime1.c*/
#include <time.h>
int main()
{
time_t timep;
time(&timep); /*获取time_t类型的当前时间*/
/*用gmtime将time_t类型的时间转换为struct tm类型的时间按,//没有经过时区转换的UTC时间
然后再用asctime转换为我们常见的格式 Fri Jan 11 17:25:24 2008
*/
printf("%s", asctime(gmtime(&timep)));
return 0;
}
Compilar y ejecutar:
$gcc -o gettime1 gettime1.c $./gettime1 Fri Jan 11 17:04:08 2008
A continuación se muestra cómo convertir directamente el tipo time_t a nuestro formato común:
/* gettime2.c*/
#include <time.h>
int main()
{
time_t timep;
time(&timep); /*获取time_t类型当前时间*/
/*转换为常见的字符串:Fri Jan 11 17:04:08 2008*/
printf("%s", ctime(&timep));
return 0;
}
Compilar y ejecutar:
$gcc -o gettime2 gettime2.c $./gettime2 Sat Jan 12 01:25:29 2008
Leí en un libro que si estos dos ejemplos se ejecutan uno tras otro, los resultados de ambos deberían ser iguales, excepto por la diferencia en los segundos (ya que ejecutar el programa requiere tiempo). Sin embargo, al ejecutarlos aquí, descubrí que diferían por mucho tiempo: uno era viernes y el otro sábado. Luego ejecuté el comando date una vez.
$ date 六 1月 12 01:25:19 CST 2008
Descubrí que date y gettime2 son bastante consistentes. Supongo que gettime1 no ha pasado por la conversión de zona horaria; hay diferencias entre ellos.
/*gettime3.c */
#include <time.h>
int main()
{
char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
time_t timep;
struct tm *p;
time(&timep); /*获得time_t结构的时间,UTC时间*/
p = gmtime(&timep); /*转换为struct tm结构的UTC时间*/
printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);
printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour,
p->tm_min, p->tm_sec);
return 0;
}
Compilar y ejecutar:
$gcc -o gettime3 gettime3.c $./gettime3 2008/1/11 Fri 17:42:54
Según este resultado de tiempo, se mantiene consistente con gettime1.
/*gettime4.c*/
#include <time.h>
int main()
{
char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
time_t timep;
struct tm *p;
time(&timep); /*获得time_t结构的时间,UTC时间*/
p = localtime(&timep); /*转换为struct tm结构的当地时间*/
printf("%d/%d/%d ", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday);
printf("%s %d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
return 0;
}
Compilar y ejecutar:
$gcc -o gettime4 gettime4.c $./gettime4 2008/1/12 Sat 1:49:29
Podemos decir lo siguiente a partir de los resultados anteriores:
Los tiempos representados por time, gmtime y asctime son todos tiempo UTC, solo que el tipo de dato es diferente.
Mientras que los tiempos representados por localtime y ctime son tiempos que han pasado por la conversión de zona horaria, y deberían ser consistentes con el tiempo CST que se muestra con el comando del sistema date.
/*gettime5.c*/
#include <time.h>
int main()
{
time_t timep;
struct tm *p;
time(&timep); /*当前time_t类型UTC时间*/
printf("time():%d\n",timep);
p = localtime(&timep); /*转换为本地的tm结构的时间按*/
timep = mktime(p); /*重新转换为time_t类型的UTC时间,这里有一个时区的转换*/ //by lizp 错误,没有时区转换, 将struct tm 结构的时间转换为从1970年至p的秒数
printf("time()->localtime()->mktime(): %d\n", timep);
return 0;
}
Compilar y ejecutar:
$gcc -o gettime5 gettime5.c $./gettime5 time():1200074913 time()->localtime()->mktime(): 1200074913
Aquí se convierte el tiempo UTC a hora local, y luego se convierte la hora local a tiempo UTC. Los resultados de la conversión se mantienen consistentes.
/*gettime6.c */
#include <time.h>
int main()
{
time_t timep;
struct tm *p;
time(&timep); /*得到time_t类型的UTC时间*/
printf("time():%d\n",timep);
p = gmtime(&timep); /*得到tm结构的UTC时间*/
timep = mktime(p); /*转换,这里会有时区的转换*/ //by lizp 错误,没有时区转换, 将struct tm 结构的时间转换为从1970年至p的秒数
printf("time()->gmtime()->mktime(): %d\n", timep);
return 0;
}
Compilar y ejecutar:
$gcc -o gettime6 gettime6.c $./gettime6 time():1200075192 time()->gmtime()->mktime(): 1200046392
De esto podemos ver que después de la conversión, los tiempos ya no son consistentes. Calculemos: la diferencia es exactamente 8 horas ((1200075192-1200046392)/3600 = 8). Esto demuestra que mktime convierte la hora local en tiempo UTC. Pero aquí originalmente ya era tiempo UTC, por lo que al hacer otra conversión de zona horaria, el resultado difiere en 8 horas. Se debe tener cuidado al usarlo.
La función strftime() formatea el tiempo.
Podemos usar la función strftime() para formatear el tiempo en el formato que queramos. Su prototipo es el siguiente:
size_t strftime(
char *strDest,
size_t maxsize,
const char *format,
const struct tm *timeptr
);
Podemos, según los comandos de formato en la cadena apuntada por format, colocar la información de tiempo almacenada en timeptr en la cadena apuntada por strDest, almacenando como máximo maxsize caracteres en strDest. Esta función devuelve el número de caracteres colocados en la cadena apuntada por strDest.
La operación de la función strftime() es algo similar a sprintf(): reconoce un conjunto de comandos de formato que comienzan con el signo de porcentaje (%) y coloca el resultado formateado en una cadena. Los comandos de formato especifican la representación exacta de la información de fecha y hora en la cadena strDest. Otros caracteres en la cadena de formato se colocan tal cual en la cadena. Los comandos de formato se enumeran a continuación; distinguen entre mayúsculas y minúsculas.
%a 星期几的简写 %A 星期几的全称 %b 月分的简写 %B 月份的全称 %c 标准的日期的时间串 %C 年份的后两位数字 %d 十进制表示的每月的第几天 %D 月/天/年 %e 在两字符域中,十进制表示的每月的第几天 %F 年-月-日 %g 年份的后两位数字,使用基于周的年 %G 年分,使用基于周的年 %h 简写的月份名 %H 24小时制的小时 %I 12小时制的小时 %j 十进制表示的每年的第几天 %m 十进制表示的月份 %M 十时制表示的分钟数 %n 新行符 %p 本地的AM或PM的等价显示 %r 12小时的时间 %R 显示小时和分钟:hh:mm %S 十进制的秒数 %t 水平制表符 %T 显示时分秒:hh:mm:ss %u 每周的第几天,星期一为第一天 (值从0到6,星期一为0) %U 第年的第几周,把星期日做为第一天(值从0到53) %V 每年的第几周,使用基于周的年 %w 十进制表示的星期几(值从0到6,星期天为0) %W 每年的第几周,把星期一做为第一天(值从0到53) %x 标准的日期串 %X 标准的时间串 %y 不带世纪的十进制年份(值从0到99) %Y 带世纪部分的十制年份 %z,%Z 时区名称,如果不能得到时区名称则返回空字符。 %% 百分号
Si se desea mostrar la hora actual y mostrarla en formato de 12 horas, como en el siguiente programa:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
char str[80];
lt=time(NULL);
ptr=localtime(<);
strftime(str,100,"It is now %I %p",ptr);
printf(str);
return 0;
}
El resultado de su ejecución es:
It is now 4PM
Y el siguiente programa muestra la fecha completa actual:
#include<stdio.h>
#include<string.h>
#include<time.h>
int main( void )
{
struct tm *newtime;
char tmpbuf[128];
time_t lt1;
time( <1 );
newtime=localtime(<1);
strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
printf(tmpbuf);
return 0;
}
Dirección de origen: http://blog.csdn.net/love_gaohz/article/details/6637625