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 nowes un valor entero sin ambigüedades, mientras que localy gmson struct tmque la información de fecha / hora legible tienda. Luego imprimo la información formateada (zona horaria) basada solo en los struct tmobjetos.
Según la referencia de cplusplus , los miembros de datos de struct tmson
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 tmcontiene, ¿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 HKTpara localy que la zona horaria es UTCpara gm?
Si eso no es todo lo que struct tmcontiene, 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.

tmno contiene información de zona horaria.strftimeobtiene 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ómostrftimesabe responder de diferentes maneras a dosstruct tmobjetos? A menos quetmcontenga alguna información como estatmes creada porlocaltime, quetmes creada porgmtime.tmestructura no almacena información de zona horaria, ¿qué te hace pensar que sí? La diferencia está más bien en las llamadas agmtime()ylocaltime().strftimediferencia a los tontos. Debería agregar que POSIX deja lo que sucede indefinido.tmcon información adicional. Aquí hay uno . Tenga en cuenta elconst char *tm_zonemiembro. ¿Para qué plataforma estás compilando? Eche un vistazo a latmimplementació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%Zrefleja 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_zoneabreviatura no está disponible:http://eel.is/c++draft/time.format#3
Excepto que el párrafo anterior no describe C
strftime, sino una nuevaformatfunción que opera enstd::chronotipos, notm. Además, hay un nuevo tipo:std::chrono::zoned_time( http://eel.is/c++draft/time.zone.zonedtime ) que siempre tiene disponible latime_zoneabreviatura (y el desplazamiento) y puede formatearse con laformatfunción mencionada anteriormente .Código de ejemplo:
(Descargo de responsabilidad:
formates 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 datelugar denamespace std::chrono.La biblioteca de vista previa se puede usar con C ++ 11 o posterior.
zoned_timetiene una plantillastd::chrono::durationque 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.hhayParece que
struct tmalmacena 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
localtimey entrestrftimeotras funciones.Por
strftimelo tanto, puede completar%zy%Zbasarse en esos datos globales, incluso si no se pasan como parte de unstruct tmvalor.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
localtimey 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_gmtoffy lostm_zonecampos 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_gmtoffy__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