Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

what is the best way to get microseconds of time on Windows in C or C++ ?

94 views
Skip to first unread message

Lynn McGuire

unread,
Nov 3, 2022, 9:14:20 PM11/3/22
to
What is the best way to get microseconds of time on Windows in C or C++
? I am currently using the following code to get the current time:

std::time_t t = std::time (0); // get time now
std::tm * now = std::localtime ( & t);
integer iyear = now -> tm_year + 1900;
integer imonth = now -> tm_mon + 1;
integer iday = now -> tm_mday;
integer ihour = now -> tm_hour;
integer imin = now -> tm_min;
integer isec = now -> tm_sec;
integer ihund = 0;

Thanks,
Lynn

DFS

unread,
Nov 3, 2022, 9:51:50 PM11/3/22
to
https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps


I used it like this:
----------------------------------------------------------------
LARGE_INTEGER frequency,start,end;

//calc elapsed time
double elapsedtime(LARGE_INTEGER startingtimer)
{
QueryPerformanceCounter(&end);
return (end.QuadPart - startingtimer.QuadPart) /
(double)frequency.QuadPart;
}


int main(void)
{

//turn on Windows program timing
QueryPerformanceFrequency(&frequency);

//start timing a piece of code
QueryPerformanceCounter(&start);
...
...
printf(" %.4fs to execute\n",elapsedtime(start));

}
----------------------------------------------------------------

Lynn McGuire

unread,
Nov 4, 2022, 1:07:09 AM11/4/22
to
I forgot to add I would prefer a portable way if possible. I suspect
that is not possible though below the second resolution.

Thanks,
Lynn McGuire

Christian Gollwitzer

unread,
Nov 4, 2022, 3:03:21 AM11/4/22
to
HI Lynn,
Am 04.11.22 um 06:06 schrieb Lynn McGuire:
> On 11/3/2022 8:51 PM, DFS wrote:
>> On 11/3/2022 9:14 PM, Lynn McGuire wrote:
>>> What is the best way to get microseconds of time on Windows in C or
>>> C++ ?  I am currently using the following code to get the current time:
>>>

>> ----------------------------------------------------------------
>
> I forgot to add I would prefer a portable way if possible.  I suspect
> that is not possible though below the second resolution.
>

I fear it is not possible in a portable way. Here you can find some
description about how Tcl has solved this issue especially for Windows:

https://core.tcl-lang.org/tips/doc/trunk/tip/7.md

The implementation is here:

https://github.com/tcltk/tcl/blob/main/win/tclWinTime.c

and here for Unix:

https://github.com/tcltk/tcl/blob/main/unix/tclUnixTime.c

(BSD licensed, in any case)

Christian

Juha Nieminen

unread,
Nov 4, 2022, 3:37:11 AM11/4/22
to
In comp.lang.c++ Lynn McGuire <lynnmc...@gmail.com> wrote:
> What is the best way to get microseconds of time on Windows in C or C++

It's a bit unclear whether you mean "time in microseconds units" or "time
at the microseconds resolution".

Because the latter may not be even possible (portable or not). Just because
some time function returns time "in microseconds" that doesn't mean that it
uses microsecond resolution (in other words, the value it returns may well
change at longer intervals than every microsecond; probably *significantly*
longer intervals).

It is possible to get some kind of timing at the CPU clock cycle interval
(in most modern CPUs, at least), which is about as accurate as you can
possibly get, but I don't know if there are eg. some system functions that
will return elapsed clock cycles converted into the equivalent amount of
microseconds.

Scott Lurndal

unread,
Nov 4, 2022, 9:44:26 AM11/4/22
to

Keith Thompson

unread,
Nov 4, 2022, 12:08:16 PM11/4/22
to
The resolution of the time() function is unspecified (not even
implementation-defined). In practice, time_t is almost universally an
integer type representing seconds since some epoch, usually 1970-01-01
00:00:00 UTC, but it could even be floating-point.

C11 adds the type struct timespec and the function timespec_get() which
gives a result with a resolution of 1 nanosecond. A footnote in the
standard says:

Although a struct timespec object describes times with nanosecond
resolution, the available resolution is system dependent and may
even be greater than 1 second.

The standard says that struct timespec has the following members:

time_t tv_sec; // whole seconds — ≥ 0
long tv_nsec; // nanoseconds — [0, 999999999]

which strongly implies that the resulution of time_t is 1 second, but
the standard still doesn't say so. Possibly an implementation could use
different encodings for the time_t value from time() and the time_t
value from timespec_get(), though that's unlikely in practice.

clock() returns a value of type clock_t, which is typically double, but
that's also unspecified -- and it measures processor time, not wall
clock time.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */

Lynn McGuire

unread,
Nov 4, 2022, 3:24:54 PM11/4/22
to
Get time at the microseconds resolution. My calculation engine creates
a bunch of temporary files and I use the time to create unique names for
those temporary files. Seconds should be good enough for uniqueness but
I like adding microseconds as a guarantee. Something like
uniquac1.out.009.20181972.20220912

Thanks,
Lynn

Lynn McGuire

