1

For this program I need to "grab the start time of the entire process within the max. time precision avail including nanoseconds." in the format:

April 9, 2022 13:18:17.123456789

I am able to get everything but the nanoseconds. Is it possible and/or what do you recommend?

Here is what I have:

//%B - Full Month Name
//%e - day space padded (%d 0 padded)
//$G - year (with century)
//%R - 24-hour HH:MM time, equivalent to %H:%M
//%N - nanoseconds?
//%T - ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S

#define BUFFERSIZE 256

char timeStringEnd[BUFFERSIZE] = {0};

time_t timeEnd = time(NULL);

struct tm *timePointerEnd = localtime(&timeEnd);

strftime(timeStringEnd, BUFFERSIZE, "\n%B%e, %G %T", timePointerEnd);

puts(timeStringEnd);

%N doesn't want to work. Any supplemental material/sources on using timing is much appreciated . TIA

phuclv
  • 37,963
  • 15
  • 156
  • 475
jTruBela
  • 55
  • 7
  • 3
    Does this answer your question? [Printing Time since Epoch in Nanoseconds](https://stackoverflow.com/questions/39439268/printing-time-since-epoch-in-nanoseconds) – Iłya Bursov Apr 09 '22 at 16:34
  • Succinctly — no, that doesn't answer the question relevantly. It prints a single number, not a formatted date/time as requested here. – Jonathan Leffler Apr 09 '22 at 16:55
  • @IłyaBursov although I agree with Jonathan, that is very helpful. Thank you for your contribution – jTruBela Apr 09 '22 at 17:15
  • Using `localtime()` and printing with `%B%e, %G %T` with lacks a _daylight time_ indication can make subsequent timestamp outputs look liker they step backwards when clocks going from daylight time to standard time. I recommend to use 1) `gmtime()` or 2) continue with `localtime()` and print with `%z, %Z` ... – chux - Reinstate Monica Apr 09 '22 at 17:30

1 Answers1

3

The strftime() function doesn't support sub-second times. You'll need to add that yourself. You also need to use a function that returns sub-second times — that isn't time(). Assuming you have a POSIX-ish system, you can use clock_gettime():

struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
struct tm *timePointerEnd = localtime(&tv.tv_sec);
size_t nbytes = strftime(timeStringEnd, BUFFERSIZE, "\n%B%e, %G %T", timePointerEnd);
snprintf(timeStringEnd + nbytes, sizeof(timeStringEnd) - nbytes,
         "%.9ld", tv.tv_nsec);
puts(timeStringEnd);

Note that if you want to print microseconds, you use %.6ld and tm.tv_nsec / 1000; if you want to print milliseconds, you use %.3ld and tm.tv_nsec / 1000000. Care is required.

C11 provides the timespec_get() function that does roughly the same job. It uses a struct timespec, but the arguments are slightly different. You'd pass the pointer first and specify TIME_UTC as the second argument.

If you have neither of those functions available, the (old, obsolescent) POSIX function gettimeofday() provides microsecond resolution timing. And an even older function, ftime(), also from POSIX (but removed from the standard nearly two decades ago) provides millisecond resolution timing. Both of these are often available on non-POSIX systems. Windows has other functions too.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you. I was using the timespec in another part of the program to get the start time in seconds and nanoseconds for when a function is called to eventually give me something to calculate the time elapsed. For example, if I wanted to get the total time in-between a timePointerStart and timePointerEnd including the nanoseconds would you recommend I do the nanoseconds math first and then snprintf the results after? – jTruBela Apr 09 '22 at 17:19
  • 1
    I'm torn between saying "that's a new question" and augmenting this answer with code for arithmetic on `struct timespec` structures. If you want to print the formatted time, that's done using a variant of what's shown above. If you want to calculate and print the elapsed time, you have to use different code. What format should the elapsed time be printed in? `3d 13h 12m 43.912317664s`? `306763.912317664s`? No `s` suffix to indicate the units? Or ISO 8601 'period' (aka 'interval') notation? Or what? The arithmetic is easy; the formatting choices are legion! – Jonathan Leffler Apr 09 '22 at 17:29
  • Understandable! If you want i'll give it a test first and post another question if need be but the format would be 0s.123456789ns...I think I what I "have" is the secs and nsecs using timespec binded to a struct timespec start and stop...just don't know if there is anything else built in that I could be using. – jTruBela Apr 09 '22 at 17:36
  • 1
    There are no standard functions in the POSIX or C libraries specifically for formatting time durations (the gap between two instants in time). – Jonathan Leffler Apr 09 '22 at 17:43
  • When using the timespec tm -> clock_gettime(realtime, &tm) im getting this as output: How is seconds 1649528225? and where are the first 2 digits in nanoseconds coming from? ```timespec sec - TIME Second START: 1649528225 timespec nsec - TIME Nano START: 879597000 April 9, 2022 14:17:05879597000``` – jTruBela Apr 09 '22 at 18:25
  • 1
    Assuming `struct timespec tm; clock_gettime(CLOCK_REALTIME);`, the value in `tm->tv_sec` is a `time_t` value, and will be the same as the value you'd get from `time_t now = time(0);`. It is the standard "number of seconds since The Epoch — aka 1970-01-01 00:00:00Z". The value in `tm.tv_nsec` is the fractional part of the second, represented as a value in nanoseconds between 0 and 999,999,999. When printing that, it is crucial to handle the value correctly, with `%.9ld` or equivalent. That adds leading zeros so you can distinguish between 0.100000000` and `0.000001000`, etc. – Jonathan Leffler Apr 09 '22 at 18:31
  • 1
    If you want to print microseconds, then you use `%.6ld` and `tm.tv_nsec / 1000`; if you want to print milliseconds, then you use `%.3ld` and `tm.tv_nsec / 1000000`. Care is required. – Jonathan Leffler Apr 09 '22 at 18:32
  • Oh, okay. I appreciate your help as I have learned a great deal here today. Thanks, that clarifies things for me. So, if my logic is correct, what I was seeing as the first 2 digits were 2 milliseconds followed by the nanoseconds I appended because they are included in the epoch time? – jTruBela Apr 09 '22 at 18:52
  • Probably — that's about the best I can say. I'm glad my commentary has been some help. Handling time well is an intricate process — one that requires clarity in understanding exactly what you're seeking as information. – Jonathan Leffler Apr 09 '22 at 18:55
  • @jTruBela "total time in-between a timePointerStart and timePointerEnd including the nanoseconds" --> `double diff_in_seconds = difftime(end.tv_sec, start.tv_sec) + (end.tv_nsec - start.tv_nsec)/1.0e9`. Then `printf("%.9f seconds\n", diff_in_seconds);`. – chux - Reinstate Monica Apr 09 '22 at 20:32
  • @chux-ReinstateMonica: With 10 decimal digits required for the number of seconds and 9 for the fractional part, you could run into problems with the number of digits that a `double` can store. That said, if you're dealing with current measurements, you're unlikely to have numbers of seconds that are so different, but it is worth keeping that in mind. – Jonathan Leffler Apr 09 '22 at 22:28
  • @JonathanLeffler I hate to rehash things but I was tasked with finding this in a shell script and wonder if I can pick your brain again – jTruBela May 08 '22 at 01:40
  • If you've got GNU `date`, you can use `date --rfc-3339=ns` to get the current time specified to nanoseconds. That doesn't give you options for milliseconds or microseconds. If you want that level of control, you will have to roll your own. – Jonathan Leffler May 08 '22 at 03:38