0

Using Ubuntu Linux 16.04 and g++, I was wondering if could obtain microsecond or millisecond granularity when I calculate the number of nanoseconds between Unix Epoch or Windows Epoch and an arbitrary datetime. I am aware that the time_t result of time(NULL) has seconds granularity and the struct timeval result of gettimeofday has milliseconds granularity.

What other approaches are there to solving this problem? This is not a programming question. I wrote a program to test this which I can share if requested.

Any help is greatly appreciated.

  • 4
    Note that it is a programming question, and almost a copy of your previous question. Even if you did store the time in nano seconds, you hopefully don't expect that to actually be that precise! – Julie Pelletier Jun 4 '16 at 6:44
  • @Julie Pelletier, Thank you for your help. May I ask if you are implying that I cannot be that precise with microseconds in Unix & Linux? – Frank Jun 4 '16 at 6:54
  • 1
    The limitation is not coming from the operating system in itself. I haven't done any similar tests recently but when I tested the time granularity in the past, Windows was barely able to be precise at 50ms while Linux on the same machine was able to go near 5ms. Non real time systems can not be more precise than that. – Julie Pelletier Jun 4 '16 at 6:58
  • @Julie Pelletier, Thank you for your help. I will be back here after a short nap. – Frank Jun 4 '16 at 7:20
  • 1
    @mazs, Thank you for your very nice comment. What is the best approach for subtracting time in milliseconds using C++? – Frank Jun 4 '16 at 8:47
1

You can do this with gettimeofday(). This was answered on StackOverflow, which I'll quote here:

You have two choices for getting a microsecond timestamp. The first (and best) choice, is to use the timeval type directly:

struct timeval GetTimeStamp() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    return tv;
}

The second, and for me less desirable, choice is to build a uint64_t out of a timeval:

uint64_t GetTimeStamp() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    return tv.tv_sec*(uint64_t)1000000+tv.tv_usec;
}
  • Thank you for your very nice answer. I was told today the best possible time granularity for Linux is 5 millliseconds by Julie Pellletier. Also I was told that a double has 16 significant digits and the number of milliseconds since Unix Epoch has 13 significant digits. May I ask to compare clock_gettime(clockid_t clk_id, struct timespec tp) with gettimeofday(struct timeval tv, void* restrictp)? – Frank Jun 4 '16 at 10:05
  • There's a difference between the resolution available using the hardware clock and the number of digits returned by gettimeofday. It depends on whether you want an accurate number or not. – Thomas Dickey Jun 4 '16 at 10:14
  • @Thomas Dickey, Thanks for your excellent comment I need an accurate result. What is the difference between the resolution available using the hardware clock and the number of digits returned by gettimeofday. ? – Frank Jun 4 '16 at 10:51
  • As noted in a comment by @julie-pelletier, the difference is several orders of magnitude. Perhaps someone will provide a detailed answer (have to go for now). – Thomas Dickey Jun 4 '16 at 10:59
  • @Thomas Dickey, Could I ask about having a return value with int64_t and double as the fields of a union? Thank you. – Frank Jun 4 '16 at 11:51
1

My answer is to use the decimal64 format.

Quoting from https://en.wikipedia.org/wiki/Decimal64_floating-point_format:

In computing, decimal64 is a decimal floating-point computer numbering format that occupies 8 bytes (64 bits) in computer memory. It is intended for applications where it is necessary to emulate decimal rounding exactly, such as financial and tax computations.

Decimal64 supports 16 decimal digits of significand and an exponent range of −383 to +384, i.e. ±0.000000000000000×10−383 to ±9.999999999999999×10384. (Equivalently, ±0000000000000000×10−398 to ±9999999999999999×10369.) In contrast, the corresponding binary format, which is the most commonly used type, has an approximate range of ±0.000000000000001×10−308 to ±1.797693134862315×10308. Because the significand is not normalized, most values with less than 16 significant digits have multiple possible representations; 1×102=0.1×103=0.01×104, etc. Zero has 768 possible representations (1536 if you include both signed zeros).

Decimal64 floating point is a relatively new decimal floating-point format, formally introduced in the 2008 version[1] of IEEE 754 as well as with ISO/IEC/IEEE 60559:2011.

Here is a link describing how to use decimal64.

https://stackoverflow.com/questions/12865585/stddecimaldecimal64-correct-usage-g-4-6-3

  • @Julie Pelletier, Thank you for all of your help. Is this possible to do with Windows 7 Microsoft Visual C++ compiler? – Frank Jun 5 '16 at 13:47
0

The Decimal64 floating solution is the best but it requires some programming magic with anonymous unions. In order to convert decimal64 to std::string , you have to use an union(assume it has name S) with 2 members , a decimal::decimal64 input and a uint64_t (from C++99's cstdint.h ) output. Because this union has a decimal::decimal64 member which is a C++ class and requires an user-defined constructor and destructor, one has to use the new placement operator to set the input member value and cause a change in the output member value.

Also, the programmer must initialize the S object, for example named data, like this: S data = {12345678987654321ULL} so that compiler does not delete the union object behind the scenes. To complicate things more, decimal/decimal.h , does not define the inline constructor , inline decimal64::decimal64(decimal64 __r). Finally , the user has to write a global ostream operator << for decimal64.

To simplify life for myself, today I used uint64_t to represent the number of nanoseconds from Windows Epoch today. This choice fixed my int64_t numeric overflow errors.

The tradeoff between uint64_t and decimal64 is that decimal64 has much greater dynamic range than uint64_t. Also, printf of uint64_t requires a special format specifier :

   #include <inttypes.h>
    uint64_t t;
    printf("%" PRIu64 "\n", t);

Please let me know if you have questions or need a code sample.

  • @Thomas Dickey, Could you please critique the above uint64_t answer? Thank you. – Frank Jun 8 '16 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.