unread,
Nov 4, 2022, 3:32:52 PM11/4/22
to
Thanks !

Lynn

Lynn McGuire

unread,
Nov 4, 2022, 3:33:51 PM11/4/22
to
Thanks !

Lynn


Lynn McGuire

unread,
Nov 4, 2022, 3:34:22 PM11/4/22
to
Thanks !

Lynn

Bonita Montero

unread,
Nov 4, 2022, 3:49:54 PM11/4/22
to
Use GetSystemTimeAsFileTime() and FileTimeToLocalFileTime() on
Windows or the time_t-capable Functions on Unix and this class:

Header:

#pragma once
#if defined(_MSC_VER)
#define NOMINMAX
#include <Windows.h>
#endif
#include <cstdint>
#include <compare>
#include <ctime>
#include <stdexcept>
#include <compare>
#include <memory>
#include <mutex>
#include <algorithm>
#include <vector>
#include <functional>
#include <atomic>

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 26812) // prefer enum class over enum
#pragma warning(disable: 26495) // members not intitialized
#endif

struct st_timestamp
{
constexpr st_timestamp() = default;
st_timestamp( st_timestamp const & ) = default;
constexpr st_timestamp( std::uint64_t timestamp ) noexcept;
constexpr operator std::uint64_t() const noexcept;
constexpr explicit operator std::int64_t() const noexcept;
constexpr explicit operator bool() const noexcept;
constexpr st_timestamp &operator =( st_timestamp const & ) = default;
constexpr st_timestamp &operator =( std::uint64_t timestamp ) noexcept;
private:
std::uint64_t m_timestamp;
};

struct system_time
{
std::uint16_t year;
std::uint8_t weekday, month, day;
std::uint8_t hour, minute, second;
std::uint32_t ns100;
enum reason_t : uint8_t
{
TIMESTAMP_BEYOND_63_BIT = 1,
YEAR_OUT_OF_RANGE,
MONTH_OUT_OF_RANGE,
DAY_OUT_OF_RANGE,
HOUR_OUT_OF_RANGE,
MINUTE_OUT_OF_RANGE,
SECOND_OUT_OF_RANGE,
NS100_OUT_OF_RANGE,
TIMESTAMP_BEFORE_TIME_T,
WRONG_LEAP_SECOND
};
struct leap_second_t
{
std::uint16_t year;
bool jun30, dec31;
};
struct date_error : public std::invalid_argument
{
reason_t reason();
date_error() = delete;
date_error( date_error const & ) = delete;
private:
friend struct system_time;
date_error( reason_t reason );
reason_t m_reason;
};
system_time() {}
system_time( system_time const & ) = default;
system_time( std::uint16_t year, std::uint8_t month, std::uint8_t day,
std::uint8_t hour, std::uint8_t minute, std::uint8_t second,
std::uint32_t ns100 );
explicit system_time( st_timestamp ts );
system_time( struct tm const &tm );
#if defined(_MSC_VER)
system_time( SYSTEMTIME const &st );
#endif
operator st_timestamp() const;
st_timestamp to_timestamp( reason_t *reason = nullptr ) const noexcept;
system_time &operator =( st_timestamp ts );
void from_timestamp( st_timestamp ts, reason_t *reason = nullptr )
noexcept;
system_time &operator =( system_time const & ) = default;
operator tm() const;
struct tm to_tm( reason_t *reason ) const noexcept;
system_time &operator =( struct tm const &tm );
bool from_tm( struct tm const &tm, reason_t *reason ) noexcept;
#if defined(_MSC_VER)
operator SYSTEMTIME() const;
SYSTEMTIME to_systemtime( reason_t *reason ) const noexcept;
system_time &operator =( SYSTEMTIME const &st );
bool from_systemtime( SYSTEMTIME const &st, reason_t *reason ) noexcept;
#endif
bool adjust_weekday( reason_t *reason = nullptr ) noexcept;
static std::uint8_t get_weekday( st_timestamp timestamp ) noexcept;
static_assert(sizeof(time_t) == 8, "time_t must be 64 bit");
static time_t timestamp_to_time_t( st_timestamp ts, reason_t *reason =
nullptr ) noexcept;
static st_timestamp time_t_to_timestamp( time_t time, reason_t *reason
= nullptr ) noexcept;
static void leap_seconds( std::function<leap_second_t ( bool )> const
&fn );
private:
friend struct st_timestamp;
static std::atomic<std::shared_ptr<std::vector<leap_second_t>>>
g_leapSeconds;
static constexpr std::uint64_t
MILLISECOND = 10'000,
SECOND = 1'000 * MILLISECOND,
MINUTE = 60 * SECOND,
HOUR = 60 * MINUTE,
DAY = 24 * HOUR,
WEEK = 7 * DAY,
NON_LEAP_YEAR = 365 * DAY,
LEAP_YEAR = 366 * DAY,
FOUR_YEARS_W_LJ = LEAP_YEAR + 3 * NON_LEAP_YEAR,
FOUR_YEARS_WO_LJ = 4 * NON_LEAP_YEAR,
FIRST_QUARTER_CENTURY = 25 * FOUR_YEARS_W_LJ,
REMAINING_QUARTER_CENUTRIES = 25 * FOUR_YEARS_W_LJ - DAY,
FOUR_HUNDRED_YEARS = FIRST_QUARTER_CENTURY + 3 *
REMAINING_QUARTER_CENUTRIES,
TIME_T_IN_TIMESTAMP_BEGIN = 0x19DB1DED53E800,
LAST_TIMESTAMP_IN_TIME_T = 0xD69433CCD5,
LEAP_SECOND_BIT = std::numeric_limits<int64_t>::min();
};

