Considere o seguinte 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;
}
Então armazenados em now
é um valor integral inequívoca, enquanto local
e gm
são struct tm
que armazenam informações de data / hora legível. Em seguida, imprimo as informações formatadas (fuso horário) com base apenas nos struct tm
objetos.
De acordo com a referência cplusplus , os membros dos dados struct tm
são
tm_sec
tm_min
tm_hour
tm_mday
tm_mon
tm_year
tm_wday
tm_yday
tm_isdst
Se isso é tudo o que a struct tm
contém, como o programa sabe as informações de fuso horário? Isto é, como ele sabe que o fuso horário é HKT
para local
, e que o fuso horário é UTC
para gm
?
Se isso não é tudo o que a struct tm
contém, explique como ele armazena informações de fuso horário.
A propósito, embora o código de demonstração esteja em C ++, acho que essa questão também é essencialmente uma questão C legítima.
tm
não contém informações de fuso horário.strftime
obtém o fuso horário pelo vodu nos bastidores. Se você deseja obter o fuso horário em geral, isso é uma bagunça. Existe ( atualmente ) nenhuma maneira padrão para obter um fuso horário. Felizmente Howard Hinnant está em que trabalho ... .tm
, comostrftime
saber responder de maneiras diferentes a doisstruct tm
objetos? A menos quetm
contém algumas informações como estetm
é criado porlocaltime
, quetm
é criado porgmtime
.tm
struct não armazena informações de fuso horário, o que faz você pensar que ele faz? A diferença está nas chamadas paragmtime()
elocaltime()
.strftime
distinguir os otários. Deve-se acrescentar que o POSIX deixa indefinido o que acontece.tm
s fora do padrão com informações extras. Aqui está um . Observe oconst char *tm_zone
membro. Para qual plataforma você está compilando? Dê uma olhada natm
implementação para ver se eles estenderam a estrutura.Respostas:
O padrão C diz em 7.27.1 Componentes do tempo:
(ênfase é minha)
Ou seja, as implementações têm permissão para adicionar membros adicionais
tm
, como você encontrouglibc/time/bits/types/struct_tm.h
. A especificação POSIX possui uma redação quase idêntica.O resultado é que
%Z
(ou mesmo%z
) não pode ser considerado portátilstrftime
. A especificação para%Z
reflete isso:Ou seja, os fornecedores podem levantar as mãos e simplesmente dizer: "nenhum fuso horário era determinável; portanto, não estou produzindo nenhum caractere".
Minha opinião: a API de tempo C é uma bagunça.
Estou tentando melhorar as coisas para o próximo padrão C ++ 20 na
<chrono>
biblioteca.A especificação do C ++ 20 altera isso de "sem caracteres" para uma exceção sendo lançada se a
time_zone
abreviação não estiver disponível:http://eel.is/c++draft/time.format#3
Exceto que o parágrafo acima não está descrevendo Cs
strftime
, mas uma novaformat
função que opera emstd::chrono
tipos, nãotm
. Além disso, existe um novo tipo:std::chrono::zoned_time
( http://eel.is/c++draft/time.zone.zonedtime ) que sempre tem atime_zone
abreviação (e deslocamento) disponível e pode ser formatada com aformat
função mencionada anteriormente .Código de exemplo:
(Isenção de responsabilidade: a sintaxe final da string de formatação na
format
função provavelmente será um pouco diferente, mas a funcionalidade estará lá.)Se você deseja experimentar uma prévia desta biblioteca, ela é gratuita e de código aberto aqui: https://github.com/HowardHinnant/date
Alguma instalação é necessária: https://howardhinnant.github.io/date/tz.html#Installation
Nesta visualização, você precisará usar o cabeçalho
"date/tz.h"
e o conteúdo da biblioteca está emnamespace date
vez denamespace std::chrono
.A biblioteca de visualização pode ser usada com C ++ 11 ou posterior.
zoned_time
é modelado em umstd::chrono::duration
que especifica a precisão do ponto no tempo e é deduzido no código de exemplo acima, usando o recurso CTAD do C ++ 17 . Se você estiver usando esta biblioteca de visualização no C ++ 11 ou C ++ 14, a sintaxe seria mais parecida com:Ou existe uma função auxiliar de fábrica não proposta para padronização que fará a dedução para você:
(#CTAD_eliminates_factory_functions)
fonte
Obrigado por todos os comentários à pergunta que ajudam a apontar para a direção certa. Eu posto algumas das minhas próprias pesquisas abaixo. Falo com base em um repositório arquivado da GNU C Library que encontrei no GitHub. A sua versão é
2.28.9000
.Em
glibc/time/bits/types/struct_tm.h
háParece que
struct tm
armazena informações de fuso horário, pelo menos nesta implementação.fonte
Uma das razões pelas quais a programação de data e hora é tão difícil é que é fundamentalmente pelo menos um problema um pouco difícil: "Trinta dias em setembro" e aritmética sexagesimal e fusos horários, horário de verão e anos bissextos, e nem vamos falar sobre segundos bissextos.
Mas a outra razão pela qual é difícil é que muitas bibliotecas e linguagens fazem uma bagunça perfeita, e C infelizmente não é exceção. (C ++ está tentando fazer melhor, como Howard menciona em sua resposta.)
Embora todo mundo saiba que variáveis globais são Ruim, as funções de data / hora de C usam basicamente algumas delas. Com efeito, o conceito de "fuso horário atual deste sistema" é uma variável global, e os dados globais que descreve esse fuso horário é compartilhada querendo ou não entre
localtime
estrftime
e uma série de outras funções.Assim, é
strftime
possível preencher%z
e com%Z
base nesses dados globais, mesmo que não sejam passados como parte de umstruct tm
valor.Obviamente, esse é um arranjo abaixo do ideal e começaria a causar problemas reais se houvesse uma maneira de um programa alterar dinamicamente o fuso horário que deseja usar
localtime
e o resto. (E esse arranjo persiste em parte porque na verdade não existe uma maneira padrão portátil e boa para um programa alterar o fuso horário local.)Ao longo dos anos, houve várias tentativas táticas de limpar parte da bagunça (preservando a compatibilidade com versões anteriores, é claro). Uma dessas tentativas envolve os campos estendidos
tm_gmtoff
etm_zone
descobertos nas versões de alguns sistemasstruct tm
. Essas adições são uma grande melhoria - não consigo imaginar fazer programação de data / hora em um sistema sem elas - mas ainda não são padrão e ainda existem muitos sistemas que não os possuem (nem mesmo com as grafias "ocultas"__tm_gmtoff
e__tm_zone
).Você pode ler muito mais sobre a história sórdida do suporte a data / hora em C neste artigo: Horário, Relógio e Programação de Calendário Em C , de Eric Raymond.
fonte