MINOR: time: add timeofday_as_iso_us() to return instant time as ISO

We often need ISO time + microseconds in traces and ring buffers, thus
function does this by calling gettimeofday() and keeping a cached value
of the part representing the tv_sec value, and only rewrites the microsecond
part. The cache is per-thread so it's lockless and safe to use as-is.
Some tests already show that it's easy to see 3-4 events in a single
microsecond, thus it's likely that the nanosecond version will have to
be implemented as well. But certain comments on the net suggest that
some parsers are having trouble beyond microsecond, thus for now let's
stick to the microsecond only.
diff --git a/include/common/time.h b/include/common/time.h
index 2633b1c..d6bbecb 100644
--- a/include/common/time.h
+++ b/include/common/time.h
@@ -103,6 +103,8 @@
  */
 REGPRM2 void tv_update_date(int max_wait, int interrupted);
 
+char *timeofday_as_iso_us(int pad);
+
 /*
  * sets a struct timeval to its highest value so that it can never happen
  * note that only tv_usec is necessary to detect it since a tv_usec > 999999
diff --git a/src/time.c b/src/time.c
index e830f85..1a18c76 100644
--- a/src/time.c
+++ b/src/time.c
@@ -32,6 +32,9 @@
 static THREAD_LOCAL struct timeval tv_offset;  /* per-thread time ofsset relative to global time */
 static volatile unsigned long long global_now; /* common date between all threads (32:32) */
 
+static THREAD_LOCAL unsigned int iso_time_sec;     /* last iso time value for this thread */
+static THREAD_LOCAL char         iso_time_str[28]; /* ISO time representation of gettimeofday() */
+
 /*
  * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
  */
@@ -262,6 +265,33 @@
 	return;
 }
 
+/* returns the current date as returned by gettimeofday() in ISO+microsecond
+ * format. It uses a thread-local static variable that the reader can consume
+ * for as long as it wants until next call. Thus, do not call it from a signal
+ * handler. If <pad> is non-0, a trailing space will be added. It will always
+ * return exactly 26 or 27 characters (depending on padding) and will always be
+ * zero-terminated, thus it will always fit into a 28 bytes buffer.
+ */
+char *timeofday_as_iso_us(int pad)
+{
+	struct timeval new_date;
+	struct tm tm;
+
+	gettimeofday(&new_date, NULL);
+	if (new_date.tv_sec != iso_time_sec || !new_date.tv_sec) {
+		get_localtime(new_date.tv_sec, &tm);
+		if (unlikely(strftime(iso_time_str, sizeof(iso_time_str), "%Y-%m-%dT%H:%M:%S.000000", &tm) != 26))
+			strcpy(iso_time_str, "YYYY-mm-ddTHH:MM:SS.000000"); // make the failure visible but respect format.
+		iso_time_sec = new_date.tv_sec;
+	}
+	utoa_pad(new_date.tv_usec, iso_time_str + 20, 7);
+	if (pad) {
+		iso_time_str[26] = ' ';
+		iso_time_str[27] = 0;
+	}
+	return iso_time_str;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8