2010-03-09 16 views
22

¿Podría ayudarme a cómo formatear una instancia de struct timeval en un formato legible como "2010-01-01 15: 35: 10.0001"?Struct timeval a formato imprimible

+2

Duplicado de http://stackoverflow.com/questions/1469495/unix-programming-struct-timeval-how-to-print-it-c-programming? –

+6

No es un duplicado, ya que este especifica el formateo legible por humanos, apuntando a stftime, mientras que el otro simplemente extrae los segundos y los segundos. –

Respuesta

13

Convierta tv_sec usando localtime, y strftime, luego añada tv_usec parte.

1

Puede usar la función strftime para convertir una fecha y hora en una cadena.

55

Necesita anexar manualmente la parte de microsegundos, ya que no está en el struct tm con el que trata strftime(). He aquí un fragmento:

struct timeval tv; 
time_t nowtime; 
struct tm *nowtm; 
char tmbuf[64], buf[64]; 

gettimeofday(&tv, NULL); 
nowtime = tv.tv_sec; 
nowtm = localtime(&nowtime); 
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm); 
snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv.tv_usec); 

Nota cómo usamos la precisión explícita de 06 para obtener un campo microsegundos cero llenas. Dado que los microsegundos van de 0 a 999.999, siempre deben estar acolchados a 6 dígitos. No queremos tergiversar, por ej. 57 microsegundos como 570,000 (compare "1.57" frente a "1.000057").

+1

Esto se puede hacer de manera más eficiente al guardar el valor de retorno de strftime (que devuelve el número de bytes devueltos) y usarlo para indexar en el mismo buffer que luego se puede pasar a snprintf. Esto utilizaría un búfer y evitaría la copia adicional de la cadena de strftime(). –

+2

Muy útil su respuesta y, en general, todo este hilo. Solo como complemento, en la última línea tal vez sería mejor especificar '",% s.% 06ld "'. Saludos – lrleon

+1

Recibo una advertencia: el formato '% d' espera el argumento de tipo 'int', pero el argumento 5 tiene el tipo '__suseconds_t {aka long int}' [-Wformat =] en la última línea para deshacerte de él ? – bakalolo

2
ctime((const time_t *) &timeval.ts.tv_sec) 

Creo que está buscando este código, solo para su referencia.

1

Combinando las respuestas y los comentarios anteriores, el cambio de formato para ser RFC3339 según norma, y ​​la comprobación de todas las condiciones de error, se obtiene lo siguiente:

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

ssize_t format_timeval(struct timeval *tv, char *buf, size_t sz) 
{ 
    ssize_t written = -1; 
    struct tm *gm = gmtime(&tv->tv_sec); 

    if (gm) 
    { 
    written = (ssize_t)strftime(buf, sz, "%Y-%m-%dT%H:%M:%S", gm); 
    if ((written > 0) && ((size_t)written < sz)) 
    { 
     int w = snprintf(buf+written, sz-(size_t)written, ".%06dZ", tv->tv_usec); 
     written = (w > 0) ? written + w : -1; 
    } 
    } 
    return written; 
} 

int main() { 
    struct timeval tv; 
    char buf[28]; 
    if (gettimeofday(&tv, NULL) != 0) { 
    perror("gettimeofday"); 
    return 1; 
    } 
    if (format_timeval(&tv, buf, sizeof(buf)) > 0) { 
    printf("%s\n", buf); 
    // sample output: 
    // 2015-05-09T04:18:42.514551Z 
    } 
    return 0; 
} 
0

Convertir el tv_sec usando localtime_s en lugar de hora local, porque si están escribiendo una función global que puede causar algunos problemas. si su función puede trabajar en una solución multi-hilo, por favor, considere el uso de localtime_r

0

Esto es lo que yo uso:

#include <time.h> 
#include <string.h> 

#ifdef _WIN32 
#define WIN32_LEAN_AND_MEAN 
#include <windows.h> 
#include <winsock2.h> 
#define gmtime_r(ptime,ptm) (gmtime_s((ptm),(ptime)), (ptm)) 
#else 
#include <sys/time.h> 
#endif 

#define ISO8601_LEN (sizeof "1970-01-01T23:59:59.123456Z") 

char *timeval_to_str(char iso8601[restrict static ISO8601_LEN], unsigned precision, const struct timeval * restrict tv) { 
    struct tm tm; 
    if (!gmtime_r(&tv->tv_sec, &tm)) 
     return memcpy(iso8601, "Error: Year overflow", sizeof "Error: Year overflow"); 

    tm.tm_year %= 10*1000; 
    char *frac = iso8601 + strftime(iso8601, sizeof "1970-01-01T23:59:59.", "%Y-%m-%dT%H:%M:%SZ", &tm); 

    if (precision) { 
     unsigned long usecs = tv->tv_usec; 
     for (int i = precision; i < 6; i++) usecs /= 10; 
     char *spaces = frac + sprintf(frac - 1, ".%-*luZ", precision, usecs) - 3; 
     if (spaces > frac) while (*spaces == ' ') *spaces-- = '0'; 
    } 

    return iso8601; 
} 

precision especifica el ancho de la fracción de segundo. El código es y10k- y y INT_MAX -proof.