Considere el siguiente código C ++
#include <ctime>
#include <iostream>
int main()
{
std::time_t now = std::time(nullptr);
struct tm local = *std::localtime(&now);
struct tm gm = *std::gmtime(&now);
char str[20];
std::strftime(str, 20, "%Z", &local);
std::cout << str << std::endl; // HKT
std::strftime(str, 20, "%Z", &gm);
std::cout << str << std::endl; // UTC
return 0;
}
Así almacenada en now
es un valor entero sin ambigüedades, mientras que local
y gm
son struct tm
que la información de fecha / hora legible tienda. Luego imprimo la información formateada (zona horaria) basada solo en los struct tm
objetos.
Según la referencia de cplusplus , los miembros de datos de struct tm
son
tm_sec
tm_min
tm_hour
tm_mday
tm_mon
tm_year
tm_wday
tm_yday
tm_isdst
Si eso es todo lo que struct tm
contiene, ¿cómo sabe el programa que la información de la zona horaria de él? Es decir, ¿cómo sabe que la zona horaria es HKT
para local
y que la zona horaria es UTC
para gm
?
Si eso no es todo lo que struct tm
contiene, explique cómo almacena la información de la zona horaria.
Por cierto, aunque el código de demostración está en C ++, supongo que esta pregunta en esencia también es una pregunta C legítima.
tm
no contiene información de zona horaria.strftime
obtiene la zona horaria mediante el vudú detrás de escena. Si desea obtener la zona horaria en general, eso es un poco complicado. No existe ( actualmente ) una forma estándar de obtener una zona horaria. Afortunadamente Howard Hinnant es en ese trabajo ... .tm
, ¿cómostrftime
sabe responder de diferentes maneras a dosstruct tm
objetos? A menos quetm
contenga alguna información como estatm
es creada porlocaltime
, quetm
es creada porgmtime
.tm
estructura no almacena información de zona horaria, ¿qué te hace pensar que sí? La diferencia está más bien en las llamadas agmtime()
ylocaltime()
.strftime
diferencia a los tontos. Debería agregar que POSIX deja lo que sucede indefinido.tm
con información adicional. Aquí hay uno . Tenga en cuenta elconst char *tm_zone
miembro. ¿Para qué plataforma estás compilando? Eche un vistazo a latm
implementación para ver si han ampliado la estructura.Respuestas:
El estándar C dice en 7.27.1 Componentes del tiempo:
(el énfasis es mío)
Es decir, las implementaciones pueden agregar miembros adicionales a
tm
, como se encontró conglibc/time/bits/types/struct_tm.h
. La especificación POSIX tiene una redacción casi idéntica.El resultado es que
%Z
(o incluso%z
) no puede considerarse portátil enstrftime
. La especificación para%Z
refleja esto:Es decir, a los vendedores se les permite levantar las manos y simplemente decir: "ninguna zona horaria era determinable, por lo que no estoy mostrando ningún carácter".
Mi opinión: la API de sincronización C es un desastre.
Estoy intentando mejorar las cosas para el próximo estándar C ++ 20 dentro de la
<chrono>
biblioteca.La especificación C ++ 20 cambia esto de "sin caracteres" a una excepción que se genera si la
time_zone
abreviatura no está disponible:http://eel.is/c++draft/time.format#3
Excepto que el párrafo anterior no describe C
strftime
, sino una nuevaformat
función que opera enstd::chrono
tipos, notm
. Además, hay un nuevo tipo:std::chrono::zoned_time
( http://eel.is/c++draft/time.zone.zonedtime ) que siempre tiene disponible latime_zone
abreviatura (y el desplazamiento) y puede formatearse con laformat
función mencionada anteriormente .Código de ejemplo:
(Descargo de responsabilidad:
format
es probable que la sintaxis final de la cadena de formato en la función sea ligeramente diferente, pero la funcionalidad estará allí).Si desea experimentar con una vista previa de esta biblioteca, es gratuita y de código abierto aquí: https://github.com/HowardHinnant/date
Se requiere alguna instalación: https://howardhinnant.github.io/date/tz.html#Installation
En esta vista previa, deberá usar el encabezado
"date/tz.h"
, y los contenidos de la biblioteca están ennamespace date
lugar denamespace std::chrono
.La biblioteca de vista previa se puede usar con C ++ 11 o posterior.
zoned_time
tiene una plantillastd::chrono::duration
que especifica la precisión del punto de tiempo y se deduce en el código de ejemplo anterior utilizando la función CTAD de C ++ 17 . Si está utilizando esta biblioteca de vista previa en C ++ 11 o C ++ 14, la sintaxis se parecería más a:O hay una función auxiliar de fábrica no propuesta para la estandarización que hará la deducción por usted:
(#CTAD_eliminates_factory_functions)
fuente
Gracias por todos los comentarios a la pregunta que ayudan a señalar la dirección correcta. Publico algunas de mis propias investigaciones a continuación. Hablo basado en un repositorio archivado de la Biblioteca GNU C que encontré en GitHub. Su versión es
2.28.9000
.En
glibc/time/bits/types/struct_tm.h
hayParece que
struct tm
almacena información de zona horaria, al menos en esta implementación.fuente
Una de las razones por las que la programación de fecha y hora es tan difícil es que es fundamentalmente al menos un problema un tanto difícil: "Treinta días tiene septiembre", y la aritmética sexagesimal , y las zonas horarias, y el horario de verano, y los años bisiestos, y ni siquiera hablamos de segundos bisiestos.
Pero la otra razón por la que es difícil es que demasiadas bibliotecas e idiomas hacen un desastre perfecto, y C desafortunadamente no es una excepción. (C ++ está tratando de hacerlo mejor, como Howard menciona en su respuesta).
Aunque todo el mundo sabe que las variables globales son malas, las funciones de fecha / hora de C básicamente usan un par de ellas. En efecto, el concepto de "zona horaria actual de este sistema" es una variable global, y los datos globales que describen esa zona horaria se comparten entre
localtime
y entrestrftime
otras funciones.Por
strftime
lo tanto, puede completar%z
y%Z
basarse en esos datos globales, incluso si no se pasan como parte de unstruct tm
valor.Obviamente, esa es una disposición subóptima, y comenzaría a causar problemas reales si un programa cambiara dinámicamente la zona horaria que desea usar
localtime
y el resto. (Y esta disposición persiste en parte porque en realidad no hay una buena forma estándar y portátil para que un programa cambie la zona horaria local que está usando).A lo largo de los años ha habido varios intentos poco entusiastas para limpiar parte del desorden (conservando la compatibilidad con versiones anteriores, por supuesto). Uno de esos intentos involucra la extensión
tm_gmtoff
y lostm_zone
campos que has descubierto en las versiones de algunos sistemasstruct tm
. Esas adiciones son una gran mejora, no puedo imaginar hacer una programación seria de fecha / hora en un sistema sin ellas, pero aún no son estándar, y todavía hay muchos sistemas que no las tienen (ni siquiera con la ortografía "oculta"__tm_gmtoff
y__tm_zone
).Puede leer mucho más sobre el sórdido historial de soporte de fecha / hora en C en este documento: Programación de hora, reloj y calendario en C , por Eric Raymond.
fuente