harmic - 4 months ago 30

C++ Question

I have a program that was originally written for Linux, but I now have a requirement to get it running on Solaris 10.

Part of this program uses the timegm function to convert a

`struct tm`

`time_t`

Trying to compile this program on Solaris, it fails because

`timegm`

However I have so far not been able to find an alternative function, that takes a

`struct tm`

Note that I do not wish to use

`tzset`

So my question is: how can I convert a

`struct tm`

`timegm`

The program is written in C++ so I'm not limited to C solutions, although I would prefer not to embark on a wholesale rewrite to use some additional time library.

Answer

You could use `days_from_civil`

which is described here in detail

```
// Returns number of days since civil 1970-01-01. Negative values indicate
// days prior to 1970-01-01.
// Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
// m is in [1, 12]
// d is in [1, last_day_of_month(y, m)]
// y is "approximately" in
// [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
// Exact range of validity is:
// [civil_from_days(numeric_limits<Int>::min()),
// civil_from_days(numeric_limits<Int>::max()-719468)]
template <class Int>
constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<Int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
y -= m <= 2;
const Int era = (y >= 0 ? y : y-399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365]
const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]
return era * 146097 + static_cast<Int>(doe) - 719468;
}
```

to convert the {year, month, day} triple in the `tm`

to a count of days since the epoch (1970-01-01). Be careful when converting these fields from `tm`

for their eccentricities (e.g. `tm_year + 1900`

).

Multiply this count of days by 86400 and add to that the {hours, minutes, seconds} data from the `tm`

(each converted to seconds).

And you're done. Don't worry about leap seconds, `timegm`

didn't worry about them either. If you're really concerned about leap seconds I have a C++11/14 solution available to deal with that, but I'm guessing that is more than you want to get into.

Don't be put off by the C++14 syntax shown above. It is trivial to convert this algorithm to C (or any other language for that matter).