C++ function that converts time(NULL) to local time - c++

In C++ I'm writing a function that converts time(NULL), which is all the seconds since January 1, 1970 in UTC time, to local time EST in military time format (hours:minutes:seconds). I'm honestly stumped how to mathematically do this so that the program stays accurate as time moves forward.
Also I'm well aware that there is a local time function but I'd like to build this function from the ground up. Does anyone have any advice or tips?

Also I'm well aware that there is a local time function but I'd like to build this function from the ground up. Does anyone have any advice or tips?
Why would you want to do this when there are plenty of free and well-tested packages? As mentioned in the comments, getting daylight savings time correct is non-trivial. Existing packages do just that, and they do it right, based on the IANA tzinfo database.
C options:
std::localtime(). This function uses a global variable; it is not thread safe.
localtime_r(). This is a POSIX function and is not a part of the C++ library. It does not exist on Windows.
localtime_s(). This is an optional C11 function. Even if it exists on your machine, it might not be a part of <ctime>.
C++ options:
Boost Date-Time, https://github.com/boostorg/date_time .
Howard Hinant's date-time module, https://github.com/HowardHinnant/date .

localtime() from glibc should do the job of calculating the date, provided the environment is set to the correct timezone; else use gmtime(). Building a string from the values is a separate job, see strftime() for that.
http://linux.die.net/man/3/localtime

