1
::tm tm{0, 0, 0, 29, 10, 2022 - 1900, 0, 0};  // 10 for November
auto time_t = ::mktime(&tm);
cout << "milliseconds = " << time_t * 1000 << endl;

Above code outputs 1669660200000, which is equivalent to 2022 November 29, 00:00:00. But it is in local timezone. How to get the UTC time for the aforementioned date?
A modern way with thread-safety will be appreciated.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • The modern way would be std::chrono: https://en.cppreference.com/w/cpp/chrono Handles time / day calculations & time zones among others. – nick Nov 29 '22 at 11:51
  • `timegm`/`_mkgmtime` are the UTC equivalents of `mktime` but aren't standardised – Alan Birtles Nov 29 '22 at 12:50

2 Answers2

1

There's a nit picky weak point in your solution (besides the thread safety issue): The members of tm are not guaranteed to be in the order you are assuming.

The tm structure shall contain at least the following members, in any order.

Using C++17 you can use this C++20 chrono preview library. It is free, open-source and header-only. Your program would look like:

#include "date/date.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace chrono;
    using namespace date;

    sys_time<milliseconds> tp = sys_days{2022_y/11/29};
    cout << "milliseconds = " << tp.time_since_epoch().count() << '\n';
}

And the output would be:

milliseconds = 1669680000000

One of the nice advantages of using this library is that it will easily port to C++20. The C++20 version looks like:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace chrono;

    sys_time<milliseconds> tp = sys_days{2022y/11/29};
    cout << "milliseconds = " << tp.time_since_epoch() << '\n';
}

And outputs:

milliseconds = 1669680000000ms

Demo:

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • Thank you for pointing out the code problem in the ordering issue! Is there a pure C++17 (or with ``) solution available, which doesn't require any external code at all? – iammilind Nov 30 '22 at 02:16
  • If you bend the "external code" definition, you can use my chrono-compatible algorithms here: http://howardhinnant.github.io/date_algorithms.html. The code at this link is not a library, it is a "cook book" for how to build your own date library. These algorithms are what C++20 chrono is based on, and are in the public domain. Each algorithm has an exhaustive explanation, and a unit test over +/- million years to assure its correctness modeling the proleptic Gregorian calendar. – Howard Hinnant Nov 30 '22 at 03:39
0

One old school C-style way is to first get the timezone difference and offset it with the value in the question.

static const auto TIMEZONE_OFFSET = [] (const ::time_t seconds)
{ // This method is to be called only once per execution
  ::tm tmGMT = {}, tmLocal = {}; 
  ::gmtime_r(&seconds, &tmGMT); // ::gmtime_s() for WINDOWS
  ::localtime_r(&seconds, &tmLocal);  // ::localtime_s() for WINDOWS
  return ::mktime(&tmGMT) - ::mktime(&tmLocal);
}(10000);

::tm tm{0, 0, 0, 29, 10, 2022 - 1900}; // set fields 1 by 1 as the order is not guaranteed
cout << " start of day = " << (::mktime(&tm) - TIMEZONE_OFFSET) << endl;
iammilind
  • 68,093
  • 33
  • 169
  • 336