diff --git a/deps/c-timestamp/.travis.yml b/deps/c-timestamp/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..289fc2ba202cd28b08e45692294992b80fe69288
--- /dev/null
+++ b/deps/c-timestamp/.travis.yml
@@ -0,0 +1,16 @@
+language: perl
+install: "perl -V"
+before_script:
+    - "cpanm -n Test::Harness"
+    - sudo pip install cpp-coveralls --use-mirrors
+script: "make test"
+after_success:
+    - "make clean"
+    - "make gcov"
+    - coveralls --exclude t
+notifications:
+  recipients:
+    - chansen@cpan.org
+  email:
+    on_success: change
+    on_failure: always
diff --git a/deps/c-timestamp/Makefile b/deps/c-timestamp/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e4afb3f926fd1c42468768f9b5a654544ff3cdae
--- /dev/null
+++ b/deps/c-timestamp/Makefile
@@ -0,0 +1,85 @@
+CC      = cc
+GCOV    = gcov
+CFLAGS  = $(DCFLAGS) -Wall -I. -I..
+LDFLAGS += -lc $(DLDFLAGS)
+
+SOURCES = \
+	timestamp_compare.c \
+	timestamp_format.c \
+	timestamp_parse.c \
+	timestamp_valid.c \
+	timestamp_tm.c
+
+OBJECTS = \
+	timestamp_compare.o \
+	timestamp_format.o \
+	timestamp_parse.o \
+	timestamp_valid.o \
+	timestamp_tm.o
+
+HARNESS_OBJS = \
+	t/valid.o \
+	t/compare.o \
+	t/format.o \
+	t/parse_wellformed.o \
+	t/parse_malformed.o \
+	t/tm.o
+
+HARNESS_EXES = \
+	t/valid.t \
+	t/compare.t \
+	t/format.t \
+	t/parse_wellformed.t \
+	t/parse_malformed.t \
+	t/tm.t
+
+HARNESS_DEPS = \
+	$(OBJECTS) \
+	t/tap.o
+
+.SUFFIXES:
+.SUFFIXES: .o .c .t
+
+.PHONY: check-asan test gcov cover clean
+
+.o.t:
+	$(CC) $(LDFLAGS) $< $(HARNESS_DEPS) -o $@
+
+t/valid.o: \
+	$(HARNESS_DEPS) t/valid.c
+
+t/compare.o: \
+	$(HARNESS_DEPS) t/compare.c
+
+t/format.o: \
+	$(HARNESS_DEPS) t/format.c
+
+t/parse_wellformed.o: \
+	$(HARNESS_DEPS) t/parse_wellformed.c
+
+t/parse_malformed.o: \
+	$(HARNESS_DEPS) t/parse_malformed.c
+
+t/tm.o: \
+	$(HARNESS_DEPS) t/tm.c
+
+test: $(HARNESS_EXES) 
+	@prove $(HARNESS_EXES)
+
+check-asan:
+	@$(MAKE) DCFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" \
+	DLDFLAGS="-g -fsanitize=address" test
+
+gcov:
+	@$(MAKE) DCFLAGS="-O0 -g -coverage" DLDFLAGS="-coverage" test
+	@$(GCOV) $(SOURCES)
+
+cover:
+	@$(MAKE) DCFLAGS="-O0 -g --coverage" DLDFLAGS="-coverage" test
+	@$(GCOV) -abc $(SOURCES) 
+	@gcov2perl *.gcov
+	@cover --no-gcov
+
+clean:
+	rm -f $(HARNESS_DEPS) $(HARNESS_OBJS) $(HARNESS_EXES) *.gc{ov,da,no} t/*.gc{ov,da,no}
+
diff --git a/deps/c-timestamp/README.md b/deps/c-timestamp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e038b4c238eef254bd424a646cc592997f844ac1
--- /dev/null
+++ b/deps/c-timestamp/README.md
@@ -0,0 +1,25 @@
+[![Build Status](https://travis-ci.org/chansen/c-timestamp.png?branch=master)](https://travis-ci.org/chansen/c-timestamp) [![Coverage Status](https://coveralls.io/repos/chansen/c-timestamp/badge.png)](https://coveralls.io/r/chansen/c-timestamp)
+
+timestamp
+=========
+
+
+```c
+
+typedef struct {
+    int64_t sec;    /* Number of seconds since the epoch of 1970-01-01T00:00:00Z */
+    int32_t nsec;   /* Nanoseconds [0, 999999999] */
+    int16_t offset; /* Offset from UTC in minutes [-1439, 1439] */
+} timestamp_t;
+
+int         timestamp_parse            (const char *str, size_t len, timestamp_t *tsp);
+size_t      timestamp_format           (char *dst, size_t len, const timestamp_t *tsp);
+size_t      timestamp_format_precision (char *dst, size_t len, const timestamp_t *tsp, int precision);
+int         timestamp_compare          (const timestamp_t *tsp1, const timestamp_t *tsp2);
+bool        timestamp_valid            (const timestamp_t *tsp);
+struct tm * timestamp_to_tm_utc        (const timestamp_t *tsp, struct tm *tmp);
+struct tm * timestamp_to_tm_local      (const timestamp_t *tsp, struct tm *tmp);
+
+
+```
+
diff --git a/deps/c-timestamp/t/compare.c b/deps/c-timestamp/t/compare.c
new file mode 100644
index 0000000000000000000000000000000000000000..85690b5a9f12c86a0d0711526a9c171255f3a161
--- /dev/null
+++ b/deps/c-timestamp/t/compare.c
@@ -0,0 +1,25 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+int 
+main() {
+    timestamp_t t1, t2;
+
+    t1.sec    = t2.sec    = 0;
+    t1.nsec   = t2.nsec   = 0;
+    t1.offset = t2.offset = 0;
+    cmp_ok(timestamp_compare(&t1, &t2), "==", 0, "t1 == t2");
+
+    t1.sec = 1;
+    cmp_ok(timestamp_compare(&t1, &t2), ">",  0, "t1 > t2");
+    cmp_ok(timestamp_compare(&t2, &t1), "<",  0, "t1 < t2");
+
+    t1.sec  = 0;
+    t1.nsec = 1;
+    cmp_ok(timestamp_compare(&t1, &t2), ">",  0, "t1 > t2");
+    cmp_ok(timestamp_compare(&t2, &t1), "<",  0, "t2 < t1");
+
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/t/format.c b/deps/c-timestamp/t/format.c
new file mode 100644
index 0000000000000000000000000000000000000000..b32f22f2ecade8c58545ceeac1e462ce0a491528
--- /dev/null
+++ b/deps/c-timestamp/t/format.c
@@ -0,0 +1,168 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+const struct test_t {
+    timestamp_t ts;
+    int precision;
+    const char *exp;
+} tests[] = {
+    { { INT64_C(-62135596800),         0,     0 }, 0, "0001-01-01T00:00:00Z"            },
+    { { INT64_C(-62135683140),         0,  1439 }, 0, "0001-01-01T00:00:00+23:59"       },
+    { { INT64_C(-62135510460),         0, -1439 }, 0, "0001-01-01T00:00:00-23:59"       },
+    { { INT64_C(253402300799),         0,     0 }, 0, "9999-12-31T23:59:59Z"            },
+    { { INT64_C(253402214459),         0,  1439 }, 0, "9999-12-31T23:59:59+23:59"       },
+    { { INT64_C(253402387139),         0, -1439 }, 0, "9999-12-31T23:59:59-23:59"       },
+    { {                     0,         0,     0 }, 0, "1970-01-01T00:00:00Z"            },
+    { {                     1,         0,     0 }, 0, "1970-01-01T00:00:01Z"            },
+    { {                    10,         0,     0 }, 0, "1970-01-01T00:00:10Z"            },
+    { {                    60,         0,     0 }, 0, "1970-01-01T00:01:00Z"            },
+    { {                   600,         0,     0 }, 0, "1970-01-01T00:10:00Z"            },
+    { {                  3600,         0,     0 }, 0, "1970-01-01T01:00:00Z"            },
+    { {                 36000,         0,     0 }, 0, "1970-01-01T10:00:00Z"            },
+    { {                     0, 123456789,     0 }, 9, "1970-01-01T00:00:00.123456789Z"  },
+    { {                     0, 123456780,     0 }, 9, "1970-01-01T00:00:00.123456780Z"  },
+    { {                     0, 123456700,     0 }, 9, "1970-01-01T00:00:00.123456700Z"  },
+    { {                     0, 123456000,     0 }, 6, "1970-01-01T00:00:00.123456Z"     },
+    { {                     0, 123450000,     0 }, 6, "1970-01-01T00:00:00.123450Z"     },
+    { {                     0, 123400000,     0 }, 6, "1970-01-01T00:00:00.123400Z"     },
+    { {                     0, 123000000,     0 }, 3, "1970-01-01T00:00:00.123Z"        },
+    { {                     0, 120000000,     0 }, 3, "1970-01-01T00:00:00.120Z"        },
+    { {                     0, 100000000,     0 }, 3, "1970-01-01T00:00:00.100Z"        },
+    { {                     0,  10000000,     0 }, 3, "1970-01-01T00:00:00.010Z"        },
+    { {                     0,   1000000,     0 }, 3, "1970-01-01T00:00:00.001Z"        },
+    { {                     0,    100000,     0 }, 6, "1970-01-01T00:00:00.000100Z"     },
+    { {                     0,     10000,     0 }, 6, "1970-01-01T00:00:00.000010Z"     },
+    { {                     0,      1000,     0 }, 6, "1970-01-01T00:00:00.000001Z"     },
+    { {                     0,       100,     0 }, 9, "1970-01-01T00:00:00.000000100Z"  },
+    { {                     0,        10,     0 }, 9, "1970-01-01T00:00:00.000000010Z"  },
+    { {                     0,         1,     0 }, 9, "1970-01-01T00:00:00.000000001Z"  },
+    { {                     0,         9,     0 }, 9, "1970-01-01T00:00:00.000000009Z"  },
+    { {                     0,        90,     0 }, 9, "1970-01-01T00:00:00.000000090Z"  },
+    { {                     0,       900,     0 }, 9, "1970-01-01T00:00:00.000000900Z"  },
+    { {                     0,      9000,     0 }, 6, "1970-01-01T00:00:00.000009Z"     },
+    { {                     0,     90000,     0 }, 6, "1970-01-01T00:00:00.000090Z"     },
+    { {                     0,    900000,     0 }, 6, "1970-01-01T00:00:00.000900Z"     },
+    { {                     0,   9000000,     0 }, 3, "1970-01-01T00:00:00.009Z"        },
+    { {                     0,  90000000,     0 }, 3, "1970-01-01T00:00:00.090Z"        },
+    { {                     0, 900000000,     0 }, 3, "1970-01-01T00:00:00.900Z"        },
+    { {                     0, 990000000,     0 }, 3, "1970-01-01T00:00:00.990Z"        },
+    { {                     0, 999000000,     0 }, 3, "1970-01-01T00:00:00.999Z"        },
+    { {                     0, 999900000,     0 }, 6, "1970-01-01T00:00:00.999900Z"     },
+    { {                     0, 999990000,     0 }, 6, "1970-01-01T00:00:00.999990Z"     },
+    { {                     0, 999999000,     0 }, 6, "1970-01-01T00:00:00.999999Z"     },
+    { {                     0, 999999900,     0 }, 9, "1970-01-01T00:00:00.999999900Z"  },
+    { {                     0, 999999990,     0 }, 9, "1970-01-01T00:00:00.999999990Z"  },
+    { {                     0, 999999999,     0 }, 9, "1970-01-01T00:00:00.999999999Z"  },
+    { {                     0,         0,  1439 }, 0, "1970-01-01T23:59:00+23:59"       },
+    { {                     0,         0,   120 }, 0, "1970-01-01T02:00:00+02:00"       },
+    { {                     0,         0,    90 }, 0, "1970-01-01T01:30:00+01:30"       },
+    { {                     0,         0,    60 }, 0, "1970-01-01T01:00:00+01:00"       },
+    { {                     0,         0,     1 }, 0, "1970-01-01T00:01:00+00:01"       },
+    { {                     0,         0,    -1 }, 0, "1969-12-31T23:59:00-00:01"       },
+    { {                     0,         0,   -60 }, 0, "1969-12-31T23:00:00-01:00"       },
+    { {                     0,         0,   -90 }, 0, "1969-12-31T22:30:00-01:30"       },
+    { {                     0,         0,  -120 }, 0, "1969-12-31T22:00:00-02:00"       },
+    { {                     0,         0, -1439 }, 0, "1969-12-31T00:01:00-23:59"       },
+    { {             951782400,         0,     0 }, 0, "2000-02-29T00:00:00Z"            },
+    { {            1078012800,         0,     0 }, 0, "2004-02-29T00:00:00Z"            },
+};
+
+int 
+main() {
+    int i, ntests;
+    char buf[40];
+    timestamp_t ts;
+    int n;
+
+    ntests = sizeof(tests) / sizeof(*tests);
+    for (i = 0; i < ntests; i++) {
+        const struct test_t t = tests[i];
+
+        n = (int)timestamp_format(buf, sizeof(buf), &t.ts);
+        cmp_ok(n, "==", strlen(t.exp), "timestamp_format() (exp: \"%s\")", t.exp);
+        is(buf, t.exp);
+
+        n = (int)timestamp_format_precision(buf, sizeof(buf), &t.ts, t.precision);
+        cmp_ok(n, "==", strlen(t.exp), "timestamp_format_precision(%d) (exp: \"%s\")", t.precision, t.exp);
+        is(buf, t.exp);
+    }
+
+    {
+        ts.sec    = 0;
+        ts.nsec   = 0;
+        ts.offset = 0;
+        n = (int)timestamp_format_precision(buf, sizeof(buf), &ts, 9);
+        cmp_ok(n, "==", 30);
+        is(buf, "1970-01-01T00:00:00.000000000Z");
+        
+        n = (int)timestamp_format_precision(buf, sizeof(buf), &ts, 6);
+        cmp_ok(n, "==", 27);
+        is(buf, "1970-01-01T00:00:00.000000Z");
+        
+        n = (int)timestamp_format_precision(buf, sizeof(buf), &ts, 2);
+        cmp_ok(n, "==", 23);
+        is(buf, "1970-01-01T00:00:00.00Z");
+        
+        n = (int)timestamp_format_precision(buf, sizeof(buf), &ts, 1);
+        cmp_ok(n, "==", 22);
+        is(buf, "1970-01-01T00:00:00.0Z");
+    }
+
+    {
+        ts.sec    =  0;
+        ts.offset =  0;
+        ts.nsec   = -1;
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "nsec out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "nsec out of range");
+        ts.nsec   = 1000000000;
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "nsec out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "nsec out of range");
+        ts.nsec   =  0;
+        ts.offset = -23 * 60 - 60;
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "offset out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "offset out of range");
+        ts.offset = +23 * 60 + 60;
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "offset out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "offset out of range");
+        ts.offset = 0;
+        ts.sec    = INT64_C(-62135596801); /* 0000-12-31T23:59:59Z */
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "sec out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "sec out of range");
+        ts.sec    = INT64_C(253402387140); /* 10000-01-01T23:59:00Z */
+        ok(!timestamp_format(buf, sizeof(buf), &ts), "sec out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 0), "sec out of range");
+        ts.sec    =  0;
+        ts.offset =  0;
+        ts.nsec   =  0;
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, -1), "precision out of range");
+        ok(!timestamp_format_precision(buf, sizeof(buf), &ts, 10), "precision out of range");
+    }
+    
+   /*
+    *          1         2         3
+    * 12345678901234567890123456789012345 (+ null-terminator)
+    * YYYY-MM-DDThh:mm:ssZ
+    * YYYY-MM-DDThh:mm:ss±hh:mm
+    * YYYY-MM-DDThh:mm:ss.123Z
+    * YYYY-MM-DDThh:mm:ss.123±hh:mm
+    * YYYY-MM-DDThh:mm:ss.123456Z
+    * YYYY-MM-DDThh:mm:ss.123456±hh:mm
+    * YYYY-MM-DDThh:mm:ss.123456789Z
+    * YYYY-MM-DDThh:mm:ss.123456789±hh:mm
+    */
+
+    {
+        ts.sec    = 0;
+        ts.offset = 0;
+        ts.nsec   = 0;
+        ok( timestamp_format(buf, 21, &ts), "suffcient buffer size");
+        ok(!timestamp_format(buf, 20, &ts), "insufficient buffer size");
+        ts.offset = 1;
+        ok( timestamp_format(buf, 26, &ts), "suffcient buffer size");
+        ok(!timestamp_format(buf, 25, &ts), "insufficient buffer size");
+    }
+
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/t/parse_malformed.c b/deps/c-timestamp/t/parse_malformed.c
new file mode 100644
index 0000000000000000000000000000000000000000..70b751196d92266367b01271cb95da5f9a1daeeb
--- /dev/null
+++ b/deps/c-timestamp/t/parse_malformed.c
@@ -0,0 +1,61 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+const struct test_t {
+    const char *str;
+} tests[] = {
+    { ""                                },
+    { "0000-01-01T00:00:00Z"            }, /* Year < 0001                           */
+    { "0001-00-01T00:00:00Z"            }, /* Invalid month                         */
+    { "0001-13-01T00:00:00Z"            }, /* Invalid month                         */
+    { "0001-01-32T00:00:00Z"            }, /* Invalid day                           */
+    { "2013-02-29T00:00:00Z"            }, /* Invalid day                           */
+    { "1970-01-01T24:00:00Z"            }, /* Invalid hour                          */
+    { "1970-01-01T23:60:00Z"            }, /* Invalid minute                        */
+    { "1970-01-01T23:59:61Z"            }, /* Invalid second                        */
+    { "1970-01-01T23:59:59+01"          }, /* Invalid zone offset                   */
+    { "1970-01-01T23:59:59+01:"         }, /* Invalid zone offset                   */
+    { "1970-01-01T23:59:59+01:0"        }, /* Invalid zone offset                   */
+    { "1970-01-01T23:59:59+0100"        }, /* Invalid zone offset                   */
+    { "1970-01-01T23:59:59+24:00"       }, /* Zone hour > 23                        */
+    { "1970-01-01T23:59:59+01:60"       }, /* Zone minute > 59                      */
+    { "1970-01-01"                      }, /* Date only                             */
+    { "1970-01-01T23:59:59"             }, /* Zone offset is required               */
+    { "1970-01-01T23:59:59.123"         }, /* Zone offset is required               */
+    { "1970-01-01X23:59:59Z"            }, /* Invalid time designator               */
+    { "1970:01:01T23-59-59Z"            }, /* Invalid separators                    */
+    { "1970-01-01T00:00:00.Z"           }, /* Fraction must have at-least one digit */
+    { "X970-01-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "1X70-01-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "19X0-01-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "197X-01-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "1970-X1-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "1970-0X-01T00:00:00Z"            }, /* Non-digit in component                */
+    { "1970-00-X1T00:00:00Z"            }, /* Non-digit in component                */
+    { "1970-00-0XT00:00:00Z"            }, /* Non-digit in component                */
+    { "1970-01-01T0X:00:00Z"            }, /* Non-digit in component                */
+    { "1970-01-01T00:0X:00Z"            }, /* Non-digit in component                */
+    { "1970-01-01T00:00:0XZ"            }, /* Non-digit in component                */
+    { "1970-01-01T00:00:00.12345X7890Z" }, /* Non-digit in component                */
+    { "1970-01-01T00:00:00.1234567890Z" }, /* Fraction > 9 digits                   */
+    { "1970-01-01T00:00:00,123456789Z"  }, /* Decimal sign must be full stop        */
+    { "1970-01-01T00:00:00Z "           }, /* Trailing space                        */
+};
+
+int 
+main() {
+    int i, ntests;
+
+    ntests = sizeof(tests) / sizeof(*tests);
+    for (i = 0; i < ntests; i++) {
+        const struct test_t t = tests[i];
+        timestamp_t ts;
+        int ret;
+        
+        ret = timestamp_parse(t.str, strlen(t.str), &ts);
+        cmp_ok(ret, "==", 1, "timestamp_parse(\"%s\")", t.str);
+    }
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/t/parse_wellformed.c b/deps/c-timestamp/t/parse_wellformed.c
new file mode 100644
index 0000000000000000000000000000000000000000..4c48db1922f6516d1750ec41efe25807c89d5acc
--- /dev/null
+++ b/deps/c-timestamp/t/parse_wellformed.c
@@ -0,0 +1,101 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+const struct test_t {
+    timestamp_t exp;
+    const char *str;
+} tests[] = {
+    { { INT64_C(-62135596800),         0,     0 }, "0001-01-01T00:00:00Z"            },
+    { { INT64_C(-62135683140),         0,  1439 }, "0001-01-01T00:00:00+23:59"       },
+    { { INT64_C(-62135510460),         0, -1439 }, "0001-01-01T00:00:00-23:59"       },
+    { { INT64_C(253402300799),         0,     0 }, "9999-12-31T23:59:59Z"            },
+    { { INT64_C(253402214459),         0,  1439 }, "9999-12-31T23:59:59+23:59"       },
+    { { INT64_C(253402387139),         0, -1439 }, "9999-12-31T23:59:59-23:59"       },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00Z"            },
+    { {                     1,         0,     0 }, "1970-01-01T00:00:01Z"            },
+    { {                    10,         0,     0 }, "1970-01-01T00:00:10Z"            },
+    { {                    60,         0,     0 }, "1970-01-01T00:01:00Z"            },
+    { {                   600,         0,     0 }, "1970-01-01T00:10:00Z"            },
+    { {                  3600,         0,     0 }, "1970-01-01T01:00:00Z"            },
+    { {                 36000,         0,     0 }, "1970-01-01T10:00:00Z"            },
+    { {              68169600,         0,     0 }, "1972-02-29T00:00:00Z"            },
+    { {                     0, 123456789,     0 }, "1970-01-01T00:00:00.123456789Z"  },
+    { {                     0, 123456780,     0 }, "1970-01-01T00:00:00.12345678Z"   },
+    { {                     0, 123456700,     0 }, "1970-01-01T00:00:00.1234567Z"    },
+    { {                     0, 123456000,     0 }, "1970-01-01T00:00:00.123456Z"     },
+    { {                     0, 123450000,     0 }, "1970-01-01T00:00:00.12345Z"      },
+    { {                     0, 123400000,     0 }, "1970-01-01T00:00:00.1234Z"       },
+    { {                     0, 123000000,     0 }, "1970-01-01T00:00:00.123Z"        },
+    { {                     0, 120000000,     0 }, "1970-01-01T00:00:00.12Z"         },
+    { {                     0, 100000000,     0 }, "1970-01-01T00:00:00.1Z"          },
+    { {                     0,  10000000,     0 }, "1970-01-01T00:00:00.01Z"         },
+    { {                     0,   1000000,     0 }, "1970-01-01T00:00:00.001Z"        },
+    { {                     0,    100000,     0 }, "1970-01-01T00:00:00.0001Z"       },
+    { {                     0,     10000,     0 }, "1970-01-01T00:00:00.00001Z"      },
+    { {                     0,      1000,     0 }, "1970-01-01T00:00:00.000001Z"     },
+    { {                     0,       100,     0 }, "1970-01-01T00:00:00.0000001Z"    },
+    { {                     0,        10,     0 }, "1970-01-01T00:00:00.00000001Z"   },
+    { {                     0,         1,     0 }, "1970-01-01T00:00:00.000000001Z"  },
+    { {                     0,         9,     0 }, "1970-01-01T00:00:00.000000009Z"  },
+    { {                     0,        90,     0 }, "1970-01-01T00:00:00.00000009Z"   },
+    { {                     0,       900,     0 }, "1970-01-01T00:00:00.0000009Z"    },
+    { {                     0,      9000,     0 }, "1970-01-01T00:00:00.000009Z"     },
+    { {                     0,     90000,     0 }, "1970-01-01T00:00:00.00009Z"      },
+    { {                     0,    900000,     0 }, "1970-01-01T00:00:00.0009Z"       },
+    { {                     0,   9000000,     0 }, "1970-01-01T00:00:00.009Z"        },
+    { {                     0,  90000000,     0 }, "1970-01-01T00:00:00.09Z"         },
+    { {                     0, 900000000,     0 }, "1970-01-01T00:00:00.9Z"          },
+    { {                     0, 990000000,     0 }, "1970-01-01T00:00:00.99Z"         },
+    { {                     0, 999000000,     0 }, "1970-01-01T00:00:00.999Z"        },
+    { {                     0, 999900000,     0 }, "1970-01-01T00:00:00.9999Z"       },
+    { {                     0, 999990000,     0 }, "1970-01-01T00:00:00.99999Z"      },
+    { {                     0, 999999000,     0 }, "1970-01-01T00:00:00.999999Z"     },
+    { {                     0, 999999900,     0 }, "1970-01-01T00:00:00.9999999Z"    },
+    { {                     0, 999999990,     0 }, "1970-01-01T00:00:00.99999999Z"   },
+    { {                     0, 999999999,     0 }, "1970-01-01T00:00:00.999999999Z"  },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.0Z"          },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.00Z"         },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.000Z"        },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.0000Z"       },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.00000Z"      },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.000000Z"     },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.0000000Z"    },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.00000000Z"   },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00.000000000Z"  },
+    { {                     0,         0,  1439 }, "1970-01-01T23:59:00+23:59"       },
+    { {                     0,         0,   120 }, "1970-01-01T02:00:00+02:00"       },
+    { {                     0,         0,    90 }, "1970-01-01T01:30:00+01:30"       },
+    { {                     0,         0,    60 }, "1970-01-01T01:00:00+01:00"       },
+    { {                     0,         0,     1 }, "1970-01-01T00:01:00+00:01"       },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00+00:00"       },
+    { {                     0,         0,    -1 }, "1969-12-31T23:59:00-00:01"       },
+    { {                     0,         0,   -60 }, "1969-12-31T23:00:00-01:00"       },
+    { {                     0,         0,   -90 }, "1969-12-31T22:30:00-01:30"       },
+    { {                     0,         0,  -120 }, "1969-12-31T22:00:00-02:00"       },
+    { {                     0,         0, -1439 }, "1969-12-31T00:01:00-23:59"       },
+    { {                     0,         0,     0 }, "1970-01-01T00:00:00z"            },
+    { {                     0,         0,     0 }, "1970-01-01 00:00:00Z"            },
+    { {                     0,         0,     0 }, "1970-01-01t00:00:00Z"            },
+    { {                     0,         0,     0 }, "1970-01-01 00:00:00+00:00"       },
+};
+
+int 
+main() {
+    int i, ntests;
+
+    ntests = sizeof(tests) / sizeof(*tests);
+    for (i = 0; i < ntests; i++) {
+        const struct test_t t = tests[i];
+        timestamp_t ts;
+        int ret;
+        
+        ret = timestamp_parse(t.str, strlen(t.str), &ts);
+        cmp_ok(ret, "==", 0, "timestamp_parse(\"%s\")", t.str);
+        ret = timestamp_compare(&ts, &t.exp);
+        cmp_ok(ret, "==", 0, "timestamp_compare(\"%s\")", t.str);
+        cmp_ok(ts.offset, "==", t.exp.offset, "offset (%s)", t.str);
+    }
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/t/tap.c b/deps/c-timestamp/t/tap.c
new file mode 100644
index 0000000000000000000000000000000000000000..57b80389fcffdbd5de0a0acda09d23e1d20646a7
--- /dev/null
+++ b/deps/c-timestamp/t/tap.c
@@ -0,0 +1,325 @@
+/*
+libtap - Write tests in C
+Copyright (C) 2011 Jake Gelbman <gelbman@gmail.com>
+This file is licensed under the GPL v3
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "tap.h"
+
+static int expected_tests = NO_PLAN;
+static int failed_tests;
+static int current_test;
+static char *todo_mesg;
+
+static char *
+vstrdupf (const char *fmt, va_list args) {
+    char *str;
+    int size;
+    va_list args2;
+    va_copy(args2, args);
+    if (!fmt)
+        fmt = "";
+    size = vsnprintf(NULL, 0, fmt, args2) + 2;
+    str = (char *)malloc(size);
+    vsprintf(str, fmt, args);
+    va_end(args2);
+    return str;
+}
+
+void
+cplan (int tests, const char *fmt, ...) {
+    expected_tests = tests;
+    if (tests == SKIP_ALL) {
+        char *why;
+        va_list args;
+        va_start(args, fmt);
+        why = vstrdupf(fmt, args);
+        va_end(args);
+        printf("1..0 ");
+        note("SKIP %s\n", why);
+        exit(0);
+    }
+    if (tests != NO_PLAN) {
+        printf("1..%d\n", tests);
+    }
+}
+
+int
+vok_at_loc (const char *file, int line, int test, const char *fmt,
+            va_list args)
+{
+    char *name = vstrdupf(fmt, args);
+    printf("%sok %d", test ? "" : "not ", ++current_test);
+    if (*name)
+        printf(" - %s", name);
+    if (todo_mesg) {
+        printf(" # TODO");
+        if (*todo_mesg)
+            printf(" %s", todo_mesg);
+    }
+    printf("\n");
+    if (!test) {
+        if (*name)
+            diag("  Failed%s test '%s'\n  at %s line %d.",
+                todo_mesg ? " (TODO)" : "", name, file, line);
+        else
+            diag("  Failed%s test at %s line %d.",
+                todo_mesg ? " (TODO)" : "", file, line);
+        if (!todo_mesg)
+            failed_tests++;
+    }
+    free(name);
+    return test;
+}
+
+int
+ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vok_at_loc(file, line, test, fmt, args);
+    va_end(args);
+    return test;
+}
+
+static int
+mystrcmp (const char *a, const char *b) {
+    return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
+}
+
+#define eq(a, b) (!mystrcmp(a, b))
+#define ne(a, b) (mystrcmp(a, b))
+
+int
+is_at_loc (const char *file, int line, const char *got, const char *expected,
+           const char *fmt, ...)
+{
+    int test = eq(got, expected);
+    va_list args;
+    va_start(args, fmt);
+    vok_at_loc(file, line, test, fmt, args);
+    va_end(args);
+    if (!test) {
+        diag("         got: '%s'", got);
+        diag("    expected: '%s'", expected);
+    }
+    return test;
+}
+
+int
+isnt_at_loc (const char *file, int line, const char *got, const char *expected,
+             const char *fmt, ...)
+{
+    int test = ne(got, expected);
+    va_list args;
+    va_start(args, fmt);
+    vok_at_loc(file, line, test, fmt, args);
+    va_end(args);
+    if (!test) {
+        diag("         got: '%s'", got);
+        diag("    expected: anything else");
+    }
+    return test;
+}
+
+int
+cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
+               const char *fmt, ...)
+{
+    int test = eq(op, "||") ? a || b
+             : eq(op, "&&") ? a && b
+             : eq(op, "|")  ? a |  b
+             : eq(op, "^")  ? a ^  b
+             : eq(op, "&")  ? a &  b
+             : eq(op, "==") ? a == b
+             : eq(op, "!=") ? a != b
+             : eq(op, "<")  ? a <  b
+             : eq(op, ">")  ? a >  b
+             : eq(op, "<=") ? a <= b
+             : eq(op, ">=") ? a >= b
+             : eq(op, "<<") ? a << b
+             : eq(op, ">>") ? a >> b
+             : eq(op, "+")  ? a +  b
+             : eq(op, "-")  ? a -  b
+             : eq(op, "*")  ? a *  b
+             : eq(op, "/")  ? a /  b
+             : eq(op, "%")  ? a %  b
+             : diag("unrecognized operator '%s'", op);
+    va_list args;
+    va_start(args, fmt);
+    vok_at_loc(file, line, test, fmt, args);
+    va_end(args);
+    if (!test) {
+        diag("    %d", a);
+        diag("        %s", op);
+        diag("    %d", b);
+    }
+    return test;
+}
+
+static void
+vdiag_to_fh (FILE *fh, const char *fmt, va_list args) {
+    char *mesg, *line;
+    int i;
+    if (!fmt)
+        return;
+    mesg = vstrdupf(fmt, args);
+    line = mesg;
+    for (i = 0; *line; i++) {
+        char c = mesg[i];
+        if (!c || c == '\n') {
+            mesg[i] = '\0';
+            fprintf(fh, "# %s\n", line);
+            if (!c)
+                break;
+            mesg[i] = c;
+            line = mesg + i + 1;
+        }
+    }
+    free(mesg);
+    return;
+}
+
+int
+diag (const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vdiag_to_fh(stderr, fmt, args);
+    va_end(args);
+    return 0;
+}
+
+int
+note (const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vdiag_to_fh(stdout, fmt, args);
+    va_end(args);
+    return 0;
+}
+
+int
+exit_status () {
+    int retval = 0;
+    if (expected_tests == NO_PLAN) {
+        printf("1..%d\n", current_test);
+    }
+    else if (current_test != expected_tests) {
+        diag("Looks like you planned %d test%s but ran %d.",
+            expected_tests, expected_tests > 1 ? "s" : "", current_test);
+        retval = 255;
+    }
+    if (failed_tests) {
+        diag("Looks like you failed %d test%s of %d run.",
+            failed_tests, failed_tests > 1 ? "s" : "", current_test);
+        if (expected_tests == NO_PLAN)
+            retval = failed_tests;
+        else
+            retval = expected_tests - current_test + failed_tests;
+    }
+    return retval;
+}
+
+int
+bail_out (int ignore, const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    printf("Bail out!  ");
+    vprintf(fmt, args);
+    printf("\n");
+    va_end(args);
+    exit(255);
+    return 0;
+}
+
+void
+skippy (int n, const char *fmt, ...) {
+    char *why;
+    va_list args;
+    va_start(args, fmt);
+    why = vstrdupf(fmt, args);
+    va_end(args);
+    while (n --> 0) {
+        printf("ok %d ", ++current_test);
+        note("skip %s\n", why);
+    }
+    free(why);
+}
+
+void
+ctodo (int ignore, const char *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    todo_mesg = vstrdupf(fmt, args);
+    va_end(args);
+}
+
+void
+cendtodo () {
+    free(todo_mesg);
+    todo_mesg = NULL;
+}
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <regex.h>
+
+#if defined __APPLE__ || defined BSD
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* Create a shared memory int to keep track of whether a piece of code executed
+dies. to be used in the dies_ok and lives_ok macros  */
+int
+tap_test_died (int status) {
+    static int *test_died = NULL;
+    int prev;
+    if (!test_died) {
+        test_died = (int *)mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
+                                MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+        *test_died = 0;
+    }
+    prev = *test_died;
+    *test_died = status;
+    return prev;
+}
+
+int
+like_at_loc (int for_match, const char *file, int line, const char *got,
+             const char *expected, const char *fmt, ...)
+{
+    int test;
+    regex_t re;
+    va_list args;
+    int err = regcomp(&re, expected, REG_EXTENDED);
+    if (err) {
+        char errbuf[256];
+        regerror(err, &re, errbuf, sizeof errbuf);
+        fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
+                        expected, errbuf, file, line);
+        exit(255);
+    }
+    err = regexec(&re, got, 0, NULL, 0);
+    regfree(&re);
+    test = for_match ? !err : err;
+    va_start(args, fmt);
+    vok_at_loc(file, line, test, fmt, args);
+    va_end(args);
+    if (!test) {
+        if (for_match) {
+            diag("                   '%s'", got);
+            diag("    doesn't match: '%s'", expected);
+        }
+        else {
+            diag("                   '%s'", got);
+            diag("          matches: '%s'", expected);
+        }
+    }
+    return test;
+}
+#endif
+
diff --git a/deps/c-timestamp/t/tap.h b/deps/c-timestamp/t/tap.h
new file mode 100644
index 0000000000000000000000000000000000000000..89484f477fd88d4e0b5e63a5d05e7f8369553b0a
--- /dev/null
+++ b/deps/c-timestamp/t/tap.h
@@ -0,0 +1,114 @@
+/*
+libtap - Write tests in C
+Copyright (C) 2011 Jake Gelbman <gelbman@gmail.com>
+This file is licensed under the GPL v3
+*/
+
+#ifndef __TAP_H__
+#define __TAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef va_copy
+#ifdef __va_copy
+#define va_copy __va_copy
+#else
+#define va_copy(d, s) ((d) = (s))
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int     vok_at_loc      (const char *file, int line, int test, const char *fmt,
+                         va_list args);
+int     ok_at_loc       (const char *file, int line, int test, const char *fmt,
+                         ...);
+int     is_at_loc       (const char *file, int line, const char *got,
+                         const char *expected, const char *fmt, ...);
+int     isnt_at_loc     (const char *file, int line, const char *got,
+                         const char *expected, const char *fmt, ...);
+int     cmp_ok_at_loc   (const char *file, int line, int a, const char *op,
+                         int b, const char *fmt, ...);
+int     bail_out        (int ignore, const char *fmt, ...);
+void    cplan           (int tests, const char *fmt, ...);
+int     diag            (const char *fmt, ...);
+int     note            (const char *fmt, ...);
+int     exit_status     (void);
+void    skippy          (int n, const char *fmt, ...);
+void    ctodo           (int ignore, const char *fmt, ...);
+void    cendtodo        (void);
+
+#define NO_PLAN          -1
+#define SKIP_ALL         -2
+#define ok(...)          ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define is(...)          is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define isnt(...)        isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define cmp_ok(...)      cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define plan(...)        cplan(__VA_ARGS__, NULL)
+#define done_testing()   return exit_status()
+#define BAIL_OUT(...)    bail_out(0, "" __VA_ARGS__, NULL)
+#define pass(...)        ok(1, "" __VA_ARGS__)
+#define fail(...)        ok(0, "" __VA_ARGS__)
+
+#define skip(test, ...)  do {if (test) {skippy(__VA_ARGS__, NULL); break;}
+#define endskip          } while (0)
+
+#define todo(...)        ctodo(0, "" __VA_ARGS__, NULL)
+#define endtodo          cendtodo()
+
+#define dies_ok(...)     dies_ok_common(1, __VA_ARGS__)
+#define lives_ok(...)    dies_ok_common(0, __VA_ARGS__)
+
+#ifdef _WIN32
+#define like(...)        skippy(1, "like is not implemented on MSWin32")
+#define unlike           like
+#define dies_ok_common(...) \
+    skippy(1, "Death detection is not supported on MSWin32")
+#else
+#define like(...)        like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL)
+#define unlike(...)      like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL)
+int     like_at_loc     (int for_match, const char *file, int line,
+                         const char *got, const char *expected,
+                         const char *fmt, ...);
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+int tap_test_died (int status);
+#define dies_ok_common(for_death, code, ...)                \
+    do {                                                    \
+        int cpid;                                           \
+        int it_died;                                        \
+        tap_test_died(1);                                   \
+        cpid = fork();                                      \
+        switch (cpid) {                                     \
+        case -1:                                            \
+            perror("fork error");                           \
+            exit(1);                                        \
+        case 0:                                             \
+            close(1);                                       \
+            close(2);                                       \
+            code                                            \
+            tap_test_died(0);                               \
+            exit(0);                                        \
+        }                                                   \
+        if (waitpid(cpid, NULL, 0) < 0) {                   \
+            perror("waitpid error");                        \
+            exit(1);                                        \
+        }                                                   \
+        it_died = tap_test_died(0);                         \
+        if (!it_died)                                       \
+            {code}                                          \
+        ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \
+    } while (0)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/deps/c-timestamp/t/tm.c b/deps/c-timestamp/t/tm.c
new file mode 100644
index 0000000000000000000000000000000000000000..89f317ba81f07acca2c6113f99177f68056992c8
--- /dev/null
+++ b/deps/c-timestamp/t/tm.c
@@ -0,0 +1,63 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+int 
+main() {
+    timestamp_t ts;
+    struct tm tm;
+
+    {   /* 0001-01-01T12:30:45Z */
+        ts.sec    = INT64_C(-62135551755);
+        ts.nsec   = 0;
+        ts.offset = 0;
+
+        memset(&tm, 0, sizeof(tm));
+        ok(timestamp_to_tm_utc(&ts, &tm) != NULL);
+        cmp_ok(tm.tm_year,  "==", -1899, "tm_year");
+        cmp_ok(tm.tm_mon,   "==",     0, "tm_mon");
+        cmp_ok(tm.tm_mday,  "==",     1, "tm_mday");
+        cmp_ok(tm.tm_yday,  "==",     0, "tm_yday");
+        cmp_ok(tm.tm_wday,  "==",     1, "tm_wday");
+        cmp_ok(tm.tm_hour,  "==",    12, "tm_hour");
+        cmp_ok(tm.tm_min,   "==",    30, "tm_min");
+        cmp_ok(tm.tm_sec,   "==",    45, "tm_sec");
+    }
+
+    {   /* 0001-01-01T12:30:45+02:00 */
+        ts.sec    = INT64_C(-62135558955);
+        ts.nsec   = 0;
+        ts.offset = 120;
+
+        memset(&tm, 0, sizeof(tm));
+        ok(timestamp_to_tm_local(&ts, &tm) != NULL);
+        cmp_ok(tm.tm_year,  "==", -1899, "tm_year");
+        cmp_ok(tm.tm_mon,   "==",     0, "tm_mon");
+        cmp_ok(tm.tm_mday,  "==",     1, "tm_mday");
+        cmp_ok(tm.tm_yday,  "==",     0, "tm_yday");
+        cmp_ok(tm.tm_wday,  "==",     1, "tm_wday");
+        cmp_ok(tm.tm_hour,  "==",    12, "tm_hour");
+        cmp_ok(tm.tm_min,   "==",    30, "tm_min");
+        cmp_ok(tm.tm_sec,   "==",    45, "tm_sec");
+    }
+    
+    {   /* 1970-12-31T23:59:59Z */
+        ts.sec    = INT64_C(31535999);
+        ts.nsec   = 0;
+        ts.offset = 0;
+
+        memset(&tm, 0, sizeof(tm));
+        ok(timestamp_to_tm_utc(&ts, &tm) != NULL);
+        cmp_ok(tm.tm_year,  "==",    70, "tm_year");
+        cmp_ok(tm.tm_mon,   "==",    11, "tm_mon");
+        cmp_ok(tm.tm_mday,  "==",    31, "tm_mday");
+        cmp_ok(tm.tm_yday,  "==",   364, "tm_yday");
+        cmp_ok(tm.tm_wday,  "==",     4, "tm_wday");
+        cmp_ok(tm.tm_hour,  "==",    23, "tm_hour");
+        cmp_ok(tm.tm_min,   "==",    59, "tm_min");
+        cmp_ok(tm.tm_sec,   "==",    59, "tm_sec");
+    }
+
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/t/valid.c b/deps/c-timestamp/t/valid.c
new file mode 100644
index 0000000000000000000000000000000000000000..2aaae0f930f59107c400da933077c89a94fb9a63
--- /dev/null
+++ b/deps/c-timestamp/t/valid.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include "timestamp.h"
+#include "tap.h"
+
+int 
+main() {
+    timestamp_t ts;
+
+    ts.sec    =  0;
+    ts.offset =  0;
+    ts.nsec   = -1;
+    ok(!timestamp_valid(&ts), "nsec out of range");
+
+    ts.nsec   = 1000000000;
+    ok(!timestamp_valid(&ts), "nsec out of range");
+
+    ts.nsec   =  0;
+    ts.offset = -23 * 60 - 60;
+    ok(!timestamp_valid(&ts), "offset out of range");
+
+    ts.offset = +23 * 60 + 60;
+    ok(!timestamp_valid(&ts), "offset out of range");
+
+    ts.offset = 0;
+    ts.sec    = INT64_C(-62135596801); /* 0000-12-31T23:59:59Z */
+    ok(!timestamp_valid(&ts), "sec out of range");
+    ts.sec    = INT64_C(253402387140); /* 10000-01-01T23:59:00Z */
+    ok(!timestamp_valid(&ts), "sec out of range");
+
+    done_testing();
+}
+
diff --git a/deps/c-timestamp/timestamp.h b/deps/c-timestamp/timestamp.h
new file mode 100644
index 0000000000000000000000000000000000000000..b52277a468ca60eaff00eb052aa97495f957a649
--- /dev/null
+++ b/deps/c-timestamp/timestamp.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __TIMESTAMP_H__
+#define __TIMESTAMP_H__
+#include <stddef.h>
+#include <time.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    int64_t sec;    /* Number of seconds since the epoch of 1970-01-01T00:00:00Z */
+    int32_t nsec;   /* Nanoseconds [0, 999999999] */
+    int16_t offset; /* Offset from UTC in minutes [-1439, 1439] */
+} timestamp_t;
+
+int         timestamp_parse            (const char *str, size_t len, timestamp_t *tsp);
+size_t      timestamp_format           (char *dst, size_t len, const timestamp_t *tsp);
+size_t      timestamp_format_precision (char *dst, size_t len, const timestamp_t *tsp, int precision);
+int         timestamp_compare          (const timestamp_t *tsp1, const timestamp_t *tsp2);
+bool        timestamp_valid            (const timestamp_t *tsp);
+struct tm * timestamp_to_tm_utc        (const timestamp_t *tsp, struct tm *tmp);
+struct tm * timestamp_to_tm_local      (const timestamp_t *tsp, struct tm *tmp);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/deps/c-timestamp/timestamp_compare.c b/deps/c-timestamp/timestamp_compare.c
new file mode 100644
index 0000000000000000000000000000000000000000..89c8b72251519e6f708aee71dec0b1508201c9bd
--- /dev/null
+++ b/deps/c-timestamp/timestamp_compare.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "timestamp.h"
+
+int
+timestamp_compare(const timestamp_t *t1, const timestamp_t *t2) {
+    if (t1->sec < t2->sec)
+        return -1;
+    if (t1->sec > t2->sec)
+        return 1;
+    if (t1->nsec < t2->nsec)
+        return -1;
+    if (t1->nsec > t2->nsec)
+        return 1;
+    return 0;
+}
+
diff --git a/deps/c-timestamp/timestamp_format.c b/deps/c-timestamp/timestamp_format.c
new file mode 100644
index 0000000000000000000000000000000000000000..570663c008536c1c18cad6baf704d40b48500247
--- /dev/null
+++ b/deps/c-timestamp/timestamp_format.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stddef.h>
+#include "timestamp.h"
+
+static const uint16_t DayOffset[13] = {
+    0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275
+};
+
+/* Rata Die algorithm by Peter Baum */
+
+static void
+rdn_to_ymd(uint32_t rdn, uint16_t *yp, uint16_t *mp, uint16_t *dp) {
+    uint32_t Z, H, A, B;
+    uint16_t y, m, d;
+
+    Z = rdn + 306;
+    H = 100 * Z - 25;
+    A = H / 3652425;
+    B = A - (A >> 2);
+    y = (100 * B + H) / 36525;
+    d = B + Z - (1461 * y >> 2);
+    m = (535 * d + 48950) >> 14;
+    if (m > 12)
+        y++, m -= 12;
+
+    *yp = y;
+    *mp = m;
+    *dp = d - DayOffset[m];
+}
+
+#define EPOCH INT64_C(62135683200)  /* 1970-01-01T00:00:00 */
+
+static const uint32_t Pow10[10] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static size_t
+timestamp_format_internal(char *dst, size_t len, const timestamp_t *tsp, const int precision) {
+    unsigned char *p;
+    uint64_t sec;
+    uint32_t rdn, v;
+    uint16_t y, m, d;
+    size_t dlen;
+
+    dlen = sizeof("YYYY-MM-DDThh:mm:ssZ") - 1;
+    if (tsp->offset)
+        dlen += 5; /* hh:mm */
+
+    if (precision)
+        dlen += 1 + precision;
+
+    if (dlen >= len)
+        return 0;
+
+    sec = tsp->sec + tsp->offset * 60 + EPOCH;
+    rdn = sec / 86400;
+
+    rdn_to_ymd(rdn, &y, &m, &d);
+
+   /*
+    *           1
+    * 0123456789012345678
+    * YYYY-MM-DDThh:mm:ss
+    */
+    p = (unsigned char *)dst;
+    v = sec % 86400;
+    p[18] = '0' + (v % 10); v /= 10;
+    p[17] = '0' + (v %  6); v /=  6;
+    p[16] = ':';
+    p[15] = '0' + (v % 10); v /= 10;
+    p[14] = '0' + (v %  6); v /=  6;
+    p[13] = ':';
+    p[12] = '0' + (v % 10); v /= 10;
+    p[11] = '0' + (v % 10);
+    p[10] = 'T';
+    p[ 9] = '0' + (d % 10); d /= 10;
+    p[ 8] = '0' + (d % 10);
+    p[ 7] = '-';
+    p[ 6] = '0' + (m % 10); m /= 10;
+    p[ 5] = '0' + (m % 10);
+    p[ 4] = '-';
+    p[ 3] = '0' + (y % 10); y /= 10;
+    p[ 2] = '0' + (y % 10); y /= 10;
+    p[ 1] = '0' + (y % 10); y /= 10;
+    p[ 0] = '0' + (y % 10);
+    p += 19;
+
+    if (precision) {
+        v = tsp->nsec / Pow10[9 - precision];
+        switch (precision) {
+            case 9: p[9] = '0' + (v % 10); v /= 10;
+            case 8: p[8] = '0' + (v % 10); v /= 10;
+            case 7: p[7] = '0' + (v % 10); v /= 10;
+            case 6: p[6] = '0' + (v % 10); v /= 10;
+            case 5: p[5] = '0' + (v % 10); v /= 10;
+            case 4: p[4] = '0' + (v % 10); v /= 10;
+            case 3: p[3] = '0' + (v % 10); v /= 10;
+            case 2: p[2] = '0' + (v % 10); v /= 10;
+            case 1: p[1] = '0' + (v % 10);
+        }
+        p[0] = '.';
+        p += 1 + precision;
+    }
+
+    if (!tsp->offset)
+        *p++ = 'Z';
+    else {
+        if (tsp->offset < 0)
+            p[0] = '-', v = -tsp->offset;
+        else
+            p[0] = '+', v = tsp->offset;
+
+        p[5] = '0' + (v % 10); v /= 10;
+        p[4] = '0' + (v %  6); v /=  6;
+        p[3] = ':';
+        p[2] = '0' + (v % 10); v /= 10;
+        p[1] = '0' + (v % 10);
+        p += 6;
+    }
+    *p = 0;
+    return dlen;
+}
+
+/*
+ *          1         2         3
+ * 12345678901234567890123456789012345 (+ null-terminator)
+ * YYYY-MM-DDThh:mm:ssZ
+ * YYYY-MM-DDThh:mm:ss±hh:mm
+ * YYYY-MM-DDThh:mm:ss.123Z
+ * YYYY-MM-DDThh:mm:ss.123±hh:mm
+ * YYYY-MM-DDThh:mm:ss.123456Z
+ * YYYY-MM-DDThh:mm:ss.123456±hh:mm
+ * YYYY-MM-DDThh:mm:ss.123456789Z
+ * YYYY-MM-DDThh:mm:ss.123456789±hh:mm
+ */
+
+size_t
+timestamp_format(char *dst, size_t len, const timestamp_t *tsp) {
+    uint32_t f;
+    int precision;
+
+    if (!timestamp_valid(tsp))
+        return 0;
+
+    f = tsp->nsec;
+    if (!f)
+        precision = 0;
+    else {
+        if      ((f % 1000000) == 0) precision = 3;
+        else if ((f %    1000) == 0) precision = 6;
+        else                         precision = 9;
+    }
+    return timestamp_format_internal(dst, len, tsp, precision);
+}
+
+size_t
+timestamp_format_precision(char *dst, size_t len, const timestamp_t *tsp, int precision) {
+    if (!timestamp_valid(tsp) || precision < 0 || precision > 9)
+        return 0;
+    return timestamp_format_internal(dst, len, tsp, precision);
+}
+
diff --git a/deps/c-timestamp/timestamp_parse.c b/deps/c-timestamp/timestamp_parse.c
new file mode 100644
index 0000000000000000000000000000000000000000..37251b384eefaf06901eb1599b8d347b7d4faab1
--- /dev/null
+++ b/deps/c-timestamp/timestamp_parse.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stddef.h>
+#include "timestamp.h"
+
+static int
+leap_year(uint16_t y) {
+    return ((y & 3) == 0 && (y % 100 != 0 || y % 400 == 0));
+}
+
+static unsigned char
+month_days(uint16_t y, uint16_t m) {
+    static const unsigned char days[2][13] = {
+        {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+    };
+    return days[m == 2 && leap_year(y)][m];
+}
+
+static int 
+parse_2d(const unsigned char * const p, size_t i, uint16_t *vp) {
+    unsigned char d0, d1;
+    if (((d0 = p[i + 0] - '0') > 9) ||
+        ((d1 = p[i + 1] - '0') > 9))
+        return 1;
+    *vp = d0 * 10 + d1;
+    return 0;
+}
+
+static int 
+parse_4d(const unsigned char * const p, size_t i, uint16_t *vp) {
+    unsigned char d0, d1, d2, d3;
+    if (((d0 = p[i + 0] - '0') > 9) ||
+        ((d1 = p[i + 1] - '0') > 9) ||
+        ((d2 = p[i + 2] - '0') > 9) ||
+        ((d3 = p[i + 3] - '0') > 9))
+        return 1;
+    *vp = d0 * 1000 + d1 * 100 + d2 * 10 + d3;
+    return 0;
+}
+
+static const uint32_t Pow10[10] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static const uint16_t DayOffset[13] = {
+    0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275
+};
+
+int
+timestamp_parse(const char *str, size_t len, timestamp_t *tsp) {
+    const unsigned char *cur, *end;
+    unsigned char ch;
+    uint16_t year, month, day, hour, min, sec;
+    uint32_t rdn, sod, nsec;
+    int16_t offset;
+
+    /*
+     *           1
+     * 01234567890123456789
+     * 2013-12-31T23:59:59Z
+     */
+    cur = (const unsigned char *)str;
+    if (len < 20 ||
+        cur[4]  != '-' || cur[7]  != '-' ||
+        cur[13] != ':' || cur[16] != ':')
+        return 1;
+
+    ch = cur[10];
+    if (!(ch == 'T' || ch == ' ' || ch == 't'))
+        return 1;
+
+    if (parse_4d(cur,  0, &year)  || year  <  1 ||
+        parse_2d(cur,  5, &month) || month <  1 || month > 12 ||
+        parse_2d(cur,  8, &day)   || day   <  1 || day   > 31 ||
+        parse_2d(cur, 11, &hour)  || hour  > 23 ||
+        parse_2d(cur, 14, &min)   || min   > 59 ||
+        parse_2d(cur, 17, &sec)   || sec   > 59)
+        return 1;
+
+    if (day > 28 && day > month_days(year, month))
+        return 1;
+
+    if (month < 3)
+        year--;
+
+    rdn = (1461 * year)/4 - year/100 + year/400 + DayOffset[month] + day - 306;
+    sod = hour * 3600 + min * 60 + sec;
+    end = cur + len;
+    cur = cur + 19;
+    offset = nsec = 0;
+
+    ch = *cur++;
+    if (ch == '.') {
+        const unsigned char *start;
+        size_t ndigits;
+
+        start = cur;
+        for (; cur < end; cur++) {
+            const unsigned char digit = *cur - '0';
+            if (digit > 9)
+                break;
+            nsec = nsec * 10 + digit;
+        }
+
+        ndigits = cur - start;
+        if (ndigits < 1 || ndigits > 9)
+            return 1;
+
+        nsec *= Pow10[9 - ndigits];
+
+        if (cur == end)
+            return 1;
+
+        ch = *cur++;
+    }
+
+    if (!(ch == 'Z' || ch == 'z')) {
+        /*
+         *  01234
+         * ±00:00
+         */
+        if (cur + 5 < end || !(ch == '+' || ch == '-') || cur[2] != ':')
+            return 1;
+
+        if (parse_2d(cur, 0, &hour) || hour > 23 ||
+            parse_2d(cur, 3, &min)  || min  > 59)
+            return 1;
+
+        offset = hour * 60 + min;
+        if (ch == '-')
+            offset *= -1;
+
+        cur += 5;
+    }
+
+    if (cur != end)
+        return 1;
+
+    tsp->sec    = ((int64_t)rdn - 719163) * 86400 + sod - offset * 60;
+    tsp->nsec   = nsec;
+    tsp->offset = offset;
+    return 0;
+}
+
diff --git a/deps/c-timestamp/timestamp_tm.c b/deps/c-timestamp/timestamp_tm.c
new file mode 100644
index 0000000000000000000000000000000000000000..3046b730ba49134875611821877b0442bdb2ff42
--- /dev/null
+++ b/deps/c-timestamp/timestamp_tm.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stddef.h>
+#include <time.h>
+#include "timestamp.h"
+
+static const uint16_t DayOffset[13] = {
+    0, 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275
+};
+
+/* Rata Die algorithm by Peter Baum */
+
+static void
+rdn_to_struct_tm(uint32_t rdn, struct tm *tmp) {
+    uint32_t Z, H, A, B;
+    uint16_t C, y, m, d;
+
+    Z = rdn + 306;
+    H = 100 * Z - 25;
+    A = H / 3652425;
+    B = A - (A >> 2);
+    y = (100 * B + H) / 36525;
+    C = B + Z - (1461 * y >> 2);
+    m = (535 * C + 48950) >> 14;
+    if (m > 12)
+        d = C - 306, y++, m -= 12;
+    else
+        d = C + 59 + ((y & 3) == 0 && (y % 100 != 0 || y % 400 == 0));
+
+    tmp->tm_mday = C - DayOffset[m];    /* Day of month [1,31]           */
+    tmp->tm_mon  = m - 1;               /* Month of year [0,11]          */
+    tmp->tm_year = y - 1900;            /* Years since 1900              */
+    tmp->tm_wday = rdn % 7;             /* Day of week [0,6] (Sunday =0) */
+    tmp->tm_yday = d - 1;               /* Day of year [0,365]           */
+}
+
+#define RDN_OFFSET INT64_C(62135683200)  /* 1970-01-01T00:00:00 */
+
+static struct tm *
+timestamp_to_tm(const timestamp_t *tsp, struct tm *tmp, const bool local) {
+    uint64_t sec;
+    uint32_t rdn, sod;
+
+    if (!timestamp_valid(tsp))
+        return NULL;
+
+    sec = tsp->sec + RDN_OFFSET;
+    if (local)
+        sec += tsp->offset * 60;
+    rdn = sec / 86400;
+    sod = sec % 86400;
+
+    rdn_to_struct_tm(rdn, tmp);
+    tmp->tm_sec  = sod % 60; sod /= 60;
+    tmp->tm_min  = sod % 60; sod /= 60;
+    tmp->tm_hour = sod;
+    return tmp;
+}
+
+struct tm *
+timestamp_to_tm_local(const timestamp_t *tsp, struct tm *tmp) {
+    return timestamp_to_tm(tsp, tmp, true);
+}
+
+struct tm *
+timestamp_to_tm_utc(const timestamp_t *tsp, struct tm *tmp) {
+    return timestamp_to_tm(tsp, tmp, false);
+}
+
diff --git a/deps/c-timestamp/timestamp_valid.c b/deps/c-timestamp/timestamp_valid.c
new file mode 100644
index 0000000000000000000000000000000000000000..44c2648c9f2ce742abbbb37f791be8d9a616d3c6
--- /dev/null
+++ b/deps/c-timestamp/timestamp_valid.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Christian Hansen <chansen@cpan.org>
+ * <https://github.com/chansen/c-timestamp>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "timestamp.h"
+
+#define MIN_SEC INT64_C(-62135596800) /* 0001-01-01T00:00:00 */
+#define MAX_SEC INT64_C(253402300799) /* 9999-12-31T23:59:59 */
+
+bool
+timestamp_valid(const timestamp_t *tsp) {
+    const int64_t sec = tsp->sec + tsp->offset * 60;
+    if (sec < MIN_SEC || sec > MAX_SEC ||
+        tsp->nsec < 0 || tsp->nsec > 999999999 ||
+        tsp->offset < -1439 || tsp->offset > 1439)
+        return false;
+    return true;
+}
+