MINOR: tools: add a portable timegm() alternative

timegm() is not provided everywhere and the documentation on how to
replace it is bogus as it proposes an inefficient and non-thread safe
alternative.

Here we reimplement everything needed to compute the number of seconds
since Epoch based on the broken down fields in struct tm. It is only
guaranteed to return correct values for correct inputs. It was successfully
tested with all possible 32-bit values of time_t converted to struct tm
using gmtime() and back to time_t using the legacy timegm() and this
function, and both functions always produced the same result.

Thanks to BenoƮt Garnier for an instructive discussion and detailed
explanations of the various time functions, leading to this solution.
diff --git a/include/common/standard.h b/include/common/standard.h
index f94eff9..74dc041 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -709,6 +709,27 @@
 	gmtime_r(&now, tm);
 }
 
+/* Counts a number of elapsed days since 01/01/0000 based solely on elapsed
+ * years and assuming the regular rule for leap years applies. It's fake but
+ * serves as a temporary origin. It's worth remembering that it's the first
+ * year of each period that is leap and not the last one, so for instance year
+ * 1 sees 366 days since year 0 was leap. For this reason we have to apply
+ * modular arithmetics which is why we offset the year by 399 before
+ * subtracting the excess at the end. No overflow here before ~11.7 million
+ * years.
+ */
+static inline unsigned int days_since_zero(unsigned int y)
+{
+	return y * 365 + (y + 399) / 4 - (y + 399) / 100 + (y + 399) / 400
+	       - 399 / 4 + 399 / 100;
+}
+
+/* Returns the number of seconds since 01/01/1970 0:0:0 GMT for GMT date <tm>.
+ * It is meant as a portable replacement for timegm() for use with valid inputs.
+ * Returns undefined results for invalid dates (eg: months out of range 0..11).
+ */
+extern time_t my_timegm(const struct tm *tm);
+
 /* This function parses a time value optionally followed by a unit suffix among
  * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit
  * expected by the caller. The computation does its best to avoid overflows.
diff --git a/src/standard.c b/src/standard.c
index 82b7a01..174edd2 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -2860,6 +2860,60 @@
 	return dst;
 }
 
+/* Returns the number of seconds since 01/01/1970 0:0:0 GMT for GMT date <tm>.
+ * It is meant as a portable replacement for timegm() for use with valid inputs.
+ * Returns undefined results for invalid dates (eg: months out of range 0..11).
+ */
+time_t my_timegm(const struct tm *tm)
+{
+	/* Each month has 28, 29, 30 or 31 days, or 28+N. The date in the year
+	 * is thus (current month - 1)*28 + cumulated_N[month] to count the
+	 * sum of the extra N days for elapsed months. The sum of all these N
+	 * days doesn't exceed 30 for a complete year (366-12*28) so it fits
+	 * in a 5-bit word. This means that with 60 bits we can represent a
+	 * matrix of all these values at once, which is fast and efficient to
+	 * access. The extra February day for leap years is not counted here.
+	 *
+	 * Jan : none      =  0 (0)
+	 * Feb : Jan       =  3 (3)
+	 * Mar : Jan..Feb  =  3 (3 + 0)
+	 * Apr : Jan..Mar  =  6 (3 + 0 + 3)
+	 * May : Jan..Apr  =  8 (3 + 0 + 3 + 2)
+	 * Jun : Jan..May  = 11 (3 + 0 + 3 + 2 + 3)
+	 * Jul : Jan..Jun  = 13 (3 + 0 + 3 + 2 + 3 + 2)
+	 * Aug : Jan..Jul  = 16 (3 + 0 + 3 + 2 + 3 + 2 + 3)
+	 * Sep : Jan..Aug  = 19 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3)
+	 * Oct : Jan..Sep  = 21 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2)
+	 * Nov : Jan..Oct  = 24 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2 + 3)
+	 * Dec : Jan..Nov  = 26 (3 + 0 + 3 + 2 + 3 + 2 + 3 + 3 + 2 + 3 + 2)
+	 */
+	uint64_t extra =
+		( 0ULL <<  0*5) + ( 3ULL <<  1*5) + ( 3ULL <<  2*5) + /* Jan, Feb, Mar, */
+		( 6ULL <<  3*5) + ( 8ULL <<  4*5) + (11ULL <<  5*5) + /* Apr, May, Jun, */
+		(13ULL <<  6*5) + (16ULL <<  7*5) + (19ULL <<  8*5) + /* Jul, Aug, Sep, */
+		(21ULL <<  9*5) + (24ULL << 10*5) + (26ULL << 11*5);  /* Oct, Nov, Dec, */
+
+	unsigned int y = tm->tm_year + 1900;
+	unsigned int m = tm->tm_mon;
+	unsigned long days = 0;
+
+	/* days since 1/1/1970 for full years */
+	days += days_since_zero(y) - days_since_zero(1970);
+
+	/* days for full months in the current year */
+	days += 28 * m + ((extra >> (m * 5)) & 0x1f);
+
+	/* count + 1 after March for leap years. A leap year is a year multiple
+	 * of 4, unless it's multiple of 100 without being multiple of 400. 2000
+	 * is leap, 1900 isn't, 1904 is.
+	 */
+	if ((m > 1) && !(y & 3) && ((y % 100) || !(y % 400)))
+		days++;
+
+	days += tm->tm_mday - 1;
+	return days * 86400ULL + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+}
+
 /* This function check a char. It returns true and updates
  * <date> and <len> pointer to the new position if the
  * character is found.