constexpr st_timestamp::st_timestamp( std::uint64_t timestamp ) noexcept :
m_timestamp( timestamp )
{
}

constexpr st_timestamp::operator std::uint64_t() const noexcept
{
return m_timestamp & ~system_time::LEAP_SECOND_BIT;
}

constexpr st_timestamp::operator std::int64_t() const noexcept
{
return m_timestamp;
}

constexpr st_timestamp::operator bool() const noexcept
{
return m_timestamp & system_time::LEAP_SECOND_BIT;
}

constexpr st_timestamp &st_timestamp::operator =( std::uint64_t
timestamp ) noexcept
{
m_timestamp = timestamp;
return *this;
}

// may throw invalid_argument

inline system_time::system_time( st_timestamp ts )
{
*this = ts;
}

// may throw invalid_argument

inline system_time &system_time::operator =( st_timestamp ts )
{
reason_t reason;
from_timestamp( ts, &reason );
if( reason ) [[likely]]
throw date_error( reason );
return *this;
}


inline system_time::system_time( struct tm const &tm )
{
*this = tm;
}

#if defined(_MSC_VER)
inline system_time::system_time( SYSTEMTIME const &st )
{
*this = st;
}
#endif

inline typename system_time::reason_t system_time::date_error::reason()
{
return m_reason;
}

inline uint8_t system_time::get_weekday( st_timestamp ts ) noexcept
{
using namespace std;
return (uint32_t)(((uint64_t)ts - (uint64_t)ts / WEEK * WEEK) / DAY +
1) % 7;
}

// may throw date_error

inline std::strong_ordering operator <=>( system_time const &left,
system_time const &right )
{
return (std::uint64_t)(st_timestamp)left <=> (uint64_t)(st_timestamp)right;
}

// may throw date_error

inline std::strong_ordering operator <=>( system_time const &left,
st_timestamp right )
{
return (std::uint64_t)(st_timestamp)left <=> (std::uint64_t)right;
}

// may throw date_error

inline std::strong_ordering operator <=>( st_timestamp left, system_time
const &right )
{
return (std::uint64_t)left <=> (std::uint64_t)(st_timestamp)left;
}

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

// .cpp:

#include <stdexcept>
#include <cassert>
#include <limits>
#include <algorithm>
#include <array>
#include <system_error>
#include <functional>
#if defined(__cpp_lib_hardware_interference_size)
#include <new>
#endif
#include "system_time.h"

using namespace std;

#if defined(__cpp_lib_hardware_interference_size)
constexpr size_t CL_SIZE = std::hardware_destructive_interference_size;
#else
constexpr size_t CL_SIZE = 64;
#endif

constexpr bool SYSTEM_TIME_BINARY_SEARCH = false;

// may throw date_error

system_time::system_time( std::uint16_t year, std::uint8_t month,
std::uint8_t day, std::uint8_t hour, std::uint8_t minute, std::uint8_t
second, std::uint32_t ns100 )
{
this->year = year;
this->month = month;
this->day = day;
this->hour = hour;
this->minute = minute;
this->second = second;
this->ns100 = ns100;
this->weekday = get_weekday( (st_timestamp)*this );
}

// may throw date_error

