With apologies to Steven Hawking :-)
In the beginning, there was… well, we don't know, because we weren't there to tweet about it. Without the internet, it was difficult to arrange things like hunting parties or afternoon tea. Most people woke up with the sun and slept when it was dark. The keeping of time was so sloppy that eventually winter stopped happening in winter, and something had to be done about it. In 1582 Pope Gregory XIII created our modern calendar, and centuries later most countries have adopted it. I'm not kidding about "centuries" either; Saudi Arabia only adopted it in 2016, and Britain waited until 1752 as can be seen by the weird calendar that year:
$ cal 9 1752 September 1752 Su Mo Tu We Th Fr Sa 1 2 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Despite this common calendar, we still didn't have the internet, and with the introduction of fast widespread travel, agreeing on the day wasn't enough. We had to agree on the time of day too. Since the time of day is different depending on where you are on the planet, time zones were created, and the world finally had a way to coordinate afternoon tea. Plus or minus leap seconds, but that's a different story.
And then there was Unix time
Computers like working with numbers (it's pretty much all they can do), but it's far easier to work with one large number than many small ones. So, instead of representing time as "year, month, day, hour, minute, second, timezone", early programmers chose to represent time as "seconds since Jan 1, 1970, GMT," and thus "Unix Time" (time_t) was born. Computers worldwide could easily coordinate their afternoon… er, tea? Well, they could timestamp messages, sort records by age, etc. Calculating elapsed time was as simple as subtracting two numbers.
Computers still had to interact with humans, though. Back in the dark ages of computing (i.e. pre-Internet, somewhere around 1987) mktime()
and its inverse localtime()
were written[1]. The mktime()
function converts calendar time to Unix time. It takes a year, month, day, hour, minute and second… and a tm_isdst
field? Doesn't the computer know when daylight saving time (DST) happens? Well, usually (and you can set tm_isdst to -1 most of the time), with one exception. Consider Sunday, November 6th in my timezone (America/Eastern). At 2:00 in the morning we "fall back" (reverse the clock) by an hour to transition from summer time (daylight saving time) to winter time (standard time), and the time from 1:00am to 2:00am is repeated. I repeat - the clock goes from 1:00 am to 2:00 am twice.
So if I ask mktime() to convert "Nov 6, 2022, 01:30:00" to a time_t, it needs to know *which* 01:30 I'm talking about. The tm_isdst field chooses one of those two wall clock times to convert to Unix time.
So most of the time, you can pass -1 and let the computer figure out whether DST is in effect, and if needed, set it to 0 or 1. But how do you know if it's needed? It turns out mktime() can tell you that. Let's look at the man page:
The mktime() function modifies the fields of the tm structure as
follows: ... tm_isdst is set (regardless of its initial value) to a
positive value or to 0, respectively, to indicate whether DST is or
is not in effect at the specified time.
Note that I'm referring to RHEL 8's man page and that other man pages may differ. The ISO spec may differ, too. A lot of the documentation is a bit vague, so let's try some calls and see what actually happens. Consider November 6, 2022, America/NewYork, which happens to be when the transition from DST to standard time happens, and the clocks go from 1:59 AM EDT to 1:00 AM EST. Here are some sample calls to mktime, showing what hour,› minute and DST are passed (tm_hour, tm_min, and tm_isdst) and what "fixed" values are in the structure after mktime() returns:

Ok, so that handles the normal cases, but what if we want more control over the transition period?

Ah! So, if you ask for a specific one of the overlap times, you can get it. What happens if you try this outside of a transition period?

With a bit of experimentation we've found enough consistency that we can choose at least one of two ways to get the results we want:
If it doesn't matter which of the two overlap times you get, set
tm_isdst
to -1. After the call,tm_isdst
will have a suitable value.If it does matter, call
mktime()
twice - once withtm_isdst
set to 0 and once set to 1. If both calls settm_isdst
to the same value, use thetime_t
for the call that had that value from the start. I.e. for one of the two calls,tm_isdst
will remain unchanged, and that's the "right" call. If the two calls return two differenttm_isdst
values, you have all the information you can get so you can choose one.
Here's some pseudo-code that changes the logic so that the tm_isdst
you pass is only a hint, and only to be used during overlap times:
time_t mktime_hint (struct tm *t_in): if (t_in->tm_isdst == -1) return mktime (t_in); t0 = *t_in; t0.tm_isdst = 0; ret0 = mktime (&t0); t1 = *t_in; t1.tm_isdst = 1; ret1 = mktime (&t1); if (t0.tm_isdst == t1.tm_isdst) { if (t0.tm_isdst == 0) *t_in = t0, return ret0; *t_in = t1, return ret1; } // it's an overlapped time, choose one and return it.
Caveats
Above, I quoted RHEL 8's man page for mktime()
. If you refer to the relevant standards, you'll find that the behavior of mktime()
is not clearly defined. Normally one would rely on the standards to define the behavior one relies on, but when the behavior is unspecified, one must experiment on and research the implementation itself. The above results are based on RHEL's C library, which is based on glibc, and glibc has a policy of "backward compatibility forever"[2], so we can consider our experimental results reliable. However, even RHEL and Fedora differ in what the tm_isdst field means. Defining "Daylight Saving Time" is actually up to each government which is highly political and, thus, inconsistent. It turns out that the only valid non-negative values for tm_isdst
are whatever values are returned by localtime()
. In Dublin's official timezone data, for example, tm_isdst
is zero in their summer and one in their winter, the opposite of the norm, but not on RHEL, which "normalizes" the data. If you lived in Dublin and used Fedora, and made an invalid assumption about tm_isdst
values, you would not be on time for tea.
Conclusion
When standards cover the functions you're using, follow them. Here we've needed to experiment to find out what RHEL does when the standards are vague. If you need to support other systems with other C libraries, you'll need to test those to see how they work. Go ahead, you've got time.
[1] The oldest reference I can find was a contribution to BSD by David Olson, so, thanks Dave!
[2] How the GNU C Library handles backward compatibility
Sobre o autor
DJ Delorie is a Principal Software Engineer at Red Hat.
Navegue por canal
Automação
Últimas novidades em automação de TI para empresas de tecnologia, equipes e ambientes
Inteligência artificial
Descubra as atualizações nas plataformas que proporcionam aos clientes executar suas cargas de trabalho de IA em qualquer ambiente
Nuvem híbrida aberta
Veja como construímos um futuro mais flexível com a nuvem híbrida
Segurança
Veja as últimas novidades sobre como reduzimos riscos em ambientes e tecnologias
Edge computing
Saiba quais são as atualizações nas plataformas que simplificam as operações na borda
Infraestrutura
Saiba o que há de mais recente na plataforma Linux empresarial líder mundial
Aplicações
Conheça nossas soluções desenvolvidas para ajudar você a superar os desafios mais complexos de aplicações
Programas originais
Veja as histórias divertidas de criadores e líderes em tecnologia empresarial
Produtos
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Red Hat Cloud Services
- Veja todos os produtos
Ferramentas
- Treinamento e certificação
- Minha conta
- Suporte ao cliente
- Recursos para desenvolvedores
- Encontre um parceiro
- Red Hat Ecosystem Catalog
- Calculadora de valor Red Hat
- Documentação
Experimente, compre, venda
Comunicação
- Contate o setor de vendas
- Fale com o Atendimento ao Cliente
- Contate o setor de treinamento
- Redes sociais
Sobre a Red Hat
A Red Hat é a líder mundial em soluções empresariais open source como Linux, nuvem, containers e Kubernetes. Fornecemos soluções robustas que facilitam o trabalho em diversas plataformas e ambientes, do datacenter principal até a borda da rede.
Selecione um idioma
Red Hat legal and privacy links
- Sobre a Red Hat
- Oportunidades de emprego
- Eventos
- Escritórios
- Fale com a Red Hat
- Blog da Red Hat
- Diversidade, equidade e inclusão
- Cool Stuff Store
- Red Hat Summit