115

What's the best method to print out time in C in the format 2009‐08‐10 
18:17:54.811?

sashoalm
  • 75,001
  • 122
  • 434
  • 781
Dominic Bou-Samra
  • 14,799
  • 26
  • 100
  • 156

7 Answers7

119

Use strftime().

#include <stdio.h>
#include <time.h>

int main()
{
    time_t timer;
    char buffer[26];
    struct tm* tm_info;

    timer = time(NULL);
    tm_info = localtime(&timer);

    strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
    puts(buffer);
 
    return 0;
}

For milliseconds part, have a look at this question. How to measure time in milliseconds using ANSI C?

Neuron
  • 5,141
  • 5
  • 38
  • 59
Hamid Nazari
  • 3,905
  • 2
  • 28
  • 31
  • It's an even better answer now, and props for looking up how to handle the millisecond part. I think your buffer is now a little longer than it needs to be, though. – Jack Kelly Sep 09 '10 at 03:56
  • 19
    Better to be longer than shorter :-) – paxdiablo Sep 09 '10 at 04:12
  • Superb answer. I could do all sorts of things in PHP, but knew it was all there already in C. THanks. – Vijay Kumar Kanta Jan 23 '14 at 12:43
  • 1
    Perhaps the line `time(&timer)` should rather be `timer = time(NULL);`, at least for Linux. `The tloc argument is obsolescent and should always be NULL in new code. When tloc is NULL, the call cannot fail.` – Antonin Décimo Nov 28 '16 at 16:39
  • 10
    The answer is definitely wrong in at least one case (Linux) as "struct tm" used by localtime() doesn't hold any time information below the seconds. Instead "struct timeval" used by gettimeofday() has microseconds which, divided by 1000 will yield the milliseconds. All those upvotes are really wrong and misleading! Unless someone reports under which architecture you get time details below the second with "struct tm". – EnzoR Sep 28 '17 at 10:10
44

The above answers do not fully answer the question (specifically the millisec part). My solution to this is to use gettimeofday before strftime. Note the care to avoid rounding millisec to "1000". This is based on Hamid Nazari's answer.

#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>

int main() {
  char buffer[26];
  int millisec;
  struct tm* tm_info;
  struct timeval tv;

  gettimeofday(&tv, NULL);

  millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
  if (millisec>=1000) { // Allow for rounding up to nearest second
    millisec -=1000;
    tv.tv_sec++;
  }

  tm_info = localtime(&tv.tv_sec);

  strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", tm_info);
  printf("%s.%03d\n", buffer, millisec);

  return 0;
}
Chris
  • 852
  • 1
  • 8
  • 19
  • 1
    `gettimeofday` is not available on Windows implementations – Mendes Jun 30 '16 at 22:17
  • Please add '-lm' options when you build it. – skysign Aug 03 '16 at 08:41
  • 4
    I think that buffer[24] is enough, reason is like below, YYYY:MM:DD HH:MM:SS.mmm + '\0', is 24. – skysign Aug 03 '16 at 08:47
  • 1
    @Mendes, why mentioning Windows? The question is about plain C language. This is a better answer (though not the right one), despite all those wrong upvotes! – EnzoR Sep 28 '17 at 10:13
  • Enzo: Because people do actually use windows for C programming.... (Not me though). Why is this not the "right' answer? – Chris Sep 29 '17 at 02:41
  • Caveat, with the current solution here, if the time rolls over (ex. from 8.998 to 9.001) between those two time-related calls, the results will be misleading. (Ex. 9.998 or 9.999) – user3624334 Nov 24 '19 at 18:38
  • 2
    user3624334 : Nope, you don't understand the code. There is only one request for time. I assume you mean the localtime call - it just reformats the output from gettimeofday. – Chris Nov 25 '19 at 21:49
12

time.h defines a strftime function which can give you a textual representation of a time_t using something like:

