Unix epoch and outputs a "broken down time" representation of
Greenwhich Meridian time as an array of numbers representing
(in this order): the year, the month (zero-based), the day of
- the month, the hour of the day, the minute of the hour, the
- second of the minute, the day of the week, and the day of the
- year -- all one-based unless otherwise stated.
+ the month (one-based), the hour of the day, the minute of the
+ hour, the second of the minute, the day of the week, and the
+ day of the year -- all one-based unless otherwise stated. The
+ day of the week number may be wrong on some systems for dates
+ before March 1st 1900, or after December 31 2099.
The `localtime` builtin works like the `gmtime` builtin, but
using the local timezone setting.
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "JQ" "1" "April 2017" "" ""
+.TH "JQ" "1" "May 2017" "" ""
.
.SH "NAME"
\fBjq\fR \- Command\-line JSON processor
Low\-level jq interfaces to the C\-library time functions are also provided: \fBstrptime\fR, \fBstrftime\fR, \fBstrflocaltime\fR, \fBmktime\fR, \fBgmtime\fR, and \fBlocaltime\fR\. Refer to your host operating system\'s documentation for the format strings used by \fBstrptime\fR and \fBstrftime\fR\. Note: these are not necessarily stable interfaces in jq, particularly as to their localization functionality\.
.
.P
-The \fBgmtime\fR builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwhich Meridian time as an array of numbers representing (in this order): the year, the month (zero\-based), the day of the month, the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year \-\- all one\-based unless otherwise stated\.
+The \fBgmtime\fR builtin consumes a number of seconds since the Unix epoch and outputs a "broken down time" representation of Greenwhich Meridian time as an array of numbers representing (in this order): the year, the month (zero\-based), the day of the month (one\-based), the hour of the day, the minute of the hour, the second of the minute, the day of the week, and the day of the year \-\- all one\-based unless otherwise stated\. The day of the week number may be wrong on some systems for dates before March 1st 1900, or after December 31 2099\.
.
.P
The \fBlocaltime\fR builtin works like the \fBgmtime\fR builtin, but using the local timezone setting\.
#endif
}
+/* Compute and set tm_wday */
+static void set_tm_wday(struct tm *tm) {
+ /*
+ * https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Gauss.27s_algorithm
+ * https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html
+ *
+ * Tested with dates from 1900-01-01 through 2100-01-01. This
+ * algorithm produces the wrong day-of-the-week number for dates in
+ * the range 1900-01-01..1900-02-28, and for 2100-01-01..2100-02-28.
+ * Since this is only needed on OS X and *BSD, we might just document
+ * this.
+ */
+ int century = (1900 + tm->tm_year) / 100;
+ int year = (1900 + tm->tm_year) % 100;
+ if (tm->tm_mon < 2)
+ year--;
+ /*
+ * The month value in the wday computation below is shifted so that
+ * March is 1, April is 2, .., January is 11, and February is 12.
+ */
+ int mon = tm->tm_mon - 1;
+ if (mon < 1)
+ mon += 12;
+ int wday =
+ (tm->tm_mday + (int)floor((2.6 * mon - 0.2)) + year + (int)floor(year / 4.0) + (int)floor(century / 4.0) - 2 * century) % 7;
+ if (wday < 0)
+ wday += 7;
+#if 0
+ /* See commentary above */
+ assert(wday == tm->tm_wday || tm->tm_wday == 8);
+#endif
+ tm->tm_wday = wday;
+}
+/*
+ * Compute and set tm_yday.
+ *
+ */
+static void set_tm_yday(struct tm *tm) {
+ static const int d[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+ int mon = tm->tm_mon;
+ int year = 1900 + tm->tm_year;
+ int leap_day = 0;
+ if (tm->tm_mon > 1 &&
+ ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
+ leap_day = 1;
+
+ /* Bound check index into d[] */
+ if (mon < 0)
+ mon = -mon;
+ if (mon > 11)
+ mon %= 12;
+
+ int yday = d[mon] + leap_day + tm->tm_mday - 1;
+ assert(yday == tm->tm_yday || tm->tm_yday == 367);
+ tm->tm_yday = yday;
+}
+
#ifdef HAVE_STRPTIME
static jv f_strptime(jq_state *jq, jv a, jv b) {
if (jv_get_kind(a) != JV_KIND_STRING || jv_get_kind(b) != JV_KIND_STRING)
return e;
}
jv_free(b);
- if ((tm.tm_wday == 8 || tm.tm_yday == 367) && my_timegm(&tm) == (time_t)-2) {
- jv_free(a);
- return jv_invalid_with_msg(jv_string("strptime/1 not supported on this platform"));
- }
+ /*
+ * This is OS X or some *BSD whose strptime() is just not that
+ * helpful!
+ *
+ * We don't know that the format string did involve parsing a
+ * year, or a month (if tm->tm_mon == 0). But with our invalid
+ * day-of-week and day-of-year sentinel checks above, the worst
+ * this can do is produce garbage.
+ */
+ if (tm.tm_wday == 8 && tm.tm_mday != 0 && tm.tm_mon >= 0 && tm.tm_mon <= 11)
+ set_tm_wday(&tm);
+ if (tm.tm_yday == 367 && tm.tm_mday != 0 && tm.tm_mon >= 0 && tm.tm_mon <= 11)
+ set_tm_yday(&tm);
jv r = tm2jv(&tm);
if (*end != '\0')
r = jv_array_append(r, jv_string(end));
# strptime() is not available on mingw/WIN32
[strptime("%Y-%m-%dT%H:%M:%SZ")|(.,mktime)]
-"2015-03-05T23:51:47Z"
[[2015,2,5,23,51,47,4,63],1425599507]
+# Check day-of-week and day of year computations
+# (should trip an assert if this fails)
+last(range(365 * 199)|("1900-03-01T01:02:03Z"|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime) + (86400 * .)|strftime("%Y-%m-%dT%H:%M:%SZ")|strptime("%Y-%m-%dT%H:%M:%SZ"))
+null
+[2099,0,10,1,2,3,6,9]
+
# %e is not available on mingw/WIN32
strftime("%A, %B %e, %Y")
1435677542.822351