diff --git a/debian/libwsutil0.symbols b/debian/libwsutil0.symbols index 2aa4359818..df377b8bee 100644 --- a/debian/libwsutil0.symbols +++ b/debian/libwsutil0.symbols @@ -186,6 +186,7 @@ libwsutil.so.0 libwsutil0 #MINVER# type_util_gdouble_to_guint64@Base 1.10.0 type_util_guint64_to_gdouble@Base 1.10.0 ulaw2linear@Base 1.12.0~rc1 + unix_epoch_to_nstime@Base 3.5.0 update_adler32@Base 1.12.0~rc1 update_crc10_by_bytes@Base 1.10.0 ws_add_crash_info@Base 1.10.0 diff --git a/doc/editcap.pod b/doc/editcap.pod index 402c710176..1d7f520e1e 100644 --- a/doc/editcap.pod +++ b/doc/editcap.pod @@ -105,7 +105,8 @@ The time is given in ISO 8601 format, either YYYY-MM-DD HH:MM:SS[.nnnnnnnnn][Z|±hh:mm] or YYYY-MM-DDTHH:MM:SS[.nnnnnnnnn][Z|±hh:mm] . The fractional seconds are optional, as is the time zone offset from UTC -(in which case local time is assumed). +(in which case local time is assumed). Unix epoch timestamps +(floating point format) are also accepted. =item -B Estop timeE @@ -114,7 +115,8 @@ The time is given in ISO 8601 format, either YYYY-MM-DD HH:MM:SS[.nnnnnnnnn][Z|±hh:mm] or YYYY-MM-DDTHH:MM:SS[.nnnnnnnnn][Z|±hh:mm] . The fractional seconds are optional, as is the time zone offset from UTC -(in which case local time is assumed). +(in which case local time is assumed). Unix epoch timestamps +(floating point format) are also accepted. =item -c Epackets per fileE diff --git a/editcap.c b/editcap.c index b5f055caab..175dca693f 100644 --- a/editcap.c +++ b/editcap.c @@ -764,6 +764,7 @@ print_usage(FILE *output) fprintf(output, " given time.\n"); fprintf(output, " Time format for -A/-B options is\n"); fprintf(output, " YYYY-MM-DDThh:mm:ss[.nnnnnnnnn][Z|+-hh:mm]\n"); + fprintf(output, " Unix epoch timestamps are also supported.\n"); fprintf(output, "\n"); fprintf(output, "Duplicate packet removal:\n"); fprintf(output, " --novlan remove vlan info from packets before checking for duplicates.\n"); @@ -1284,7 +1285,7 @@ main(int argc, char *argv[]) nstime_t in_time; check_startstop = TRUE; - if (0 < iso8601_to_nstime(&in_time, optarg)) { + if ((0 < iso8601_to_nstime(&in_time, optarg)) || (0 < unix_epoch_to_nstime(&in_time, optarg))) { if (opt == 'A') { nstime_copy(&starttime, &in_time); have_starttime = TRUE; diff --git a/wsutil/nstime.c b/wsutil/nstime.c index a2939a4c30..a66ad390b0 100644 --- a/wsutil/nstime.c +++ b/wsutil/nstime.c @@ -17,6 +17,10 @@ #include "epochs.h" #include "time_util.h" +#ifndef HAVE_STRPTIME +# include "wsutil/strptime.h" +#endif + /* this is #defined so that we can clearly see that we have the right number of zeros, rather than as a guard against the number of nanoseconds in a second changing ;) */ @@ -453,6 +457,80 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr) return ret_val; } +/* + * function: unix_epoch_to_nstime + * parses a character string for a date and time given in + * a floating point number containing a Unix epoch date-time + * format (e.g. 1600000000.000 for Sun Sep 13 05:26:40 AM PDT 2020) + * and converts to an nstime_t + * returns number of chars parsed on success, or 0 on failure + * + * Reference: https://en.wikipedia.org/wiki/Unix_time + */ +guint8 +unix_epoch_to_nstime(nstime_t *nstime, const char *ptr) +{ + struct tm tm; + char *ptr_new; + + gint n_chars = 0; + guint frac = 0; + guint8 ret_val = 0; + const char *start = ptr; + + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + nstime_set_unset(nstime); + + if (!(ptr_new=strptime(ptr, "%s", &tm))) { + return 0; + } + + /* Validate what we got so far. mktime() doesn't care about strange + values (and we use this to our advantage when calculating the + time zone offset) but we should at least start with something valid */ + if (!tm_is_valid(&tm)) { + return 0; + } + + /* No UTC offset given; ISO 8601 says this means localtime */ + nstime->secs = mktime(&tm); + + /* Now let's test for fractional seconds */ + if (*ptr_new == '.' || *ptr_new == ',') { + /* Get fractional seconds */ + ptr_new++; + if (1 <= sscanf(ptr_new, "%u%n", &frac, &n_chars)) { + /* normalize frac to nanoseconds */ + if ((frac >= 1000000000) || (frac == 0)) { + frac = 0; + } else { + switch (n_chars) { /* including leading zeros */ + case 1: frac *= 100000000; break; + case 2: frac *= 10000000; break; + case 3: frac *= 1000000; break; + case 4: frac *= 100000; break; + case 5: frac *= 10000; break; + case 6: frac *= 1000; break; + case 7: frac *= 100; break; + case 8: frac *= 10; break; + default: break; + } + } + ptr_new += n_chars; + } + /* If we didn't get frac, it's still its default of 0 */ + } + else { + tm.tm_sec = 0; + } + nstime->nsecs = frac; + + /* return pointer shift */ + ret_val = (guint)(ptr_new-start); + return ret_val; +} + /* * Editor modelines * diff --git a/wsutil/nstime.h b/wsutil/nstime.h index 2292b6f811..4003a6371d 100644 --- a/wsutil/nstime.h +++ b/wsutil/nstime.h @@ -128,6 +128,11 @@ WS_DLL_PUBLIC gboolean nsfiletime_to_nstime(nstime_t *nstime, guint64 nsfiletime Note that nstime is set to unset in the case of failure */ WS_DLL_PUBLIC guint8 iso8601_to_nstime(nstime_t *nstime, const char *ptr); +/** parse an Unix epoch timestamp format datetime string to nstime, returns + number of chars parsed on success, 0 on failure. + Note that nstime is set to unset in the case of failure */ +WS_DLL_PUBLIC guint8 unix_epoch_to_nstime(nstime_t *nstime, const char *ptr); + #ifdef __cplusplus } #endif /* __cplusplus */