void system_time::from_timestamp( st_timestamp ts, reason_t *reason )
noexcept
{
auto reasonableErr = [&]( reason_t retReason ) -> void
{
if( reason ) [[likely]]
*reason = retReason;
memset( this, 0, sizeof *this );
};
uint64_t tsCalc = (uint64_t)ts;
bool leapSecond = (bool)ts;
weekday = get_weekday( ts );
tsCalc += LEAP_YEAR; // 1601 - 1600 = leap year
uint16_t y400, y100, y4, y;
y400 = (uint16_t)(tsCalc / FOUR_HUNDRED_YEARS);
tsCalc -= y400 * FOUR_HUNDRED_YEARS;
bool isLeapYear;
auto leapQuad = [&]()
{
if( tsCalc >= LEAP_YEAR ) [[likely]]
// y >= 1
tsCalc -= LEAP_YEAR,
y = (uint16_t)(1 + tsCalc / NON_LEAP_YEAR), // 1 ... 3
tsCalc -= tsCalc / NON_LEAP_YEAR * NON_LEAP_YEAR,
isLeapYear = false;
else
// y == 0
y = 0,
isLeapYear = true;
};
if( tsCalc >= FIRST_QUARTER_CENTURY ) [[likely]]
{
// (y % 400) >= 100
y100 = (uint16_t)(1 + (tsCalc - FIRST_QUARTER_CENTURY) /
REMAINING_QUARTER_CENUTRIES); // 1 ... 3
tsCalc -= FIRST_QUARTER_CENTURY + (tsCalc - FIRST_QUARTER_CENTURY) /
REMAINING_QUARTER_CENUTRIES * REMAINING_QUARTER_CENUTRIES;
if( tsCalc >= FOUR_YEARS_WO_LJ ) [[likely]]
// (y % 400) >= 100 && (y % 100) >= 4
y4 = (uint16_t)(1 + (tsCalc - FOUR_YEARS_WO_LJ) / FOUR_YEARS_W_LJ),
// 1 ... 24
tsCalc -= FOUR_YEARS_WO_LJ + (tsCalc - FOUR_YEARS_WO_LJ) /
FOUR_YEARS_W_LJ * FOUR_YEARS_W_LJ,
leapQuad();
else
// (y % 400) >= 100 && (y % 100) < 4
y4 = 0,
y = (uint16_t)(tsCalc / NON_LEAP_YEAR),
tsCalc -= tsCalc / NON_LEAP_YEAR * NON_LEAP_YEAR,
isLeapYear = false;
}
else
// (y % 400) < 100
y100 = 0,
y4 = (uint16_t)(tsCalc / FOUR_YEARS_W_LJ),
tsCalc -= tsCalc / FOUR_YEARS_W_LJ * FOUR_YEARS_W_LJ,
leapQuad();
year = 1600 + 400 * y400 + 100 * y100 + 4 * y4 + y;
{
static uint64_t const monthOffsets[2][12 + 1] alignas(CL_SIZE) =
{
{ 0 * DAY, 31 * DAY, 59 * DAY, 90 * DAY, 120 * DAY, 151 * DAY, 181 *
DAY, 212 * DAY, 243 * DAY, 273 * DAY, 304 * DAY, 334 * DAY, 999 * DAY },
{ 0 * DAY, 31 * DAY, 60 * DAY, 91 * DAY, 121 * DAY, 152 * DAY, 182 *
DAY, 213 * DAY, 244 * DAY, 274 * DAY, 305 * DAY, 335 * DAY, 999 * DAY }
};
uint64_t const *pMonthOffsets = monthOffsets[isLeapYear];
size_t moHit;
if constexpr( !SYSTEM_TIME_BINARY_SEARCH )
for( moHit = 0; tsCalc >= pMonthOffsets[moHit + 1]; ++moHit );
else
{
size_t lower = 0, upper = 12, mid;
moHit = -1;
do
{
mid = (lower + upper) / 2;
if( pMonthOffsets[mid] <= tsCalc )
moHit = mid,
lower = mid + 1;
else
upper = mid;
} while( lower != upper );
assert( moHit != -1 );
}
uint64_t mo = pMonthOffsets[moHit];
uint8_t dy = (uint8_t)((tsCalc - mo) / DAY);
tsCalc -= mo + dy * DAY;
month = 1 + (uint8_t)moHit;
day = 1 + dy;
}
hour = (uint8_t)(tsCalc / HOUR);
tsCalc %= HOUR;
minute = (uint8_t)(tsCalc / MINUTE);
tsCalc %= MINUTE;
second = (uint8_t)(tsCalc / SECOND);
if( leapSecond ) [[unlikely]]
{
if( second != 59 || minute != 59 || hour != 23 || (month != 6 || day
!= 30) && (month != 12 || day != 31) ) [[unlikely]]
return reasonableErr( WRONG_LEAP_SECOND );
shared_ptr leapSeconds( g_leapSeconds.load( memory_order_relaxed ) );
size_t lower = 0, upper = leapSeconds->size();
for( ; ; )
{
size_t mid = (lower + upper) / 2;
leap_second_t const &ls = (*leapSeconds)[mid];
if( ls.year == year ) [[unlikely]]
if( month == 6 && ls.jun30 || month == 12 && ls.dec31 ) [[likely]]
{
++second;
break;
}
else
return reasonableErr( WRONG_LEAP_SECOND );
bool midIsLower = ls.year < year;
(midIsLower ? lower : upper) = mid + midIsLower;
if( lower == upper ) [[unlikely]]
return reasonableErr( WRONG_LEAP_SECOND );
}
}
tsCalc %= SECOND;
ns100 = (uint32_t)tsCalc;
}

// may throw date_error
// may throw system_error
// may throw bad_alloc

extern system_time::leap_second_t const leapSecondsInit2016[26];