If you want to learn about the algorithms for converting a count of days to a year/month/day triple (and back), here they are, highly optimized, explained in pains-taking detail (don't read while operating heavy machinery):
http://howardhinnant.github.io/date_algorithms.html
You should also know that most (all?) implementations of time() track an approximation of UTC called Unix Time. This count treats leap seconds simply as clock corrections to an imperfect clock. That means you can ignore the effect of leap seconds when converting Unix Time seconds to days (just divide by 86400).
For converting to EST, you have some choices (in order of increasing difficulty and accuracy):
You can ignore daylight savings time and always take the offset as -5 hours.
You can assume the current daylight savings rules, ignoring the fact that they have changed many times in the past, and will likely change again.
You can get the past and present rules from the IANA timezone database,
or your OS's local equivalent.

There are two things which you will need to consider:
1. Leap years
One extra day in a year, that is possible to calculate mathematically.
2. Leap seconds
Seconds inserted or removed as needed (so a minute can have 61 or 59 seconds).
Those are irregular and you will need a lookup table for them. Otherwise your conversion routine will not be correct.
List of them is available for example here: https://en.wikipedia.org/wiki/Leap_second

Related

Leap seconds and std::chrono

I took a look att cppreference.org (emphasis mine):
The clock std::chrono::utc_clock is a Clock that represents Coordinated Universal Time (UTC). It measures time since 00:00:00 UTC, Thursday, 1 January 1970, including leap seconds.
Comparing that to the definition of system_clock:
system_clock measures Unix Time (i.e., time since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds).
Is it actually possible to have both in the same system? For example, if the system clock is synchronized via NTP, then the server decides what time it is, and that could use leap seconds or not, but the C++ library implementation cannot know anything about that. Or, does the standard require a database over when a leap second was introduced?
NTP servers give you UTC (in a seconds-since-1900 format). The current time, is the current time. It doesn't really matter how many leap seconds there have been in order to get there.
Where things get complicated is when a leap second is added. NTP will announce this in the moment, and various operating systems do various things internally to record that, owing to their propensity to store time as "number of seconds since an epoch" — Linux and Windows don't include leap seconds in this, because it would make their timestamp rendering more complicated (how many leap seconds have there been?) and they can't be dealing with. Instead, they just slow or speed up the clock for a little while around the announced leap second, so rather than actually recording it they just adjust their own seconds-count so rendering that count as a timestamp will appear accurate later.
(What I don't know is how an OS will redetermine its not-really-but-sort-of-seconds count from an NTP transaction without knowing how many leap seconds to deduct; edits welcomed.)
system_clock gives you this seconds count, which (on mainstream platforms) just comes straight from the OS (e.g. time()).
utc_clock gives you a similar seconds count, but one that is "real". On such mainstream platforms this will necessarily have to be the system_clock with leap seconds added after-the-fact. This historical data comes from the system too, indeed some kind of database (though the exact source is up to the implementation).
In conclusion, the data sources for the two clocks are (slightly) different, so there is no question of whether they can co-exist on the same system. But, the system_clock probably comes directly from your operating system, in a way that the utc_clock probably doesn't.
Further reading
NTP and leap seconds: https://www.meinbergglobal.com/english/info/leap-second.htm#os
The new utc_clock feature and its friends: https://howardhinnant.github.io/date/d0355r4.html
I found this working draft about time for C++ 20, which seems to be due out in AD 2020. It has a subpage about utc_clock which includes this example:
clock_­cast<utc_­clock>(sys_­seconds{sys_­days{1970y/January/1}}).time_­since_­epoch() is 0s.
clock_­cast<utc_­clock>(sys_­seconds{sys_­days{2000y/January/1}}).time_­since_­epoch()
and states the last value "is 946'684'822s, which is 10'957 * 86'400s + 22s." Notice that 10,957 days are about 30 years, so the value of utc_clock evidently represents seconds since 1 January 1970 UTC, where each leap second increments the value of utc_clock.
Since this is expressed as a conversion, it seems reasonable to infer the conversion would call upon a table of leap seconds, and could be performed even if the operating system had no notion of the distinction between UTC and TAI, and no concept of a minute which contained 61 seconds.
I must admit I am more interested in time than C++ and have not written serious C++ code in nearly 20 years.

How to detect if there is a leap second when using the tm struct?

According to this struct tm documentation, the value tm_sec can be 0 - 61 and the extra range is to include leap seconds in some systems. How can I detect if there is a leap second in a system generally and in my openSUSE 13.2 machine specifically?
Leap seconds are not related to a particular system. It is even not directly an informatic problem but rather a physical one.
In a ideal world, where every clock would be perfectly accurate, there would be no reason for leap seconds. But in our restricted world, clocks tend to deviate.
Moving the system time, specially moving it backwards can cause bad things to happen. If a batch task stores the time of its last run to know which files has already been processed and because of the clock moving backwards it thinks that time is now before its last run, it will process again file which may be plain wrong.
For that reason, system developpers invented the leap seconds that allow a system to adjust its system clock (of course only slight deltas, but it is generally enough if you check you clock on a regular base) without having to move it backwards.
As noted by #Supuhstar, this is just an operating system implementation of leap seconds. But leap seconds have a true physical origin and were introduced to compensate variation between two definitions of time UTC and TAI - physically variations in earth rotation speed. I give more details on it in this other post of mine

Manipulating times logically with respects to daylight savings time

Is there a way to logically (not absolutely) add a time period to a local time and get a valid local time in the future?
For example, adding one day to 11 am on day 1 becomes 11 am on day 2 even if there's a daylight savings change (+/- one hour) in the meantime? If the time doesn't exist, it could return an error or the next valid time.
C++ standard mechanisms, Windows API functions, STL and/or Boost classes are all fine.
It sort of depends on your semantics.
If you are interested in what the local time might be in exactly half a day, then yes: you convert to UTC, add half a day, and convert back to local time.
On the other hand, if you operate primarily on local times (we do this in electricity load forecasting, for example), you might go the other way, ie 'how many hours away is our half-day future event?': you treat the local time as if it were UTC, add half a day, then treat that as a local time and convert back to UTC to do sanity checks - you have to be aware that some local times don't exist, and some local times are ambiguous.
If you're starting with a local time such as 2013-07-02 18:30:00 and you just want to go to the next calendar day at the same time, then despite the suggestions of others - you really don't want to involve UTC.
You are working in terms of calendar time. UTC is for measuring instantaneous time. Calendar time can have discontinuities for DST changes, but instantaneous time does not.
When you add a day to instantaneous time, you are always adding exactly 24 hours. But when you add a day to calendar time, you are advancing the calendar by one day position. That is subtle, but distinctly different. A calendar day might have 23, 24, or 25 actual hours to it.
When it comes to discontinuities, you will need to deal with the "spring-forward" transition, when the clocks skip an hour. If you add a day and end up in this gap, you would be referring to a time that doesn't exist on the calendar. You need to decide what you want to have happen in this case. Should it advance to the next possible time? Or should it error? Or perhaps you will add one more hour in this case. It's up to you.
The other discontinuity is the "fall-back" transition, when the clocks roll back an hour. There may be two actual instants that this single calendar position could refer to - but since you were only interested in the calendar time, then that shouldn't affect you directly. If you do want to know what instant it maps to, then you would again need to make a decision - perhaps involving some business logic or asking the user via UI.
In order to know where the discontinuities are, you will need a time zone database. The IANA database is the defacto standard.
For C++, you should look into using Boost's Date and Time support. They do use the standard database (aka "ZoneInfo"), and discuss using it here. You probably want to use a local_time.
If at all possible, stay away from POSIX time zone settings like PST8DST, while Boost supports them, they are cryptic and generally difficult to use internationally. The IANA time zones have lookup keys consisting of area and location, such as America/New_York or Europe/London.
Also look in Boost at local_time::ambiguous_result and local_time::time_label_invalid. Those will tell you if you are in a discontinuity.
I will also say that (IMHO), working with local date times, time zone, DST, etc. is much more complex in C++ than in any other language. There are great solutions for PHP, Python, .Net, Ruby, and others. Boost probably has the most comprehensive date/time implementation for C++, but it is no where near as simple as a library like Noda Time for .Net
UPDATE
I've come to realize that Boost's support for IANA/Olson time zones is flawed. Their time zone data file strips away the rich history of the IANA/Olson time zone database - which essentially recreates all of the problems of POSIX time zones that I described in the timezone tag wiki. Therefore, I no longer recommend using Boost for time zone conversion.
Instead, consider ICU, or the time zone functions of the GNU C library (as described here) - both of which use the IANA/Olson time zone data in its entirety.

How to reliably convert local time to UTC on a Windows machine using C++ WinAPI

I need to be able to convert local time to UTC on a Windows machine. I found the SystemTimeToTzSpecificLocalTime API that claims to do this, but then I read its description and found this:
The SystemTimeToTzSpecificLocalTime function may calculate the local time incorrectly under the following conditions:
The time zone uses a different UTC offset for the old and new years.
The UTC time to be converted and the calculated local time are in different years.
My first rhetorical question to MS, "How difficult is it to write a reliable API?"
And then, the actual question — how do you do it to work in 100% of the times? (And not like that API suggests.)
The answer to both your questions is that it is essentially impossible. This is one of the reasons computer science folks tend to hate dealing with local time.
Here are some examples of the confounding issues: When we jump back an hour from 2:00 to 1:00, there are two 1:30's. We also have no way to know today what the daylight savings time rules, if any, will be in ten years. Time zone boundaries are sometimes moved, so just knowing that you're in Pacific time today may not be enough to tell us what your time zone offset was 85 years ago. There is no way to know today what leap seconds may or may not be inserted in the future.
If you find yourself in a situation when it is possible, you will have to code in the specific circumstances that make those operations possible in your particular case. The operations provided are generalized and provide "usually correct" results without constraining the cases in which they can be used.
Moral: Don't use local time except for display. And even then, converting times in the past or future into local times is problematic.
Since the DST periods sometimes change in certain areas, it's hard to write something that is correct in all cases, past and future.
Nevertheless, I you need this functionality, I would suggest using the C functions (localtime, mktime, ...). I recently had a problem where the Windows function SystemTimeToTzSpecificLocalTime did not work correctly on a Citrix server (Citrix does quite some strange (but advanced) things regarding timezones), but the C functions worked correctly.

Time terminology

I'm a bit lost with time terminology.
I understand what epoch is and the difference between GMT and UTC.
However I'm a bit confused about the following notations:
calendar time
local time
wall time
How are these related to timezones and daylight savings?
P.S.
Good link (thanks to #ZincX)
Calendar time is the time that has elapsed since the epoch (t - E).
Local time is calendar time corrected for the timezone and DST.
Wall time: I assume you mean wallclock time. This it the time elapsed since a process or job has started running.
RTFM time(7), localtime(3), time(1).
Epoch: Used to refer to the beginning of something. such as the Unix Epoch which is of 00:00 , January 1, 1970 UTC. (i.e. a time_t with the value 0 represents midnight, Jan 1. 1970 UTC)
calendar time: the time since the epoch
local time: the calendar time in the timezone you (or the computer) resides in.
wall time: time elapsed on a real clock since some arbitary start , e.g. since you started a program (as opposed to e.g. CPU time used by a program since it started)
Try info and then * Date input formats: (coreutils)Date input formats. which starts with this wonderful text:
Our units of temporal measurement, from seconds on up to months,
are so complicated, asymmetrical and disjunctive so as to make
coherent mental reckoning in time all but impossible. Indeed, had
some tyrannical god contrived to enslave our minds to time, to
make it all but impossible for us to escape subjection to sodden
routines and unpleasant surprises, he could hardly have done
better than handing down our present system. It is like a set of
trapezoidal building blocks, with no vertical or horizontal
surfaces, like a language in which the simplest thought demands
ornate constructions, useless particles and lengthy
circumlocutions. Unlike the more successful patterns of language
and science, which enable us to face experience boldly or at least
level-headedly, our system of temporal calculation silently and
persistently encourages our terror of time.
... It is as though architects had to measure length in feet,
width in meters and height in ells; as though basic instruction
manuals demanded a knowledge of five different languages. It is
no wonder then that we often look into our own immediate past or
future, last Tuesday or a week from Sunday, with feelings of
helpless confusion. ...
-- Robert Grudin, `Time and the Art of Living'.
Calendar time is the time since epoch time. This can be represented in a few ways including:
simple calendar time: number of seconds since epoch
high-resolution calendar time: this uses a struct timeval datatype to include fractions of seconds too.
Local time: this is also a structure (the struct tm data type) which includes calendar time as well as timezone and DST information. This gives all the information to present a time string understandable in a certain locale.
Wall time: time elapsed during the running of your process.
I recommend reading the information at this link. It helped me.
Also take a look at this question for a good explanation of calendar time and local time with code examples written in C :
How do I use the C date and time functions on UNIX?
A bit nit-picky, but there is no such thing as GMT anymore. That term was deprecated almost 40 years ago.
There are many different time standards, UTC being one of them. Another is UT1, which is essentially time as measured by a sundial. Yet another is TAI, International Atomic Time (the real acronym is in French, as are most of the acronyms for the various time standards). TAI, as the name suggests, is time as measured by an atomic clock. UTC is a compromise between TAI and UT1. We want our time scale to stay more or less in sync with the sun, but we also want it to be based on the best definition at hand for a second. There is a tension between these two desires because the Earth does not rotate at a constant rate.
Over the long term, the Earth's rotation rate is slowing down because of the tides. The length of a day was considerably shorter a couple of billion years ago. It was a tiny bit shorter a couple of hundred years ago. Our 86,400 second-long day is based on the length of a solar day from a couple of hundred years ago. Today a solar day is about 86,400.002 seconds long, so we have to add leap seconds every so often to keep midnight more or less at midnight.
As far as the specific questions you asked,
It is now 4:25 PM CDT on June 8, 2011. That's calendar time. Here's a challenge: How many second elapsed between 12:42 AM EST on January 3, 1999 and 4:25 PM CDT on June 8, 2011? That's akin to asking someone to do arithmetic in Roman numerals. Yech.
Local time: 4:25 PM CDT and 12:42 AM EST are examples of local time. What is midnight to me is noon to someone halfway around the world.
Wall time (Better: Wall clock time): Suppose you run a program and it takes 20 minutes to run to completion. That 20 minutes is the wall clock time it took the program to run this time around. When I see some program take a lot longer than expected to run I check to see if my stupid antivirus program has gone viral. Oftentimes that is exactly what happens. After giving the antivirus program a kick in the pants, that exact same program run might take only five minutes of wall clock time. The CPU time, on the other hand, will be pretty much the same over the two runs.