#include <stdio.h>
#include <time.h>
int main (void) {
    char buff[100];
    time_t now = time (0);
    strftime (buff, 100, "%Y-%m-%d %H:%M:%S.000", localtime (&now));
    printf ("%s\n", buff);
    return 0;
}

but that won't give you sub-second resolution since that's not available from a time_t. It outputs:

2010-09-09 10:08:34.000

If you're really constrained by the specs and do not want the space between the day and hour, just remove it from the format string.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • +1 for the expedient trick for filling out the display to the millisecond. I had a customer once that wanted me to do that, but with non-zero digits so it looked like there was significance there. I talked him out of it but agreed to put in zeros. – RBerteig Sep 09 '10 at 07:22
  • 7
    A friend of mine (not me of course) once used a similar trick - they kept statics containing the last second and "millisecond". Where the second hadn't changed from the last time, they just added a random value between 1 and 200 to millisec (making sure it didn't go past 999 of course - the actual max for the rand() was always the min of 200 and half the distance to 999). Where the second did change, they just set millisec to 0 before the add. Nice seemingly random but properly sequenced milliseconds and the customer was none the wiser :-) – paxdiablo Sep 09 '10 at 07:29
7

Following code prints with microsecond precision. All we have to do is use gettimeofday and strftime on tv_sec and append tv_usec to the constructed string.

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
int main(void) {
    struct timeval tmnow;
    struct tm *tm;
    char buf[30], usec_buf[6];
    gettimeofday(&tmnow, NULL);
    tm = localtime(&tmnow.tv_sec);
    strftime(buf,30,"%Y:%m:%dT%H:%M:%S", tm);
    strcat(buf,".");
    sprintf(usec_buf,"%dZ",(int)tmnow.tv_usec);
    strcat(buf,usec_buf);
    printf("%s",buf);
    return 0;
}
Nataraj
  • 379
  • 7
  • 18
4

trick:

    int time_len = 0, n;
    struct tm *tm_info;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    tm_info = localtime(&tv.tv_sec);
    time_len+=strftime(log_buff, sizeof log_buff, "%y%m%d %H:%M:%S", tm_info);
    time_len+=snprintf(log_buff+time_len,sizeof log_buff-time_len,".%03ld ",tv.tv_usec/1000);
2

You could use strftime, but struct tm doesn't have resolution for parts of seconds. I'm not sure if that's absolutely required for your purposes.

struct tm tm;
/* Set tm to the correct time */
char s[20]; /* strlen("2009-08-10 18:17:54") + 1 */
strftime(s, 20, "%F %H:%M:%S", &tm);
Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
1

None of the solutions on this page worked for me, I mixed them up and made them working with Windows and Visual Studio 2019, Here's How :

#include <Windows.h>
#include <time.h> 
#include <chrono>

static int gettimeofday(struct timeval* tp, struct timezone* tzp) {
    namespace sc = std::chrono;
    sc::system_clock::duration d = sc::system_clock::now().time_since_epoch();
    sc::seconds s = sc::duration_cast<sc::seconds>(d);
    tp->tv_sec = s.count();
    tp->tv_usec = sc::duration_cast<sc::microseconds>(d - s).count();
    return 0;
}

static char* getFormattedTime() {
    static char buffer[26];

    // For Miliseconds
    int millisec;
    struct tm* tm_info;
    struct timeval tv;

    // For Time
    time_t rawtime;
    struct tm* timeinfo;

    gettimeofday(&tv, NULL);

    millisec = lrint(tv.tv_usec / 1000.0);
    if (millisec >= 1000) 
    {
        millisec -= 1000;
        tv.tv_sec++;
    }

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer, 26, "%Y:%m:%d %H:%M:%S", timeinfo);
    sprintf_s(buffer, 26, "%s.%03d", buffer, millisec);

    return buffer;
}

Result :

2020:08:02 06:41:59.107

2020:08:02 06:41:59.196