st_timestamp system_time::to_timestamp( reason_t *reason ) const noexcept
{
using namespace std;
auto reasonableErr = [&]( reason_t retReason ) -> st_timestamp
{
if( reason ) [[likely]]
*reason = retReason;
return st_timestamp( -1 );
};
if( year < 1601 || year > 30828 ) [[unlikely]]
return reasonableErr( YEAR_OUT_OF_RANGE );
if( month < 1 || month > 12 ) [[unlikely]]
return reasonableErr( MONTH_OUT_OF_RANGE );
bool isLeapYear = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
static uint8_t const monthLengths[2][1 + 12] alignas(CL_SIZE) =
{
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
if( day == 0 || day > monthLengths[isLeapYear][month] ) [[unlikely]]
return reasonableErr( DAY_OUT_OF_RANGE );
if( hour >= 24 ) [[unlikely]]
return reasonableErr( HOUR_OUT_OF_RANGE );
if( minute >= 60 ) [[unlikely]]
return reasonableErr( MINUTE_OUT_OF_RANGE );
uint8_t sec = second;
uint64_t leapSecondBit = 0;
if( sec >= 60 ) [[unlikely]]
{
if( sec != 60 || minute != 59 || hour == 23 || (month != 6 || day !=
30) && (month != 12 || day != 31) ) [[unlikely]]
return reasonableErr( SECOND_OUT_OF_RANGE );
shared_ptr leapSeconds( g_leapSeconds.load( memory_order_relaxed ) );
if( !leapSeconds ) [[unlikely]]
{
size_t i = 0;
leap_seconds(
[&]( bool reset ) -> leap_second_t
{
i = !reset ? i : 0;
if( i != size( ::leapSecondsInit2016 ) ) [[likely]]
return ::leapSecondsInit2016[i++];
else
return leap_second_t { 0xFFFFu, false, false };
} );
leapSeconds = g_leapSeconds.load( memory_order_relaxed );
}
size_t lower = 0, upper = leapSeconds->size();
for( ; ; )
{
size_t mid = (lower + upper) / 2;
leap_second_t const &ls = (*leapSeconds)[mid];
if( ls.year == year ) [[unlikely]]
if( month == 6 && ls.jun30 || month == 12 && ls.dec31 ) [[likely]]
{
--sec, leapSecondBit = LEAP_SECOND_BIT;
break;
}
else
return reasonableErr( SECOND_OUT_OF_RANGE );
bool midIsLower = ls.year < year;
(midIsLower ? lower : upper) = mid + midIsLower;
if( lower == upper ) [[unlikely]]
return reasonableErr( SECOND_OUT_OF_RANGE );
}
}
if( ns100 >= 10'000'000 ) [[unlikely]]
return reasonableErr( NS100_OUT_OF_RANGE );
uint16_t yr = year - 1600;
uint64_t timestamp = yr / 400 * FOUR_HUNDRED_YEARS;
yr %= 400;
auto leapQuad = [&]()
{
timestamp += yr / 4 * FOUR_YEARS_W_LJ;
yr %= 4;
if( yr >= 1 ) [[likely]]
timestamp += LEAP_YEAR + (yr - 1) * NON_LEAP_YEAR;
};
if( yr >= 100 ) [[likely]]
{
timestamp += FIRST_QUARTER_CENTURY;
yr -= 100;
timestamp += yr / 100 * REMAINING_QUARTER_CENUTRIES;
yr %= 100;
if( yr >= 4 ) [[likely]]
timestamp += FOUR_YEARS_WO_LJ,
yr -= 4,
leapQuad();
else
timestamp += yr * NON_LEAP_YEAR;
}
else
leapQuad();
timestamp -= LEAP_YEAR; // - (1.1.1601 - 1.1.1600)
static uint16_t const monthOffsets[2][1 + 12] alignas(CL_SIZE) =
{
{ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
};
timestamp += (monthOffsets[isLeapYear][month] + day - 1) * DAY;
timestamp += hour * HOUR;
timestamp += minute * MINUTE;
timestamp += sec * SECOND;
timestamp += ns100;
if( timestamp > (uint64_t)numeric_limits<int64_t>::max() ) [[unlikely]]
return reasonableErr( TIMESTAMP_BEYOND_63_BIT );
if( reason ) [[likely]]
*reason = (reason_t)0;
return timestamp | leapSecondBit;
}

// may throw date_error

system_time::operator st_timestamp() const
{
reason_t reason;
st_timestamp ts = to_timestamp( &reason );
if( reason ) [[unlikely]]
throw date_error( reason );
return ts;
}

#if defined(_MSC_VER)
// may throw date_error

system_time::operator SYSTEMTIME() const
{
reason_t reason;
SYSTEMTIME st = to_systemtime( &reason );
if( reason ) [[unlikely]]
throw date_error( reason );
return st;
}

SYSTEMTIME system_time::to_systemtime( reason_t *reason ) const noexcept
{
SYSTEMTIME st;
st.wYear = year;
st.wDay = day;
st.wHour = hour;
st.wMinute = minute;
st.wSecond = second;
st.wMilliseconds = (WORD)(ns100 / 10'000);
reason_t lReason;
st_timestamp timestamp = to_timestamp( &lReason );
if( lReason ) [[unlikely]]
{
if( reason ) [[likely]]
*reason = lReason;
memset( &st, 0, sizeof st );
return st;
}
st.wDayOfWeek = get_weekday( timestamp );;
return st;
}

// may throw date_error

system_time &system_time::operator =( SYSTEMTIME const &st )
{
reason_t reason;
from_systemtime( st, &reason );
if( reason ) [[unlikely]]
throw date_error( reason );
return *this;
}

bool system_time::from_systemtime( SYSTEMTIME const &st, reason_t
*reason ) noexcept
{
system_time stAux;
stAux.year = st.wYear;
stAux.month = (uint8_t)st.wMonth;
stAux.day = (uint8_t)st.wDay;
stAux.hour = (uint8_t)st.wHour;
stAux.minute = (uint8_t)st.wMinute;
stAux.second = (uint8_t)st.wSecond;
stAux.ns100 = (uint32_t)st.wMilliseconds * 10'000;
reason_t lReason;
st_timestamp timestamp = to_timestamp( &lReason );
if( lReason ) [[unlikely]]
{
if( reason ) [[likely]]
*reason = lReason;
return false;
}
stAux.weekday = get_weekday( timestamp );
*this = stAux;
return true;
}

#endif

// may throw date_error

system_time::operator tm() const
{
reason_t reason;
struct tm tm( to_tm( &reason ) );
if( reason ) [[unlikely]]
throw date_error( reason );
return tm;
}

struct tm system_time::to_tm( reason_t *reason ) const noexcept
{
using namespace std;
auto reasonableErr = [&]( reason_t retReason ) -> struct tm
{
if( reason ) [[likely]]
*reason = retReason;
return tm( -1 );
};
if( year < 1900 || year - 1900u > (unsigned)numeric_limits<int>::max()
) [[unlikely]]
return reasonableErr( YEAR_OUT_OF_RANGE );
reason_t lReason;
uint64_t timestamp = to_timestamp( &lReason );
if( lReason ) [[unlikely]]
return reasonableErr( lReason );
uint8_t wd = get_weekday( timestamp );
struct tm tm;
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
uint16_t const monthOffsets[2][1 + 12] alignas(CL_SIZE) =
{
{ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
};
tm.tm_yday = monthOffsets[year % 4 == 0 && year % 100 != 0 || year %
400 == 0][month] + day - 1;
tm.tm_hour = hour;
tm.tm_min = minute;
tm.tm_sec = second;
tm.tm_wday = wd;
return tm;
}

// may throw date_error

system_time &system_time::operator =( struct tm const &tm )
{
reason_t reason;
if( !from_tm( tm, &reason ) ) [[unlikely]]
throw date_error( reason );
return *this;
}

bool system_time::from_tm( struct tm const &tm, reason_t *reason ) noexcept
{
auto reasonableErr = [&]( reason_t retReason ) -> bool
{
if( reason ) [[unlikely]]
*reason = retReason;
return false;
};
if( tm.tm_year < 1601 - 1900 || tm.tm_year > 30828 - 1900 ) [[unlikely]]
return reasonableErr( YEAR_OUT_OF_RANGE );
system_time stAux;
stAux.year = tm.tm_year + 1900;
stAux.month = tm.tm_mon + 1;
stAux.day = tm.tm_mday;
stAux.hour = tm.tm_hour;
stAux.minute = tm.tm_min;
stAux.second = tm.tm_sec;
stAux.ns100 = 0;
reason_t lReason;
uint64_t timestamp = stAux.to_timestamp( &lReason );
if( lReason ) [[unlikely]]
return reasonableErr( lReason );
stAux.weekday = get_weekday( timestamp );
*this = stAux;
return true;
}

// may throw date_error

time_t system_time::timestamp_to_time_t( st_timestamp ts, reason_t
*reason ) noexcept
{
if( (uint64_t)ts < TIME_T_IN_TIMESTAMP_BEGIN ) [[unlikely]]
{
if( reason ) [[likely]]
*reason = TIMESTAMP_BEFORE_TIME_T;
return -1;
}
return ((uint64_t)ts - TIME_T_IN_TIMESTAMP_BEGIN) / SECOND;
}

// may throw date_error

st_timestamp system_time::time_t_to_timestamp( time_t time, reason_t
*reason ) noexcept
{
if( time > LAST_TIMESTAMP_IN_TIME_T ) [[unlikely]]
{
if( reason ) [[likely]]
*reason = TIMESTAMP_BEYOND_63_BIT;
return -1;
}
return st_timestamp( TIME_T_IN_TIMESTAMP_BEGIN + time * SECOND );
}

// may throw date_error

inline bool system_time::adjust_weekday( reason_t *reason ) noexcept
{
reason_t lReason;
uint64_t timestamp = to_timestamp( &lReason );
if( lReason ) [[unlikely]]
{
if( reason ) [[likely]]
*reason = lReason;
return false;
}
weekday = get_weekday( timestamp );
return true;
}

system_time::date_error::date_error( reason_t reason ) :
invalid_argument(
[]( reason_t reason ) -> char const *
{
static struct err_map_t
{
reason_t reason;
char const *what;
} const errMaps[] =
{
err_map_t { TIMESTAMP_BEYOND_63_BIT, "system_time - timestamp beyond
63 bit (14.9.30828 22:48:5.4775807)" },
err_map_t { YEAR_OUT_OF_RANGE, "system_time - year out of range" },
err_map_t { MONTH_OUT_OF_RANGE, "system_time - month out of range" },
err_map_t { DAY_OUT_OF_RANGE, "system_time - day out of range" },
err_map_t { HOUR_OUT_OF_RANGE, "system_time - hour out of range" },
err_map_t { MINUTE_OUT_OF_RANGE, "system_time - minute out of range" },
err_map_t { SECOND_OUT_OF_RANGE, "system_time - second out of range" },
err_map_t { NS100_OUT_OF_RANGE, "system_time - 100ns-steps out of
range" },
err_map_t { TIMESTAMP_BEFORE_TIME_T, "system_time - timestamp before
time_t (1.1.1970 00:00.0)" }
};
for( err_map_t const &errMap : errMaps )
if( errMap.reason == reason ) [[unlikely]]
return errMap.what;
return "";
}( reason ) ),
m_reason( reason )
{
}

// may throw bad_alloc
// may throw invalid_argument if there's a duplicate leap year from the
feeder
// may throw date_error if a year is out of range (< 1601 || > 30828)
// may throw invalid_argument if leap year from feeder has no leaps

void system_time::leap_seconds( std::function<leap_second_t ( bool )>
const &feeder )
{
using namespace std;
auto feedLoop = [&]<typename Fn>( Fn fn ) -> size_t
requires requires( Fn fn, leap_second_t const &ls ) { { fn( ls ) }; }
{
size_t i = 0;
for( leap_second_t ls; (ls = feeder( i++ == 0 )).year != 0xFFFFu; fn(
ls ) );
return i;
};
vector<leap_second_t> leaps;
leaps.reserve( feedLoop( [&]( leap_second_t const & ) { } ) );
feedLoop( [&]( leap_second_t const &ls ) { leaps.emplace_back( ls ); } );
sort( leaps.begin(), leaps.end(),
[]( leap_second_t &lhs, leap_second_t &rhs ) -> bool { return lhs.year
< rhs.year; } );
for( leap_second_t const &lp : leaps )
if( &lp != &leaps[0] && lp.year == (&lp)[-1].year ) [[unlikely]]
throw invalid_argument( "duplicate leap year" );
else if( lp.year < 1601 || lp.year > 30828 ) [[unlikely]]
throw date_error( YEAR_OUT_OF_RANGE );
else if( !lp.jun30 && !lp.dec31 ) [[unlikely]]
throw invalid_argument( "leap year without leaps" );
g_leapSeconds.store( make_shared<vector<leap_second_t>>( move( leaps )
), memory_order_release );
}

atomic<shared_ptr<vector<system_time::leap_second_t>>>
system_time::g_leapSeconds;

static system_time::leap_second_t const leapSecondsInit2016[26] =
{
{ 1972, true, true },
{ 1973, false, true },
{ 1974, false, true },
{ 1975, false, true },
{ 1976, false, true },
{ 1977, false, true },
{ 1978, false, true },
{ 1979, false, true },
{ 1981, true, false },
{ 1982, true, false },
{ 1983, true, false },
{ 1985, true, false },
{ 1987, false, true },
{ 1989, false, true },
{ 1990, false, true },
{ 1992, true, false },
{ 1993, true, false },
{ 1994, true, false },
{ 1995, false, true },
{ 1997, true, false },
{ 1998, false, true },
{ 2005, false, true },
{ 2008, false, true },
{ 2012, true, false },
{ 2015, true, false },
{ 2016, false, true }
};

This is similar to Windows' FILETIME (100ns-intervals since 1.1.1601
00:00:00.0) and you can convert the C-timestamps also to st_timestamp.
st_timestamp is a 64 bit timestamp which uses the highes bit to indi-
cate if the timestamp is within a leap-second. If you - implicitly
or explicitly - convert the st_timestamp to an uint64_t the highest
bit is stripped and you can calculate with it like with a Unix-time-
stamp, but with a higher resolution. You can implicitly or explicitly
convert back an uint64_t-value to a st_timestamp independently on if
the highest bit is set or not. The bit is only honored if you convert
this timestamp to a system_time object, i.e. the second-part is set
to 60 if the st_timestamp corresponds to a legal leap-second.

Ben Bacarisse

unread,
Nov 4, 2022, 3:50:59 PM11/4/22
to
Have you ruled out tmpnam and tmpfile?

--
Ben.

Lynn McGuire

unread,
Nov 4, 2022, 4:16:23 PM11/4/22
to
I just ported this code from F77 to C++. I totally forgot about tmpnam
and tmpfile.

Thanks,
Lynn

Keith Thompson

unread,
Nov 4, 2022, 6:05:53 PM11/4/22
to
An alternative is to keep a counter, incremented for each generated file
name, and append it to the file name, perhaps resetting to 0 when the
seconds count advances. If your only requirement is uniqueness, that
should be good enough.

Digression: I remember an implementation of gettimeofday() that did
something like that (on SunOS, maybe?). The system clock had a
resolution of 0.01 second, so the value of tv_usec on successive calls
might be:
420000
420001
420002
430000
430001
430002
...
I don't remember whether the implicit counter was per-process or
system-wide.

Bart

unread,
Nov 4, 2022, 6:31:45 PM11/4/22
to
On 04/11/2022 19:49, Bonita Montero wrote:

> #pragma once
...


Did you write 800 lines of code just for this task?

Lynn McGuire

unread,
Nov 4, 2022, 6:35:28 PM11/4/22
to
The problem is multiple instances of the same program creating the same
name files.

Lynn

Chris M. Thomasson

unread,
Nov 4, 2022, 6:56:32 PM11/4/22
to
Prepend the file names with the PID? Something to make it unique.
Perhaps a SHA2-HMAC or something.

Keith Thompson

unread,
Nov 4, 2022, 7:16:02 PM11/4/22
to
You could incorporate the process id into the file name.

There's no truly portable way to do that, but one solution for POSIX and
another for Windows is likely to be good enough.

Bonita Montero

unread,
Nov 5, 2022, 1:40:55 AM11/5/22
to
Dou you think you could get that easier ?

Opus

unread,
Nov 6, 2022, 2:54:09 PM11/6/22
to
Le 04/11/2022 à 06:06, Lynn McGuire a écrit :
> I forgot to add I would prefer a portable way if possible.  I suspect
> that is not possible though below the second resolution.

You're asking specifically on Windows, and then you now want a portable
solution. There isn't. But you could write your own compatibility layer,
calling either Windows API functions or POSIX functions. This isn't
rocket science. I've done that long ago and keep reusing it. There may
of course be many third-party code/libraries doing just that if you
don't want to do it yourself.

IME, using performance counters on Windows is the only sure way of
getting proper resolution. Any third-party code will use them in one way
or another. Why not do that yourself, it'll be only a few lines of code
to write a compatibility layer.

Lynn McGuire

unread,
Nov 14, 2022, 5:59:02 PM11/14/22
to
On 11/4/2022 8:44 AM, Scott Lurndal wrote:
"Nowadys I would use the following for gettimeofday() on Windows, which
is using GetSystemTimePreciseAsFileTime() if compiled for Windows 8 or
higher and GetSystemTimeAsFileTime() otherwise:"

I used the gettimeofday function. Works well !

Thanks,
Lynn

Keith Thompson

unread,
Nov 14, 2022, 8:36:45 PM11/14/22
to
Be aware that POSIX says gettimeofday() is obsolescent, and recommends
clock_gettime() instead.

Lynn McGuire

unread,
Nov 15, 2022, 6:26:28 PM11/15/22
to
This works fine for me:

// from:
//
https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows

struct timezone {
int tz_minuteswest;
int tz_dsttime;
};

int mygettimeofday (struct timeval *tv, struct timezone *tz)
{
if (tv) {
FILETIME filetime; /* 64-bit value representing the
number of 100-nanosecond intervals since January 1, 1601 00:00 UTC */
ULARGE_INTEGER x;
ULONGLONG usec;
static const ULONGLONG epoch_offset_us = 11644473600000000ULL; /*
microseconds betweeen Jan 1,1601 and Jan 1,1970 */

#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
GetSystemTimePreciseAsFileTime ( & filetime);
#else
GetSystemTimeAsFileTime ( & filetime);
#endif
x.LowPart = filetime.dwLowDateTime;
x.HighPart = filetime.dwHighDateTime;
usec = x.QuadPart / 10 - epoch_offset_us;
tv->tv_sec = (time_t) (usec / 1000000ULL);
tv->tv_usec = (long) (usec % 1000000ULL);
}
if (tz) {
TIME_ZONE_INFORMATION timezone;
GetTimeZoneInformation(&timezone);
tz->tz_minuteswest = timezone.Bias;
tz->tz_dsttime = 0;
}
return 0;
}

Thanks,
Lynn

Andreas

unread,
Nov 16, 2022, 7:15:14 AM11/16/22
to
Am 16.11.2022 um 00:26 schrieb Lynn McGuire:
> This works fine for me:
>
>     //  from:
>     //
> https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows
>
> struct timezone {
>     int tz_minuteswest;
>     int tz_dsttime;
> };
>
> int mygettimeofday (struct timeval *tv, struct timezone *tz)
> {
>     if (tv) {
>         FILETIME               filetime; /* 64-bit value representing
> the number of 100-nanosecond intervals since January 1, 1601 00:00 UTC */
>         ULARGE_INTEGER         x;
>         ULONGLONG              usec;
>         static const ULONGLONG epoch_offset_us = 11644473600000000ULL;
Wrong value. Correct value is 116444736000000000ULL (9 trailing zeros).

Rough estimation (1970-1601)*365*24*60*60 = 11'636'784'000 seconds
(ignoring Feb 29 in leap years). Additional 6 zeros to convert seconds
to microseconds.

Manu Raju

unread,
Nov 20, 2022, 4:39:33 PM11/20/22
to
In c# I can use this code and it works:

DateTime test = DateTime.Now;

Console.WriteLine($"Day: {test.Day}");
Console.WriteLine($"Month: {test.Month}");
Console.WriteLine($"Year: {test.Year}");
Console.WriteLine($"Hour: {test.Hour}");
Console.WriteLine($"Minute: {test.Minute}");
Console.WriteLine($"Second: {test.Second}");
Console.WriteLine($"Microseconds: {test.Microsecond}");
Console.WriteLine($"Nanoseconds: {test.Nanosecond}");
Console.WriteLine($"Ticks: {test.Ticks}");



0 new messages