{"thread":{"id":"45241","subject":"[PATCH 5/6] ref-filter: avoid using `unsigned long` for catch-all data type","startedAt":"2017-02-27T21:34:29Z","lastAt":"2017-05-22T13:40:03Z","messageCount":113,"participants":["Johannes Schindelin","Junio C Hamano","Jeff King","René Scharfe","Torsten Bögershausen","Jacob Keller","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"312776","messageId":"bcc49c57cbe4c438d95cccd1cc94693431674e5b.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 5/6] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:31:42Z","receivedAt":"2017-02-27T21:34:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply use `uintmax_t` instead.\n\nUnfortunately, this patch is larger than that because the field's name\nwas tied to its data type.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 07c1f372351..b8b34d4dd9e 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -236,7 +236,7 @@ struct atom_value {\n \t\tstruct align align;\n \t} u;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n };\n \n /*\n@@ -492,7 +492,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -539,8 +539,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -644,11 +644,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1583,9 +1583,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n\n"},{"id":"312777","messageId":"d3bc8b3ad88e5d63c38b1eaa5054e6665d62d6d8.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 4/6] Prepare for timestamps to use 64-bit signed types","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:31:36Z","receivedAt":"2017-02-27T21:34:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code uses the unsigned long type to represent\ntimestamps. However, this type is limited to 32-bit e.g. on 64-bit\nWindows. Hence it is a suboptimal type for this use case.\n\nIn any case, we need to use the time_t type to represent timestamps\nsince we often send those values to system functions which are declared\nto accept time_t parameters.\n\nSo let's prepare for the case where timestamps are represented as 64-bit\nsigned integers by introducing the Makefile option TIME_T_IS_INT64.\n\nAs we have to resort to using `strtoull()` (and casting the parsed,\nunsigned value to an `int64_t`), the check in the `date_overflows()`\nhelper has to be relaxed: a value of ULLONG_MAX (cast to `int64_t`)\nnow *also* indicates an overflow.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Makefile                   | 4 ++++\n archive-tar.c              | 5 ++++-\n builtin/name-rev.c         | 2 +-\n builtin/prune.c            | 2 +-\n builtin/worktree.c         | 2 +-\n credential-cache--daemon.c | 2 +-\n date.c                     | 8 ++++----\n git-compat-util.h          | 7 +++++++\n ref-filter.c               | 2 +-\n 9 files changed, 24 insertions(+), 10 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 8e4081e0619..0232cf62d33 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1518,6 +1518,10 @@ ifdef HAVE_GETDELIM\n \tBASIC_CFLAGS += -DHAVE_GETDELIM\n endif\n \n+ifdef TIME_T_IS_INT64\n+\tBASIC_CFLAGS += -DTIME_T_IS_INT64\n+endif\n+\n ifeq ($(TCLTK_PATH),)\n NO_TCLTK = NoThanks\n endif\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..695339a2369 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n #define USTAR_MAX_SIZE 077777777777UL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex cd89d48b65e..a0f16407b93 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -145,7 +145,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\tunsigned long taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 8f4f0522856..1e5eb0292b1 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 831fe058a53..3df95e112e5 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..b298ac01e4f 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -52,7 +52,7 @@ static int check_expirations(void)\n \tstatic unsigned long wait_for_entry_until;\n \tint i = 0;\n \tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\tunsigned long next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\ndiff --git a/date.c b/date.c\nindex 97ab5fcc349..23dee2964c1 100644\n--- a/date.c\n+++ b/date.c\n@@ -659,7 +659,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -1184,8 +1184,8 @@ int date_overflows(unsigned long t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 4365012c536..5cf1133532d 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,15 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#ifdef TIME_T_IS_INT64\n+#define PRItime PRId64\n+#define parse_timestamp strtoull\n+#define TIME_MAX INT64_MAX\n+#else\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n+#endif\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 6fab0db5e0d..07c1f372351 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -638,7 +638,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n\n"},{"id":"312778","messageId":"f4ff525dda1964dd0e7cef1d0507e1f2403469e1.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 3/6] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:31:31Z","receivedAt":"2017-02-27T21:34:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\nto using time_t instead.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\n\"lu\") so that it is easy later on to change the data type to time_t.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 11 files changed, 27 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex cffc6265408..c9486dd580b 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1736,11 +1736,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1853,7 +1853,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 1a5caccd0f5..5413c76e7a6 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 55d20cc2d88..24612c2299a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -903,7 +903,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 1dbb8a06922..4a878645847 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -456,12 +456,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/date.c b/date.c\nindex a8848f6e141..97ab5fcc349 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 601f0779a19..54fb35e39c5 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -357,7 +357,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 5eff97bea2e..4365012c536 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 98637053760..ba309ec1760 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -52,7 +52,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 8c47dc1707a..c2be661f6d4 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -859,7 +859,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n\n"},{"id":"312781","messageId":"cover.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":null,"subject":"[PATCH 0/6] Use time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:30:20Z","receivedAt":"2017-02-27T21:50:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as `time_t` exists, and at\nleast on 64-bit Windows it is 64-bit. Meaning: we *can* support these\nabsurd future dates on those platforms.\n\nSo let's do this.\n\nOne notable fallout of this patch series is that on 64-bit Linux (and\nother platforms where `unsigned long` is 64-bit), we now limit the range\nof dates to LONG_MAX (i.e. the *signed* maximum value). This needs to be\ndone as `time_t` can be signed (and indeed is at least on my Ubuntu\nsetup).\n\nObviously, I think that we can live with that, and I hope that all\ninterested parties agree.\n\n\nJohannes Schindelin (6):\n  t0006 & t5000: prepare for 64-bit time_t\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Prepare for timestamps to use 64-bit signed types\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  Use time_t where appropriate\n\n Documentation/technical/api-parse-options.txt |  8 +--\n Makefile                                      |  4 ++\n archive-tar.c                                 |  5 +-\n builtin/am.c                                  |  4 +-\n builtin/blame.c                               | 14 ++---\n builtin/fsck.c                                |  6 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  4 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +-\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        | 10 +--\n builtin/reflog.c                              | 24 +++----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  4 +-\n cache.h                                       | 14 ++---\n commit.c                                      | 16 ++---\n commit.h                                      |  2 +-\n config.mak.uname                              |  2 +\n credential-cache--daemon.c                    | 12 ++--\n date.c                                        | 90 +++++++++++++--------------\n fetch-pack.c                                  |  8 +--\n fsck.c                                        |  2 +-\n git-compat-util.h                             | 10 +++\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  4 +-\n reachable.c                                   | 10 ++-\n reachable.h                                   |  4 +-\n ref-filter.c                                  | 22 +++----\n reflog-walk.c                                 |  8 +--\n refs.c                                        | 14 ++---\n refs.h                                        |  8 +--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +-\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +-\n t/helper/test-date.c                          | 11 ++--\n t/helper/test-parse-options.c                 |  4 +-\n t/t0006-date.sh                               |  4 +-\n t/t5000-tar-tree.sh                           |  6 +-\n t/test-lib.sh                                 |  2 +\n tag.c                                         |  4 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  8 +--\n vcs-svn/fast_export.c                         |  8 +--\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 51 files changed, 221 insertions(+), 199 deletions(-)\n\n\nbase-commit: e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v1\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v1\n\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n"},{"id":"312782","messageId":"12b60c14dad15e3252e314771b3fe369305bbfc5.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 2/6] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:30:32Z","receivedAt":"2017-02-27T21:50:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using `time_t` instead, let's introduce a\nsymbol `parse_timestamp` (currently being defined to `strtoul`) where\nappropriate, so that we can later easily switch to use `strtoull()`\ninstead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c         | 2 +-\n bundle.c             | 2 +-\n commit.c             | 4 ++--\n date.c               | 6 +++---\n fsck.c               | 2 +-\n git-compat-util.h    | 2 ++\n pretty.c             | 2 +-\n ref-filter.c         | 2 +-\n t/helper/test-date.c | 2 +-\n tag.c                | 2 +-\n upload-pack.c        | 2 +-\n 11 files changed, 15 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 31fb60578f6..75e2d939036 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -882,7 +882,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 2cf85158b48..7f56b643704 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -90,7 +90,7 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \tif (buf >= tail)\n \t\treturn 0;\n \t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -608,7 +608,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..a8848f6e141 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\ttime_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex 939792752bf..33a66e68a83 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -690,7 +690,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex ef6d560e156..5eff97bea2e 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex 5e683830d9d..6d1e1e87e7d 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3820b21cc75..6fab0db5e0d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -637,7 +637,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..98637053760 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -33,7 +33,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..55d07725777 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -111,7 +111,7 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \tif (buf >= tail)\n \t\treturn 0;\n \t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 7597ba3405e..8c47dc1707a 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n\n"},{"id":"312790","messageId":"3871d1d9de0315a1a98bce5d8f544a5e18917f25.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 1/6] t0006 & t5000: prepare for 64-bit time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:30:26Z","receivedAt":"2017-02-27T22:28:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply does not use `time_t`, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) forced the test cases\nto be skipped that require a 64-bit (or larger) data type to be used to\nrepresent the time.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, when we\nwill have switched to using `time_t` where appropriate, we can flip that\nprerequisite to test `time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 86d77c16dd3..6151a3d70f8 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1163,3 +1163,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.11.1.windows.1.379.g44ae0bc\n\n\n"},{"id":"312797","messageId":"xmqqwpcbmfai.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"12b60c14dad15e3252e314771b3fe369305bbfc5.1488231002.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 2/6] Specify explicitly where we parse timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T22:37:09Z","receivedAt":"2017-02-27T22:45:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Currently, Git's source code represents all timestamps as `unsigned\n> long`. In preparation for using `time_t` instead, let's introduce a\n> symbol `parse_timestamp` (currently being defined to `strtoul`) where\n> appropriate, so that we can later easily switch to use `strtoull()`\n> instead.\n\nThis definitely is a very good thing to do as a separate step.\n\n> diff --git a/date.c b/date.c\n> index a996331f5b3..a8848f6e141 100644\n> --- a/date.c\n> +++ b/date.c\n> ...\n> @@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n>  \t\t\t\t     time_t now)\n>  {\n>  \tchar *end;\n> -\tunsigned long number = strtoul(date, &end, 10);\n> +\ttime_t number = parse_timestamp(date, &end, 10);\n\nThis hunk does not belong to this step.  Everybody else in this step\nstill receives parse_timestamp()'s return value in ulong, not time_t.\nI presume that that will happen in the final step 6/6 (which could\nbe a huge patch that exceeds 100k?)\n"},{"id":"312798","messageId":"xmqqh93fmemg.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"xmqqwpcbmfai.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/6] Specify explicitly where we parse timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T22:51:35Z","receivedAt":"2017-02-27T22:52:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> -\tunsigned long number = strtoul(date, &end, 10);\n>> +\ttime_t number = parse_timestamp(date, &end, 10);\n>\n> This hunk does not belong to this step.  Everybody else in this step\n\nobviously I meant \"the left half of this hunk\" ;-)\n\n> still receives parse_timestamp()'s return value in ulong, not time_t.\n> I presume that that will happen in the final step 6/6 (which could\n> be a huge patch that exceeds 100k?)\n"},{"id":"312799","messageId":"xmqqd1e3mefm.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"3871d1d9de0315a1a98bce5d8f544a5e18917f25.1488231002.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 1/6] t0006 & t5000: prepare for 64-bit time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T22:55:41Z","receivedAt":"2017-02-27T22:55:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> This quick fix, however, tests for *long* to be 64-bit or not. What we\n> need, though, is a test that says whether *whatever data type we use for\n> timestamps* is 64-bit or not.\n>\n> The same quick fix was used to handle the similar problem where Git's\n> source code uses `unsigned long` to represent size, instead of `size_t`.\n>\n> So let's just add another prerequisite to test specifically whether\n> timestamps are represented by a 64-bit data type or not. Later, when we\n> will have switched to using `time_t` where appropriate, we can flip that\n> prerequisite to test `time_t` instead of `long`.\n\nThe changes that move from LONG_IS to TIME_IS in this patch are all\nabout time (iow, LONG_IS_64BIT prereq is still used in the check on\nsizes).  The patch looks sensible.\n\n"},{"id":"312804","messageId":"75efe76cbb0636741a7c3aec9e21459bc1dc3cbe.1488231002.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH 6/6] Use time_t where appropriate","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-27T21:31:51Z","receivedAt":"2017-02-27T23:53:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. That causes a lot of problems, in particular where unsigned long\nis only 32-bit (notably on Windows, even in 64-bit versions).\n\nSo let's just use time_t instead.\n\nNote that in some systems (most notably 32-bit Linux), time_t is *still*\nonly 32-bit.\n\nTherefore, it might seem desirable to simply replace unsigned long by\nint64_t when working with timestamps, but that comes with its own set of\nproblems, as we often interact with the system's date functions that\n*do* use time_t.\n\nSo let's just stick with time_t.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs `time_t` can be signed, we now have to switch to using LONG_MAX as\nthe maximum timestamp lest expressions like `timestamp < TIME_MAX`\nevaluate to false. Technically, this introduces a limitation on\nplatforms where we used 64-bit unsigned longs to represent timestamps\nbefore. Practically, however, this simply unifies the behavior with\nplatforms where `time_t` is signed (and where sending too large\ntimestamps to libc functions would fail).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++---\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++---\n builtin/fsck.c                                |  4 +--\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 ++--\n builtin/pack-objects.c                        |  4 +--\n builtin/prune.c                               |  2 +-\n builtin/receive-pack.c                        |  6 ++--\n builtin/reflog.c                              | 24 ++++++-------\n builtin/show-branch.c                         |  4 +--\n builtin/worktree.c                            |  2 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 ++++----\n commit.c                                      | 12 +++----\n commit.h                                      |  2 +-\n config.mak.uname                              |  2 ++\n credential-cache--daemon.c                    | 12 +++----\n date.c                                        | 50 +++++++++++++--------------\n fetch-pack.c                                  |  6 ++--\n git-compat-util.h                             |  2 +-\n http-backend.c                                |  4 +--\n parse-options-cb.c                            |  4 +--\n pretty.c                                      |  2 +-\n reachable.c                                   | 10 +++---\n reachable.h                                   |  4 +--\n ref-filter.c                                  |  2 +-\n reflog-walk.c                                 |  8 ++---\n refs.c                                        | 14 ++++----\n refs.h                                        |  8 ++---\n refs/files-backend.c                          |  4 +--\n revision.c                                    |  6 ++--\n revision.h                                    |  4 +--\n sha1_name.c                                   |  6 ++--\n t/helper/test-date.c                          |  4 +--\n t/helper/test-parse-options.c                 |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +--\n vcs-svn/fast_export.c                         |  4 +--\n vcs-svn/fast_export.h                         |  4 +--\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 45 files changed, 140 insertions(+), 140 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 27bd701c0d6..28c9a64fc11 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -178,13 +178,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &time_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `time_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &time_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `time_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 75e2d939036..c3e0a4816e4 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -877,7 +877,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttime_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex c9486dd580b..33701a1353e 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1570,13 +1570,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttime_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttime_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1587,7 +1587,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttime_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1846,7 +1846,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(time_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 5413c76e7a6..42452744d67 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,\n-\tunsigned long timestamp)\n+\ttime_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1,\n }\n \n static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, time_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 331f2192607..7be9d106c0b 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -67,7 +67,7 @@ static void git_config_date_string(const char *key, const char **output)\n \tif (git_config_get_string_const(key, output))\n \t\treturn;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttime_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 24612c2299a..c0d3143d0e3 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -904,7 +904,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (time_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex b572a37c261..5a9580230c8 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(unsigned char *sha1, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, time_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex a0f16407b93..5faafeda96f 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttime_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, time_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -145,7 +145,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = TIME_MAX;\n+\ttime_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 8841f8b366b..e46ed73f51b 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static time_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2593,7 +2593,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct sha1_array recent_objects;\n \n static int loosened_object_can_be_discarded(const unsigned char *sha1,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    time_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 1e5eb0292b1..a8babb1f201 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static time_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 4a878645847..1b21617c601 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -77,7 +77,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static time_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -451,7 +451,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, time_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -493,7 +493,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttime_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 7a7136e53e2..331c874174e 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static time_t default_reflog_expire;\n+static time_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttime_t expire_total;\n+\ttime_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttime_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, time_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttime_t expire_total;\n+\ttime_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, time_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttime_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttime_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, time_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 974f3403abe..512b5e3db34 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -742,7 +742,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttime_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -753,7 +753,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttime_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 3df95e112e5..f12a0e4689c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static time_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..75b82e6b653 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttime_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex 61fc86e6d71..a276d1ea1b0 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1361,18 +1361,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(time_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(time_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, time_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, time_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+time_t approxidate_careful(const char *, int *);\n+time_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(time_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 7f56b643704..ab379e9d6f4 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static time_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -474,8 +474,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttime_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttime_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -599,7 +599,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttime_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -622,8 +622,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttime_t a_date = *(author_date_slab_at(author_date, a));\n+\ttime_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 9c12abb9111..7b2d3d0b8a8 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttime_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.mak.uname b/config.mak.uname\nindex 447f36ac2e3..ea1a71a936b 100644\n--- a/config.mak.uname\n+++ b/config.mak.uname\n@@ -370,6 +370,7 @@ ifeq ($(uname_S),Windows)\n \tNO_INET_PTON = YesPlease\n \tNO_INET_NTOP = YesPlease\n \tNO_POSIX_GOODIES = UnfortunatelyYes\n+\tTIME_T_IS_INT64 = YesItIs\n \tNATIVE_CRLF = YesPlease\n \tDEFAULT_HELP_FORMAT = html\n \n@@ -520,6 +521,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n \tNO_INET_PTON = YesPlease\n \tNO_INET_NTOP = YesPlease\n \tNO_POSIX_GOODIES = UnfortunatelyYes\n+\tTIME_T_IS_INT64 = YesItIs\n \tDEFAULT_HELP_FORMAT = html\n \tCOMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32\n \tCOMPAT_CFLAGS += -DSTRIP_EXTENSION=\\\".exe\\\"\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex b298ac01e4f..364e5e0c5be 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttime_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static time_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic time_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = TIME_MAX;\n+\ttime_t now = time(NULL);\n+\ttime_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttime_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 23dee2964c1..dad2d0c807e 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(time_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(time_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(time_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(time_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttime_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttime_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttime_t years = totalmonths / 12;\n+\t\ttime_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(time_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(time_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttime_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(time_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,10 +650,10 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, time_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttime_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, time_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttime_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, time_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1114,7 +1114,7 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n+static time_t approxidate_str(const char *date,\n \t\t\t\t     const struct timeval *tv,\n \t\t\t\t     int *error_ret)\n {\n@@ -1151,9 +1151,9 @@ static unsigned long approxidate_str(const char *date,\n \treturn update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+time_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+time_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,7 +1180,7 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(time_t t)\n {\n \ttime_t sys;\n \ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 54fb35e39c5..d3401733b05 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -356,7 +356,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttime_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -545,7 +545,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t time_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -630,7 +630,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttime_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 5cf1133532d..027f3b2f8eb 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -326,7 +326,7 @@ extern char *gitdirname(char *);\n #else\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n-#define TIME_MAX ULONG_MAX\n+#define TIME_MAX LONG_MAX\n #endif\n \n #ifndef PATH_SEP\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..4e88735a9e3 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, time_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttime_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex b7d8f7dcb2c..a560d8d0b8c 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(time_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (time_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 6d1e1e87e7d..ab689009536 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttime_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex d0199cace4a..f4d2be6beb7 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,12 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n };\n \n static void add_recent_object(const unsigned char *sha1,\n-\t\t\t      unsigned long mtime,\n-\t\t\t      struct recent_data *data)\n+\t\t\t      time_t mtime, struct recent_data *data)\n {\n \tstruct object *obj;\n \tenum object_type type;\n@@ -139,7 +138,7 @@ static int add_recent_packed(const unsigned char *sha1,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   time_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +155,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    time_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..2a7f6588941 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  time_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   time_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex b8b34d4dd9e..265b7c03845 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -618,7 +618,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex a246af27678..d1a8673c348 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tunsigned char osha1[20], nsha1[20];\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttime_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, time_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttime_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttime_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex cd36b64ed93..546e9080555 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -658,7 +658,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttime_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -667,15 +667,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttime_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttime_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, time_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -722,7 +722,7 @@ static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n }\n \n static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, time_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -742,9 +742,9 @@ static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, time_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttime_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 9fbff90e79b..1748827a7ba 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -262,9 +262,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttime_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttime_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int reflog_exists(const char *refname);\n@@ -293,7 +293,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tunsigned char *old_sha1, unsigned char *new_sha1,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, time_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);\n@@ -536,7 +536,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  time_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex c041d4ba21a..4316de3a692 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3115,7 +3115,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tunsigned char osha1[20], nsha1[20];\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tint tz;\n \n \t/* old SP new SP name <email> SP time TAB msg LF */\n@@ -3940,7 +3940,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, time_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex b37dbec378f..419d5fa954e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, time_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttime_t date = ~0ul;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)\n }\n \n static int handle_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, time_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(osha1, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 9fac1a607de..e39e5b524bb 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttime_t max_age;\n+\ttime_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 73a915ff1b3..9520586139e 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -658,8 +658,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttime_t at_time;\n+\t\ttime_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1052,7 +1052,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, time_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ba309ec1760..371f9d259c6 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -47,7 +47,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttime_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -95,7 +95,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..8af62dd7501 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static time_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/tag.c b/tag.c\nindex 55d07725777..a0b22c788b6 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static time_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..aaf56849de8 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttime_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex c2be661f6d4..4dcc6aa8d95 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static time_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttime_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5df87ce6bb4 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, time_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttime_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..864dada2b31 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, time_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttime_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..9e1eb8d4176 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttime_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex d47012048f8..da261363551 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1374,7 +1374,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, time_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.11.1.windows.1.379.g44ae0bc\n"},{"id":"312809","messageId":"xmqqlgsrmesc.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-27T22:48:03Z","receivedAt":"2017-02-28T00:50:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> One notable fallout of this patch series is that on 64-bit Linux (and\n> other platforms where `unsigned long` is 64-bit), we now limit the range\n> of dates to LONG_MAX (i.e. the *signed* maximum value). This needs to be\n> done as `time_t` can be signed (and indeed is at least on my Ubuntu\n> setup).\n>\n> Obviously, I think that we can live with that, and I hope that all\n> interested parties agree.\n\ns/ulong/time_t/ is definintely a good change, and it will take us to\na place we would want to be in in some future.  \n\nAs long as there remains no platform we care about whose time_t and\nlong are still 32-bit signed integer, there will be a fallout to\nthem with this change.  Probably it is of a larger impact than\nlosing the upper half of a 64-bit timestamp range on larger boxes.\nHopefully those platforms have died out (or at least we don't mind\nbreaking them)?\n\nIt appears that we use uint64_t in many places in our code.  So\nwhile philosophically time_t is the right type, uint64_t might be\npractically a safer alternative type to use at the endgame patch in\nthis series.  I haven't seen it yet, but presumably the last one 6/6\nis the endgame?\n\n\n"},{"id":"312829","messageId":"alpine.DEB.2.20.1702281149120.3767@virtualbox","threadId":"45241","inReplyTo":"xmqqh93fmemg.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/6] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-28T10:49:29Z","receivedAt":"2017-02-28T11:07:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 27 Feb 2017, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> >> -\tunsigned long number = strtoul(date, &end, 10);\n> >> +\ttime_t number = parse_timestamp(date, &end, 10);\n> >\n> > This hunk does not belong to this step.  Everybody else in this step\n> \n> obviously I meant \"the left half of this hunk\" ;-)\n\nObviously ;-)\n\nCiao,\nJohannes\n"},{"id":"312830","messageId":"alpine.DEB.2.20.1702281211270.3767@virtualbox","threadId":"45241","inReplyTo":"xmqqlgsrmesc.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-28T11:32:01Z","receivedAt":"2017-02-28T11:36:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 27 Feb 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > One notable fallout of this patch series is that on 64-bit Linux (and\n> > other platforms where `unsigned long` is 64-bit), we now limit the\n> > range of dates to LONG_MAX (i.e. the *signed* maximum value). This\n> > needs to be done as `time_t` can be signed (and indeed is at least on\n> > my Ubuntu setup).\n> >\n> > Obviously, I think that we can live with that, and I hope that all\n> > interested parties agree.\n> \n> s/ulong/time_t/ is definintely a good change, and it will take us to a\n> place we would want to be in in some future.  \n\nActually. I have to take back the part where I hoped that all interested\nparties would agree. The problem is 32-bit Linux:\n\n\t$ cat >a1.c <<-\\EOF\n\t#include <stdio.h>\n\t#include <limits.h>\n\t#include <time.h>\n\n\tint main(int argc, char **argv)\n\t{\n\t\tprintf(\"sizeof(long): %d, sizeof(time_t): %d, ulong_max: %lu\\n\",\n\t\t       (int)sizeof(long), (int)sizeof(time_t), ULONG_MAX);\n\t\treturn 0;\n\t}\n\tEOF\n\n\t$ gcc -m32 -Wall -o a1 a1.c\n\n\t$ ./a1\n\tsizeof(long): 4, sizeof(time_t): 4, ulong_max: 4294967295\n\nSo. Not only is `long` a 32-bit on 32-bit Linux, but so is `time_t`. And\nwith that, switching from `ULONG_MAX` as the maximal time we can represent\nin Git to `LONG_MAX` is kind of a serious problem.\n\n> As long as there remains no platform we care about whose time_t and long\n> are still 32-bit signed integer, there will be a fallout to them with\n> this change.\n\nSorry, I do not understand the verb \"remains\" in conjunction with \"no\nplatform\"...\n\nDo you mean to say that currently no platform we care about has 32-bit\nsigned time_t/long?\n\nIf so, I just demonstrated this to be unfortunately incorrect.\n\n> It appears that we use uint64_t in many places in our code.  So\n> while philosophically time_t is the right type, uint64_t might be\n> practically a safer alternative type to use at the endgame patch in\n> this series.\n\nYes, I think you are right. We should use uint64_t instead of time_t, but\n*semantically* we should not even use uint64_t. We should introduce our\nown data type instead of repeating the mistake to use a data type that\ndoes not convey its role to the reader.\n\nCurrently, I am favoring timestamp_t.\n\n> I haven't seen it yet, but presumably the last one 6/6 is the endgame?\n\nMaybe it took a while to get sent out, but it made it into public inbox:\nhttp://public-inbox.org/git/75efe76cbb0636741a7c3aec9e21459bc1dc3cbe.1488231002.git.johannes.schindelin@gmx.de/\n\nCiao,\nJohannes\n"},{"id":"312845","messageId":"20170228142802.hu5esthnqdsgc2po@sigill.intra.peff.net","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-28T14:28:02Z","receivedAt":"2017-02-28T14:35:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 27, 2017 at 10:30:20PM +0100, Johannes Schindelin wrote:\n\n> One notable fallout of this patch series is that on 64-bit Linux (and\n> other platforms where `unsigned long` is 64-bit), we now limit the range\n> of dates to LONG_MAX (i.e. the *signed* maximum value). This needs to be\n> done as `time_t` can be signed (and indeed is at least on my Ubuntu\n> setup).\n> \n> Obviously, I think that we can live with that, and I hope that all\n> interested parties agree.\n\nI do not just agree, but I think the move to a signed timestamp is a big\nimprovement. Git's object format is happy to represent times before\n1970, but the code is not. I know this has been a pain for people who\nimport ancient histories into Git.\n\nIt looks from the discussion like the sanest path forward is our own\nsigned-64bit timestamp_t. That's unfortunate compared to using the\nstandard time_t, but hopefully it would reduce the number of knobs (like\nTIME_T_IS_INT64) in the long run.\n\n-Peff\n"},{"id":"312848","messageId":"alpine.DEB.2.20.1702281600330.3767@virtualbox","threadId":"45241","inReplyTo":"20170228142802.hu5esthnqdsgc2po@sigill.intra.peff.net","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-28T15:01:35Z","receivedAt":"2017-02-28T15:10:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Peff,\n\nOn Tue, 28 Feb 2017, Jeff King wrote:\n\n> On Mon, Feb 27, 2017 at 10:30:20PM +0100, Johannes Schindelin wrote:\n> \n> > One notable fallout of this patch series is that on 64-bit Linux (and\n> > other platforms where `unsigned long` is 64-bit), we now limit the\n> > range of dates to LONG_MAX (i.e. the *signed* maximum value). This\n> > needs to be done as `time_t` can be signed (and indeed is at least on\n> > my Ubuntu setup).\n> > \n> > Obviously, I think that we can live with that, and I hope that all\n> > interested parties agree.\n> \n> I do not just agree, but I think the move to a signed timestamp is a big\n> improvement. Git's object format is happy to represent times before\n> 1970, but the code is not. I know this has been a pain for people who\n> import ancient histories into Git.\n> \n> It looks from the discussion like the sanest path forward is our own\n> signed-64bit timestamp_t. That's unfortunate compared to using the\n> standard time_t, but hopefully it would reduce the number of knobs (like\n> TIME_T_IS_INT64) in the long run.\n\nBoy am I happy that I did not go ahead and changed the code to use\nuint64_t yet...\n\nI'll let the dust settle a bit and then make further changes and send out\nv2.\n\nCiao,\nDscho\n"},{"id":"312852","messageId":"f6b57868-0173-48d9-86cb-79780f7e301b@web.de","threadId":"45241","inReplyTo":"20170228142802.hu5esthnqdsgc2po@sigill.intra.peff.net","subject":"Re: [PATCH 0/6] Use time_t","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-02-28T16:38:37Z","receivedAt":"2017-02-28T16:45:35Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 28.02.2017 um 15:28 schrieb Jeff King:\n> On Mon, Feb 27, 2017 at 10:30:20PM +0100, Johannes Schindelin wrote:\n>\n>> One notable fallout of this patch series is that on 64-bit Linux (and\n>> other platforms where `unsigned long` is 64-bit), we now limit the range\n>> of dates to LONG_MAX (i.e. the *signed* maximum value). This needs to be\n>> done as `time_t` can be signed (and indeed is at least on my Ubuntu\n>> setup).\n>>\n>> Obviously, I think that we can live with that, and I hope that all\n>> interested parties agree.\n>\n> I do not just agree, but I think the move to a signed timestamp is a big\n> improvement. Git's object format is happy to represent times before\n> 1970, but the code is not. I know this has been a pain for people who\n> import ancient histories into Git.\n>\n> It looks from the discussion like the sanest path forward is our own\n> signed-64bit timestamp_t. That's unfortunate compared to using the\n> standard time_t, but hopefully it would reduce the number of knobs (like\n> TIME_T_IS_INT64) in the long run.\n\nGlibc will get a way to enable 64-bit time_t on 32-bit platforms \neventually (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign). \nCan platforms that won't provide a 64-bit time_t by 2038 be actually \nused at that point?  How would we get time information on them?  How \nwould a custom timestamp_t help us?\n\nRegarding the need for knobs: We could let the compiler chose between \nstrtoll() and strtol() based on the size of time_t, in an inline \nfunction.  The maximum value can be calculated using its size as well. \nAnd we could use PRIdMAX and cast to intmax_t for printing.\n\nRené\n"},{"id":"312855","messageId":"xmqqvarukz0g.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"20170228142802.hu5esthnqdsgc2po@sigill.intra.peff.net","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-28T17:26:23Z","receivedAt":"2017-02-28T17:35:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I do not just agree, but I think the move to a signed timestamp is a big\n> improvement. Git's object format is happy to represent times before\n> 1970, but the code is not. I know this has been a pain for people who\n> import ancient histories into Git.\n>\n> It looks from the discussion like the sanest path forward is our own\n> signed-64bit timestamp_t. That's unfortunate compared to using the\n> standard time_t, but hopefully it would reduce the number of knobs (like\n> TIME_T_IS_INT64) in the long run.\n\nKeeping it unsigned is safer in the short-term.  There are some\nplaces that uses 0 as \"impossible time\" (e.g. somebody tried to\nparse a string as time and returns a failure) and these places need\nto be found and be replaced with probably the most negative value\nthat timestamp_t cn represent.  Another possible special value we\nmay use is for \"expiring everything\" but I think we tend to just use\nthe timestamp of the present time for that purpose and not UONG_MAX,\nso we should be OK there.\n\nBut we need to cross the bridge to signed timestamp sometime, and I\ndo not see any reason why that somtime should not be now.\n\n\n"},{"id":"312876","messageId":"xmqqa896kuve.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"f6b57868-0173-48d9-86cb-79780f7e301b@web.de","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-28T18:55:49Z","receivedAt":"2017-02-28T20:00:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <l.s.r@web.de> writes:\n\n> Am 28.02.2017 um 15:28 schrieb Jeff King:\n>\n>> It looks from the discussion like the sanest path forward is our own\n>> signed-64bit timestamp_t. That's unfortunate compared to using the\n>> standard time_t, but hopefully it would reduce the number of knobs (like\n>> TIME_T_IS_INT64) in the long run.\n>\n> Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n> eventually\n> (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign). Can\n> platforms that won't provide a 64-bit time_t by 2038 be actually used\n> at that point?  How would we get time information on them?  How would\n> a custom timestamp_t help us?\n\nThat's a sensible \"wait, let's step back a bit\".  I take it that you\nare saying \"time_t is just fine\", and I am inclined to agree.\n\nRight now, they may be able to have future timestamps ranging to\nyear 2100 and switching to time_t would limit their ability to\nexpress future time to 2038 but they would be able to express\ntimestamp in the past to cover most of 20th century.  Given that\nthese 32-bit time_t software platforms will die off before year 2038\n(either by underlying hardware getting obsolete, or software updated\nto handle 64-bit time_t), the (temporary) loss of 2038-2100 range\nwould not be too big a deal to warrant additional complexity.\n\n> Regarding the need for knobs: We could let the compiler chose between\n> strtoll() and strtol() based on the size of time_t, in an inline\n> function.  The maximum value can be calculated using its size as\n> well. And we could use PRIdMAX and cast to intmax_t for printing.\n\nThanks.\n"},{"id":"312878","messageId":"20170228200145.ymbqmxwrbbrwagks@sigill.intra.peff.net","threadId":"45241","inReplyTo":"xmqqvarukz0g.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-28T20:01:45Z","receivedAt":"2017-02-28T20:09:45Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 28, 2017 at 09:26:23AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > I do not just agree, but I think the move to a signed timestamp is a big\n> > improvement. Git's object format is happy to represent times before\n> > 1970, but the code is not. I know this has been a pain for people who\n> > import ancient histories into Git.\n> >\n> > It looks from the discussion like the sanest path forward is our own\n> > signed-64bit timestamp_t. That's unfortunate compared to using the\n> > standard time_t, but hopefully it would reduce the number of knobs (like\n> > TIME_T_IS_INT64) in the long run.\n> \n> Keeping it unsigned is safer in the short-term.  There are some\n> places that uses 0 as \"impossible time\" (e.g. somebody tried to\n> parse a string as time and returns a failure) and these places need\n> to be found and be replaced with probably the most negative value\n> that timestamp_t cn represent.  Another possible special value we\n> may use is for \"expiring everything\" but I think we tend to just use\n> the timestamp of the present time for that purpose and not UONG_MAX,\n> so we should be OK there.\n\nYeah. I think I was the one who invented the \"0 is impossible\"\nconvention. We can certainly stick with it for now (it's awkward if you\nreally do have an entry on Jan 1 1970, but other than that it's an OK\nmarker). I agree that the most negatively value is probably a saner\nchoice, but we can switch to it after the dust settles.\n\n> But we need to cross the bridge to signed timestamp sometime, and I\n> do not see any reason why that somtime should not be now.\n\nYep.\n\n-Peff\n"},{"id":"312879","messageId":"20170228200423.33dghyephxsmxrx6@sigill.intra.peff.net","threadId":"45241","inReplyTo":"xmqqa896kuve.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-28T20:04:23Z","receivedAt":"2017-02-28T20:12:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 28, 2017 at 10:55:49AM -0800, Junio C Hamano wrote:\n\n> > Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n> > eventually\n> > (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign). Can\n> > platforms that won't provide a 64-bit time_t by 2038 be actually used\n> > at that point?  How would we get time information on them?  How would\n> > a custom timestamp_t help us?\n> \n> That's a sensible \"wait, let's step back a bit\".  I take it that you\n> are saying \"time_t is just fine\", and I am inclined to agree.\n> \n> Right now, they may be able to have future timestamps ranging to\n> year 2100 and switching to time_t would limit their ability to\n> express future time to 2038 but they would be able to express\n> timestamp in the past to cover most of 20th century.  Given that\n> these 32-bit time_t software platforms will die off before year 2038\n> (either by underlying hardware getting obsolete, or software updated\n> to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n> would not be too big a deal to warrant additional complexity.\n\nFor what it's worth, I'm on board with just using time_t if it reduces\nthe overall complexity. I agree that the \"loss\" of far-future timestamp\nhandling is unlikely to matter between now and 2038, and those systems\nwill have to figure out their time_t problems by then. By actually using\ntime_t we get to piggy-back on their solution.\n\n-Peff\n"},{"id":"312900","messageId":"alpine.DEB.2.20.1702282149160.3767@virtualbox","threadId":"45241","inReplyTo":"xmqqa896kuve.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-28T20:54:58Z","receivedAt":"2017-02-28T21:28:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 28 Feb 2017, Junio C Hamano wrote:\n\n> René Scharfe <l.s.r@web.de> writes:\n> \n> > Am 28.02.2017 um 15:28 schrieb Jeff King:\n> >\n> >> It looks from the discussion like the sanest path forward is our own\n> >> signed-64bit timestamp_t. That's unfortunate compared to using the\n> >> standard time_t, but hopefully it would reduce the number of knobs\n> >> (like TIME_T_IS_INT64) in the long run.\n> >\n> > Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n> > eventually (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign).\n> > Can platforms that won't provide a 64-bit time_t by 2038 be actually\n> > used at that point?  How would we get time information on them?  How\n> > would a custom timestamp_t help us?\n> \n> That's a sensible \"wait, let's step back a bit\".  I take it that you are\n> saying \"time_t is just fine\", and I am inclined to agree.\n> \n> Right now, they may be able to have future timestamps ranging to\n> year 2100 and switching to time_t would limit their ability to\n> express future time to 2038 but they would be able to express\n> timestamp in the past to cover most of 20th century.  Given that\n> these 32-bit time_t software platforms will die off before year 2038\n> (either by underlying hardware getting obsolete, or software updated\n> to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n> would not be too big a deal to warrant additional complexity.\n\nYou seem to assume that time_t is required to be signed. But from my\nunderstanding that is only guaranteed by POSIX, not by ISO C.\n\nWe may very well buy ourselves a ton of trouble if we decide to switch to\n`time_t` rather than to `int64_t`.\n\nCiao,\nJohannes"},{"id":"312902","messageId":"20170228213122.kk6mrbbqer6o7rd6@sigill.intra.peff.net","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1702282149160.3767@virtualbox","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-28T21:31:22Z","receivedAt":"2017-02-28T21:31:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 28, 2017 at 09:54:58PM +0100, Johannes Schindelin wrote:\n\n> > Right now, they may be able to have future timestamps ranging to\n> > year 2100 and switching to time_t would limit their ability to\n> > express future time to 2038 but they would be able to express\n> > timestamp in the past to cover most of 20th century.  Given that\n> > these 32-bit time_t software platforms will die off before year 2038\n> > (either by underlying hardware getting obsolete, or software updated\n> > to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n> > would not be too big a deal to warrant additional complexity.\n> \n> You seem to assume that time_t is required to be signed. But from my\n> understanding that is only guaranteed by POSIX, not by ISO C.\n\nI wonder how common that is in practice, and whether it is worth\ntreating it as a quality-of-implementation issue. IOW, to say \"your\nplatform time_t doesn't handle negative times, so you get Jan 1 1970 for\nany dates before then. Complain to your platform vendor\".\n\nI'm not sure how much complexity it would add to the code.  Either way,\nwhen we parse an ascii-decimal timestamp from an object, we need to do\nbounds checking. Whether that bound is at \"0\" or \"LONG_MIN\", I don't\nthink that it changes much.\n\nMeanwhile, if we were to have a negative timestamp_t but the system\ntime_t is unsigned, we have to do a bounds-check any time we use a\nsystem function like gmtime(), or risk funny wrap-around bugs.\n\n-Peff\n"},{"id":"312918","messageId":"20170228223325.vabdrwas2qn52gup@sigill.intra.peff.net","threadId":"45241","inReplyTo":"xmqqh93ehrxx.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-02-28T22:33:25Z","receivedAt":"2017-02-28T22:33:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 28, 2017 at 02:27:22PM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > ... We can certainly stick with it for now (it's awkward if you\n> > really do have an entry on Jan 1 1970, but other than that it's an OK\n> > marker). I agree that the most negatively value is probably a saner\n> > choice, but we can switch to it after the dust settles.\n> \n> I was trying to suggest that we should strive to switch to the most\n> negative or whatever the most implausible value in the new range\n> (and leave it as a possible bug to be fixed if we missed a place\n> that still used \"0 is impossible\") while doing the ulong to time_t\n> (or timestamp_t that is i64).  \n> \n> \"safer in the short term\" wasn't meant to be \"let's not spend time\n> to do quality work\".  As long as we are switching, we should follow\n> it through.\n\nSure, I'd be much happier to see it done now. I just didn't want to pile\non the requirements to the point that step 1 doesn't get done. But I\nhaven't even looked at the code changes needed for time_t. I suspect\nDscho has a better feel for it at this point.\n\n-Peff\n"},{"id":"312926","messageId":"alpine.DEB.2.20.1703010000260.3767@virtualbox","threadId":"45241","inReplyTo":"6bd6ef64-2749-f17a-aea8-d25b147892c5@web.de","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-28T23:10:44Z","receivedAt":"2017-02-28T23:18:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi René,\n\nOn Tue, 28 Feb 2017, René Scharfe wrote:\n\n> Am 28.02.2017 um 21:54 schrieb Johannes Schindelin:\n> >\n> > On Tue, 28 Feb 2017, Junio C Hamano wrote:\n> >\n> > > René Scharfe <l.s.r@web.de> writes:\n> > >\n> > > > Am 28.02.2017 um 15:28 schrieb Jeff King:\n> > > >\n> > > > > It looks from the discussion like the sanest path forward is our\n> > > > > own signed-64bit timestamp_t. That's unfortunate compared to\n> > > > > using the standard time_t, but hopefully it would reduce the\n> > > > > number of knobs (like TIME_T_IS_INT64) in the long run.\n> > > >\n> > > > Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n> > > > eventually\n> > > > (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign).  Can\n> > > > platforms that won't provide a 64-bit time_t by 2038 be actually\n> > > > used at that point?  How would we get time information on them?\n> > > > How would a custom timestamp_t help us?\n> > >\n> > > That's a sensible \"wait, let's step back a bit\".  I take it that you\n> > > are saying \"time_t is just fine\", and I am inclined to agree.\n> > >\n> > > Right now, they may be able to have future timestamps ranging to\n> > > year 2100 and switching to time_t would limit their ability to\n> > > express future time to 2038 but they would be able to express\n> > > timestamp in the past to cover most of 20th century.  Given that\n> > > these 32-bit time_t software platforms will die off before year 2038\n> > > (either by underlying hardware getting obsolete, or software updated\n> > > to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n> > > would not be too big a deal to warrant additional complexity.\n> >\n> > You seem to assume that time_t is required to be signed. But from my\n> > understanding that is only guaranteed by POSIX, not by ISO C.\n> >\n> > We may very well buy ourselves a ton of trouble if we decide to switch\n> > to `time_t` rather than to `int64_t`.\n> \n> True, and time_t doesn't even have to be an integer type.  But which\n> platforms capable of running git use something else than int32_t or\n> int64_t?\n\nThat kind of thinking is dangerous. We don't know what platforms are\nrunning Git, and we have a very clear example how we got it very wrong\nrecently, when we broke building with musl by requiring REG_STARTEND\nsupport [*1*].\n\nSo why gamble? If we switch to uint64_t, it would definitely provide the\nsmoothest upgrade path. It is what the code assumed implicitly when we\nbroke 32-bit in v2.9.1.\n\nIf anybody really wants to support negative timestamps, it should be done\non top of my work. My current patch series does not even start to try to\naddress the ramifications of negative timestamps (see e.g. the use of\nstrtoull() for parsing). It is quite unreasonable to ask for such a\nfundamental design change when it could very easily be done incrementally\ninstead, when needed, by someone who needs it.\n\nMy work would pave the way for that effort, of course. But this is really\nas far as I can go with this patch series, given that I have bigger fish\nto fry than to support negative timestamps.\n\nCiao,\nDscho\n\nFootnote *1*: I still deeply regret deviating from my v1 that did *not*\nrequire REG_STARTEND, but would have kept things working for platforms\nwithout REG_STARTEND by simulating it.\n\nBut our thinking was: who would want to run Git in an environment so\nridiculously old that it does not have that clearly useful REG_STARTEND\nsupport? Our answer was \"nobody\". And it was incorrect."},{"id":"312928","messageId":"xmqqh93ehrxx.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"20170228200145.ymbqmxwrbbrwagks@sigill.intra.peff.net","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-02-28T22:27:22Z","receivedAt":"2017-02-28T23:30:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> ... We can certainly stick with it for now (it's awkward if you\n> really do have an entry on Jan 1 1970, but other than that it's an OK\n> marker). I agree that the most negatively value is probably a saner\n> choice, but we can switch to it after the dust settles.\n\nI was trying to suggest that we should strive to switch to the most\nnegative or whatever the most implausible value in the new range\n(and leave it as a possible bug to be fixed if we missed a place\nthat still used \"0 is impossible\") while doing the ulong to time_t\n(or timestamp_t that is i64).  \n\n\"safer in the short term\" wasn't meant to be \"let's not spend time\nto do quality work\".  As long as we are switching, we should follow\nit through.\n\n>> But we need to cross the bridge to signed timestamp sometime, and I\n>> do not see any reason why that somtime should not be now.\n>\n> Yep.\n>\n> -Peff\n"},{"id":"312933","messageId":"876bb673-ae8c-64bb-6a4d-385c84fb22d3@web.de","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1703010000260.3767@virtualbox","subject":"Re: [PATCH 0/6] Use time_t","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-03-01T00:59:34Z","receivedAt":"2017-03-01T01:36:31Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 01.03.2017 um 00:10 schrieb Johannes Schindelin:\n> Hi René,\n>\n> On Tue, 28 Feb 2017, René Scharfe wrote:\n>\n>> Am 28.02.2017 um 21:54 schrieb Johannes Schindelin:\n>>>\n>>> On Tue, 28 Feb 2017, Junio C Hamano wrote:\n>>>\n>>>> René Scharfe <l.s.r@web.de> writes:\n>>>>\n>>>>> Am 28.02.2017 um 15:28 schrieb Jeff King:\n>>>>>\n>>>>>> It looks from the discussion like the sanest path forward is our\n>>>>>> own signed-64bit timestamp_t. That's unfortunate compared to\n>>>>>> using the standard time_t, but hopefully it would reduce the\n>>>>>> number of knobs (like TIME_T_IS_INT64) in the long run.\n>>>>>\n>>>>> Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n>>>>> eventually\n>>>>> (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign).  Can\n>>>>> platforms that won't provide a 64-bit time_t by 2038 be actually\n>>>>> used at that point?  How would we get time information on them?\n>>>>> How would a custom timestamp_t help us?\n>>>>\n>>>> That's a sensible \"wait, let's step back a bit\".  I take it that you\n>>>> are saying \"time_t is just fine\", and I am inclined to agree.\n>>>>\n>>>> Right now, they may be able to have future timestamps ranging to\n>>>> year 2100 and switching to time_t would limit their ability to\n>>>> express future time to 2038 but they would be able to express\n>>>> timestamp in the past to cover most of 20th century.  Given that\n>>>> these 32-bit time_t software platforms will die off before year 2038\n>>>> (either by underlying hardware getting obsolete, or software updated\n>>>> to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n>>>> would not be too big a deal to warrant additional complexity.\n>>>\n>>> You seem to assume that time_t is required to be signed. But from my\n>>> understanding that is only guaranteed by POSIX, not by ISO C.\n>>>\n>>> We may very well buy ourselves a ton of trouble if we decide to switch\n>>> to `time_t` rather than to `int64_t`.\n>>\n>> True, and time_t doesn't even have to be an integer type.  But which\n>> platforms capable of running git use something else than int32_t or\n>> int64_t?\n>\n> That kind of thinking is dangerous. We don't know what platforms are\n> running Git, and we have a very clear example how we got it very wrong\n> recently, when we broke building with musl by requiring REG_STARTEND\n> support [*1*].\n\nIn general that's true, and if nobody can add to the list (glibc: \nint32_t on 32-bit platforms, int64_t on 64-bit platforms for now; \nNetBSD, OpenBSD, Windows int64_t) then we shouldn't make assumptions \nabout time_t that go beyond the C standard -- at least not without \nverifying them, e.g. with asserts or tests.  I'd especially be \ninterested in hearing about platforms that use a floating point type.\n\nSystems lacking REG_STARTEND can use compat/regex/ -- that's doesn't \nsound too bad.  (I didn't follow the original discussion too closely, \nand don't mean to open it up again.)\n\n> So why gamble? If we switch to uint64_t, it would definitely provide the\n> smoothest upgrade path. It is what the code assumed implicitly when we\n> broke 32-bit in v2.9.1.\n\nWe can assume that time_t exists everywhere and is used by functions \nlike gettimeofday(2) and localtime(3).  Why invent our own layer on top? \n  What would it be able to do that time_t alone can't?  I understand a \nneed to handle times before 1970 for historical documents, but what good \nwould it do to have the ability to handle dates beyond 2038, today?\n\nPlatforms that don't use the next two decades to provide a time_t that \ncan store the current time by then will have bigger problems than a \ncrippled git.\n\n> If anybody really wants to support negative timestamps, it should be done\n> on top of my work. My current patch series does not even start to try to\n> address the ramifications of negative timestamps (see e.g. the use of\n> strtoull() for parsing). It is quite unreasonable to ask for such a\n> fundamental design change when it could very easily be done incrementally\n> instead, when needed, by someone who needs it.\n\nI'm confused.  Your patch series converts to time_t.  Why not use it? \nThat would prepare ourselves for the bright future when we'll have a \n64-bit time_t in every libc. :)\n\nRené\n\n\n"},{"id":"312934","messageId":"6bd6ef64-2749-f17a-aea8-d25b147892c5@web.de","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1702282149160.3767@virtualbox","subject":"Re: [PATCH 0/6] Use time_t","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-02-28T21:31:49Z","receivedAt":"2017-03-01T06:08:17Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 28.02.2017 um 21:54 schrieb Johannes Schindelin:\n> Hi Junio,\n>\n> On Tue, 28 Feb 2017, Junio C Hamano wrote:\n>\n>> René Scharfe <l.s.r@web.de> writes:\n>>\n>>> Am 28.02.2017 um 15:28 schrieb Jeff King:\n>>>\n>>>> It looks from the discussion like the sanest path forward is our own\n>>>> signed-64bit timestamp_t. That's unfortunate compared to using the\n>>>> standard time_t, but hopefully it would reduce the number of knobs\n>>>> (like TIME_T_IS_INT64) in the long run.\n>>>\n>>> Glibc will get a way to enable 64-bit time_t on 32-bit platforms\n>>> eventually (https://sourceware.org/glibc/wiki/Y2038ProofnessDesign).\n>>> Can platforms that won't provide a 64-bit time_t by 2038 be actually\n>>> used at that point?  How would we get time information on them?  How\n>>> would a custom timestamp_t help us?\n>>\n>> That's a sensible \"wait, let's step back a bit\".  I take it that you are\n>> saying \"time_t is just fine\", and I am inclined to agree.\n>>\n>> Right now, they may be able to have future timestamps ranging to\n>> year 2100 and switching to time_t would limit their ability to\n>> express future time to 2038 but they would be able to express\n>> timestamp in the past to cover most of 20th century.  Given that\n>> these 32-bit time_t software platforms will die off before year 2038\n>> (either by underlying hardware getting obsolete, or software updated\n>> to handle 64-bit time_t), the (temporary) loss of 2038-2100 range\n>> would not be too big a deal to warrant additional complexity.\n>\n> You seem to assume that time_t is required to be signed. But from my\n> understanding that is only guaranteed by POSIX, not by ISO C.\n>\n> We may very well buy ourselves a ton of trouble if we decide to switch to\n> `time_t` rather than to `int64_t`.\n\nTrue, and time_t doesn't even have to be an integer type.  But which \nplatforms capable of running git use something else than int32_t or int64_t?\n\nRené\n"},{"id":"312952","messageId":"xmqq1sugj4gn.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"20170228223325.vabdrwas2qn52gup@sigill.intra.peff.net","subject":"Re: [PATCH 0/6] Use time_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-01T17:23:52Z","receivedAt":"2017-03-01T17:24:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Tue, Feb 28, 2017 at 02:27:22PM -0800, Junio C Hamano wrote:\n>\n>> Jeff King <peff@peff.net> writes:\n>> \n>> > ... We can certainly stick with it for now (it's awkward if you\n>> > really do have an entry on Jan 1 1970, but other than that it's an OK\n>> > marker). I agree that the most negatively value is probably a saner\n>> > choice, but we can switch to it after the dust settles.\n>> \n>> I was trying to suggest that we should strive to switch to the most\n>> negative or whatever the most implausible value in the new range\n>> (and leave it as a possible bug to be fixed if we missed a place\n>> that still used \"0 is impossible\") while doing the ulong to time_t\n>> (or timestamp_t that is i64).  \n>> \n>> \"safer in the short term\" wasn't meant to be \"let's not spend time\n>> to do quality work\".  As long as we are switching, we should follow\n>> it through.\n>\n> Sure, I'd be much happier to see it done now. I just didn't want to pile\n> on the requirements to the point that step 1 doesn't get done.\n\nAh, that was what you meant.\n\nI was assuming that we are switching to a longer _signed_ type.  It\nfelt silly to tell users \"you can use timestamps before the epoch\nnow with this change, but you cannot express time exactly at the\nepoch\".\n\nI am perfectly OK with switching to a longer _unsigned_ type with\nthe \"0 is impossible\" [*1*] intact, aka \"safer in the short term\",\nif we want to it make our first step.  That may be a smaller step,\nbut still a step in the right direction.\n\n\n[Footnote]\n\n*1* It could be \"-1 is impossible\", I didn't actually check.\n    Funnily enough, ISO C99 uses (time_t)(-1) to signal an error\n    when returning value from mktime() and time().\n\n"},{"id":"312959","messageId":"xmqqbmtkhna9.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"f4ff525dda1964dd0e7cef1d0507e1f2403469e1.1488231002.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH 3/6] Introduce a new \"printf format\" for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-01T18:20:14Z","receivedAt":"2017-03-01T18:23:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> So let's introduce the pseudo format \"PRItime\" (currently simply being\n> \"lu\") so that it is easy later on to change the data type to time_t.\n\nThe problem being solved is a good thing to solve, and \n\n> -\tprintf(\"author-time %lu\\n\", ci.author_time);\n> +\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n\nis one of the two ingredients to the solution for this line.  But\nthe final form would require casting ci.author_time to the type\nexpected by %PRItime format specifier.  With this change alone, you\ncould define PRItime to expect an winder type in the next step but\nthat would be a bad conversion.  IOW, changing only the format\nwithout introducing an explicit cast appears to invite future\nmistakes.\n\nIt would be better to introduce the timestamp_t we discussed earlier\nbefore (or at) this step, and typedef it to ulong first, and then in\nthis step, change the above to\n\n\tprintf(\"author-time %\"PRItime\"\\n\", (timestamp_t)ci.author_time);\n\nto keep them in sync.  And at a later step in the series, you can\nupdate definition of PRItime and timestamp_t to make them wider at\nthe same time, and the changes in this patch like the above line\nwould not need to be touched again.\n\n\n"},{"id":"312972","messageId":"xmqqy3wog4e0.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"xmqqbmtkhna9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 3/6] Introduce a new \"printf format\" for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-01T19:53:43Z","receivedAt":"2017-03-01T20:11:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>\n>> So let's introduce the pseudo format \"PRItime\" (currently simply being\n>> \"lu\") so that it is easy later on to change the data type to time_t.\n>\n> The problem being solved is a good thing to solve, and \n>\n>> -\tprintf(\"author-time %lu\\n\", ci.author_time);\n>> +\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n> ...\n> It would be better to introduce the timestamp_t we discussed earlier\n> before (or at) this step, and typedef it to ulong first, and then in\n> this step, change the above to\n>\n> \tprintf(\"author-time %\"PRItime\"\\n\", (timestamp_t)ci.author_time);\n>\n> to keep them in sync.\n\nNah, ignore me.  This was just me being silly.\n\nI was somehow expecting (incorrecty) that we would pick one single\nPRItime for everybody and end up doing an equivalent of\n\n\tprintf(\"%llu\", (unsigned long long)(something_that_is_time_t))\n\nBut as long as the plan is to configure PRItime for the platform's\ntime_t (or whatever the final type for timestamp_t is), we do not\nhave to have any extra cast here.  The endgame will use the type\nthat is consistent with %PRItime for variables and structure fields,\nand we do not want an extra cast.\n"},{"id":"316061","messageId":"cover.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1488231002.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:03Z","receivedAt":"2017-04-02T19:06:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as we already make use of\n64-bit data types internally. There is no good reason why we should not\nuse the same for timestamps. Hence, let's use uintmax_t for timestamps.\n\nNote: while the `time_t` data type exists and is meant to be used for\ntimestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\nused `time_t` for that reason, but it came with a few serious downsides:\nas `time_t` can be signed (and indeed, on Windows it is an int64_t),\nGit's expectation that 0 is the minimal value does no longer hold true,\nintroducing its own set of interesting challenges. Besides, if we *can*\nhandle far in the future timestamps (except for formatting them using\nthe system libraries), it is more consistent to do so.\n\nThe upside of using `uintmax_t` for timestamps is that we do a much\nbetter job to support far in the future timestamps across all platforms,\nincluding 32-bit ones. The downside is that those platforms that use a\n32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nChanges since v1 (sorry, the interdiff is huge due to the switch from\ntime_t to uintmax_t):\n\n- moved an `unsigned long` -> `time_t` change into 6/6 (it inadvertently\n  was done as part of the patch that wanted to introduce\n  parse_timestamp()).\n\n- using `uintmax_t` for timestamps instead of `time_t` now.\n\n- as 32-bit Linux still uses 32-bit time_t, while we may be able to\n  represent timestamps far in the future internally, as soon as we try\n  to format them using strftime() it will fail. Added safeguards against\n  that and prepared t0006 and t5000 for this scenario (i.e. skip those\n  tests that require strftime() to handle 64-bit timestamps).\n\n- found a couple more places where strtoul() was still hardcoded for\n  parsing timestamps, and fixed them.\n\n\nJohannes Schindelin (8):\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  t0006 & t5000: prepare for 64-bit timestamps\n  t0006 & t5000: skip \"far in the future\" test when time_t is too\n    limited\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Introduce a new data type for timestamps\n  Abort if the system time cannot handle one of our timestamps\n  Use uintmax_t for timestamps\n\n Documentation/technical/api-parse-options.txt |   8 +-\n archive-tar.c                                 |   5 +-\n archive-zip.c                                 |   6 +-\n archive.h                                     |   2 +-\n builtin/am.c                                  |   4 +-\n builtin/blame.c                               |  14 ++--\n builtin/fsck.c                                |   6 +-\n builtin/gc.c                                  |   2 +-\n builtin/log.c                                 |   4 +-\n builtin/merge-base.c                          |   2 +-\n builtin/name-rev.c                            |   6 +-\n builtin/pack-objects.c                        |   4 +-\n builtin/prune.c                               |   4 +-\n builtin/receive-pack.c                        |  14 ++--\n builtin/reflog.c                              |  24 +++---\n builtin/rev-list.c                            |   2 +-\n builtin/rev-parse.c                           |   3 +-\n builtin/show-branch.c                         |   4 +-\n builtin/worktree.c                            |   4 +-\n bundle.c                                      |   4 +-\n cache.h                                       |  14 ++--\n commit.c                                      |  18 ++--\n commit.h                                      |   2 +-\n config.c                                      |   2 +-\n credential-cache--daemon.c                    |  12 +--\n date.c                                        | 113 ++++++++++++++------------\n fetch-pack.c                                  |   8 +-\n fsck.c                                        |   2 +-\n git-compat-util.h                             |   9 ++\n http-backend.c                                |   4 +-\n parse-options-cb.c                            |   4 +-\n pretty.c                                      |   4 +-\n reachable.c                                   |   9 +-\n reachable.h                                   |   4 +-\n ref-filter.c                                  |  22 ++---\n reflog-walk.c                                 |   8 +-\n refs.c                                        |  14 ++--\n refs.h                                        |   8 +-\n refs/files-backend.c                          |   8 +-\n revision.c                                    |   6 +-\n revision.h                                    |   4 +-\n sha1_name.c                                   |   6 +-\n t/helper/test-date.c                          |  18 ++--\n t/helper/test-parse-options.c                 |   4 +-\n t/t0006-date.sh                               |   4 +-\n t/t5000-tar-tree.sh                           |   6 +-\n t/test-lib.sh                                 |   3 +\n tag.c                                         |   6 +-\n tag.h                                         |   2 +-\n upload-pack.c                                 |   8 +-\n vcs-svn/fast_export.c                         |   8 +-\n vcs-svn/fast_export.h                         |   4 +-\n vcs-svn/svndump.c                             |   2 +-\n wt-status.c                                   |   2 +-\n 54 files changed, 252 insertions(+), 218 deletions(-)\n\n\nbase-commit: b14f27f91770e0f99f64135348977a0ce1c7993a\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v2\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v2\n\nInterdiff vs v1:\n\n diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\n index ed16519da8f..829b5581105 100644\n --- a/Documentation/technical/api-parse-options.txt\n +++ b/Documentation/technical/api-parse-options.txt\n @@ -183,13 +183,13 @@ There are some macros to easily define options:\n  \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n  \tThe scaled value is put into `unsigned_long_var`.\n  \n -`OPT_DATE(short, long, &time_t_var, description)`::\n +`OPT_DATE(short, long, &timestamp_t_var, description)`::\n  \tIntroduce an option with date argument, see `approxidate()`.\n -\tThe timestamp is put into `time_t_var`.\n +\tThe timestamp is put into `timestamp_t_var`.\n  \n -`OPT_EXPIRY_DATE(short, long, &time_t_var, description)`::\n +`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n  \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n -\tThe timestamp is put into `time_t_var`.\n +\tThe timestamp is put into `timestamp_t_var`.\n  \n  `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n  \tIntroduce an option with argument.\n diff --git a/Makefile b/Makefile\n index 7dafef138c0..9b36068ac5e 100644\n --- a/Makefile\n +++ b/Makefile\n @@ -1530,10 +1530,6 @@ ifdef HAVE_GETDELIM\n  \tBASIC_CFLAGS += -DHAVE_GETDELIM\n  endif\n  \n -ifdef TIME_T_IS_INT64\n -\tBASIC_CFLAGS += -DTIME_T_IS_INT64\n -endif\n -\n  ifeq ($(TCLTK_PATH),)\n  NO_TCLTK = NoThanks\n  endif\n diff --git a/archive-zip.c b/archive-zip.c\n index b429a8d974a..4f715d40450 100644\n --- a/archive-zip.c\n +++ b/archive-zip.c\n @@ -545,10 +545,12 @@ static void write_zip_trailer(const unsigned char *sha1)\n  \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n  }\n  \n -static void dos_time(time_t *time, int *dos_date, int *dos_time)\n +static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n  {\n -\tstruct tm *t = localtime(time);\n +\ttime_t time;\n +\tstruct tm *t = localtime(&time);\n  \n +\t*timestamp = time;\n  \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n  \t            (t->tm_year + 1900 - 1980) * 512;\n  \t*dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;\n diff --git a/archive.h b/archive.h\n index 415e0152e2c..62d1d82c1af 100644\n --- a/archive.h\n +++ b/archive.h\n @@ -9,7 +9,7 @@ struct archiver_args {\n  \tstruct tree *tree;\n  \tconst unsigned char *commit_sha1;\n  \tconst struct commit *commit;\n -\ttime_t time;\n +\ttimestamp_t time;\n  \tstruct pathspec pathspec;\n  \tunsigned int verbose : 1;\n  \tunsigned int worktree_attributes : 1;\n diff --git a/builtin/am.c b/builtin/am.c\n index d683268790e..89914ed8757 100644\n --- a/builtin/am.c\n +++ b/builtin/am.c\n @@ -877,7 +877,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n  \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n  \t\t\tfprintf(out, \"From: %s\\n\", str);\n  \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n -\t\t\ttime_t timestamp;\n +\t\t\ttimestamp_t timestamp;\n  \t\t\tlong tz, tz2;\n  \t\t\tchar *end;\n  \n diff --git a/builtin/blame.c b/builtin/blame.c\n index 9a7e9a2fe52..e508694f9ab 100644\n --- a/builtin/blame.c\n +++ b/builtin/blame.c\n @@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n  struct commit_info {\n  \tstruct strbuf author;\n  \tstruct strbuf author_mail;\n -\ttime_t author_time;\n +\ttimestamp_t author_time;\n  \tstruct strbuf author_tz;\n  \n  \t/* filled only when asked for details */\n  \tstruct strbuf committer;\n  \tstruct strbuf committer_mail;\n -\ttime_t committer_time;\n +\ttimestamp_t committer_time;\n  \tstruct strbuf committer_tz;\n  \n  \tstruct strbuf summary;\n @@ -1578,7 +1578,7 @@ struct commit_info {\n   */\n  static void get_ac_line(const char *inbuf, const char *what,\n  \tstruct strbuf *name, struct strbuf *mail,\n -\ttime_t *time, struct strbuf *tz)\n +\ttimestamp_t *time, struct strbuf *tz)\n  {\n  \tstruct ident_split ident;\n  \tsize_t len, maillen, namelen;\n @@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n  \tstop_progress(&pi.progress);\n  }\n  \n -static const char *format_time(time_t time, const char *tz_str,\n +static const char *format_time(timestamp_t time, const char *tz_str,\n  \t\t\t       int show_raw_time)\n  {\n  \tstatic struct strbuf time_buf = STRBUF_INIT;\n diff --git a/builtin/gc.c b/builtin/gc.c\n index c2c61a57bb3..d38677cf44c 100644\n --- a/builtin/gc.c\n +++ b/builtin/gc.c\n @@ -33,7 +33,7 @@ static int aggressive_window = 250;\n  static int gc_auto_threshold = 6700;\n  static int gc_auto_pack_limit = 50;\n  static int detach_auto = 1;\n -static unsigned long gc_log_expire_time;\n +static timestamp_t gc_log_expire_time;\n  static const char *gc_log_expire = \"1.day.ago\";\n  static const char *prune_expire = \"2.weeks.ago\";\n  static const char *prune_worktrees_expire = \"3.months.ago\";\n diff --git a/builtin/log.c b/builtin/log.c\n index 84230d946d3..6d457f3b54a 100644\n --- a/builtin/log.c\n +++ b/builtin/log.c\n @@ -904,7 +904,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n  {\n  \tstruct strbuf buf = STRBUF_INIT;\n  \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n -\t\t    (time_t) time(NULL),\n +\t\t    (timestamp_t) time(NULL),\n  \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n  \tinfo->message_id = strbuf_detach(&buf, NULL);\n  }\n diff --git a/builtin/name-rev.c b/builtin/name-rev.c\n index cf4faf27730..ee4b6950e5a 100644\n --- a/builtin/name-rev.c\n +++ b/builtin/name-rev.c\n @@ -10,7 +10,7 @@\n  \n  typedef struct rev_name {\n  \tconst char *tip_name;\n -\ttime_t taggerdate;\n +\ttimestamp_t taggerdate;\n  \tint generation;\n  \tint distance;\n  } rev_name;\n @@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n  #define MERGE_TRAVERSAL_WEIGHT 65535\n  \n  static void name_rev(struct commit *commit,\n -\t\tconst char *tip_name, time_t taggerdate,\n +\t\tconst char *tip_name, timestamp_t taggerdate,\n  \t\tint generation, int distance,\n  \t\tint deref)\n  {\n @@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n  \tstruct name_ref_data *data = cb_data;\n  \tint can_abbreviate_output = data->tags_only && data->name_only;\n  \tint deref = 0;\n -\ttime_t taggerdate = TIME_MAX;\n +\ttimestamp_t taggerdate = TIME_MAX;\n  \n  \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n  \t\treturn 0;\n diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n index 0ab7a0e6c2e..9d0fef2e49a 100644\n --- a/builtin/pack-objects.c\n +++ b/builtin/pack-objects.c\n @@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n  static int non_empty;\n  static int reuse_delta = 1, reuse_object = 1;\n  static int keep_unreachable, unpack_unreachable, include_tag;\n -static time_t unpack_unreachable_expiration;\n +static timestamp_t unpack_unreachable_expiration;\n  static int pack_loose_unreachable;\n  static int local;\n  static int have_non_local_packs;\n @@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n  static struct sha1_array recent_objects;\n  \n  static int loosened_object_can_be_discarded(const unsigned char *sha1,\n -\t\t\t\t\t    time_t mtime)\n +\t\t\t\t\t    timestamp_t mtime)\n  {\n  \tif (!unpack_unreachable_expiration)\n  \t\treturn 0;\n diff --git a/builtin/prune.c b/builtin/prune.c\n index a28d2c71b28..8dcfecde0f3 100644\n --- a/builtin/prune.c\n +++ b/builtin/prune.c\n @@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n  };\n  static int show_only;\n  static int verbose;\n -static time_t expire;\n +static timestamp_t expire;\n  static int show_progress = -1;\n  \n  static int prune_tmp_file(const char *fullpath)\n diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\n index eba38524351..f8f4242719b 100644\n --- a/builtin/receive-pack.c\n +++ b/builtin/receive-pack.c\n @@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n  static const char *NONCE_SLOP = \"SLOP\";\n  static const char *nonce_status;\n  static long nonce_stamp_slop;\n -static time_t nonce_stamp_slop_limit;\n +static timestamp_t nonce_stamp_slop_limit;\n  static struct ref_transaction *transaction;\n  \n  static enum {\n @@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n  \tgit_SHA1_Final(out, &ctx);\n  }\n  \n -static char *prepare_push_cert_nonce(const char *path, time_t stamp)\n +static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n  {\n  \tstruct strbuf buf = STRBUF_INIT;\n  \tunsigned char sha1[20];\n @@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n  static const char *check_nonce(const char *buf, size_t len)\n  {\n  \tchar *nonce = find_header(buf, len, \"nonce\");\n -\ttime_t stamp, ostamp;\n +\ttimestamp_t stamp, ostamp;\n  \tchar *bohmac, *expect = NULL;\n  \tconst char *retval = NONCE_BAD;\n  \n @@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n  \t\tretval = NONCE_BAD;\n  \t\tgoto leave;\n  \t}\n -\tstamp = strtoul(nonce, &bohmac, 10);\n +\tstamp = parse_timestamp(nonce, &bohmac, 10);\n  \tif (bohmac == nonce || bohmac[0] != '-') {\n  \t\tretval = NONCE_BAD;\n  \t\tgoto leave;\n @@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n  \t * would mean it was issued by another server with its clock\n  \t * skewed in the future.\n  \t */\n -\tostamp = strtoul(push_cert_nonce, NULL, 10);\n +\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n  \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n  \n  \tif (nonce_stamp_slop_limit &&\n diff --git a/builtin/reflog.c b/builtin/reflog.c\n index 2dc05121b77..4228d9ff4db 100644\n --- a/builtin/reflog.c\n +++ b/builtin/reflog.c\n @@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n  static const char reflog_exists_usage[] =\n  \"git reflog exists <ref>\";\n  \n -static time_t default_reflog_expire;\n -static time_t default_reflog_expire_unreachable;\n +static timestamp_t default_reflog_expire;\n +static timestamp_t default_reflog_expire_unreachable;\n  \n  struct cmd_reflog_expire_cb {\n  \tstruct rev_info revs;\n  \tint stalefix;\n -\ttime_t expire_total;\n -\ttime_t expire_unreachable;\n +\ttimestamp_t expire_total;\n +\ttimestamp_t expire_unreachable;\n  \tint recno;\n  };\n  \n @@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n  static void mark_reachable(struct expire_reflog_policy_cb *cb)\n  {\n  \tstruct commit_list *pending;\n -\ttime_t expire_limit = cb->mark_limit;\n +\ttimestamp_t expire_limit = cb->mark_limit;\n  \tstruct commit_list *leftover = NULL;\n  \n  \tfor (pending = cb->mark_list; pending; pending = pending->next)\n @@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n   * Return true iff the specified reflog entry should be expired.\n   */\n  static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n -\t\t\t\t    const char *email, time_t timestamp, int tz,\n +\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n  \t\t\t\t    const char *message, void *cb_data)\n  {\n  \tstruct expire_reflog_policy_cb *cb = cb_data;\n @@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n  \n  static struct reflog_expire_cfg {\n  \tstruct reflog_expire_cfg *next;\n -\ttime_t expire_total;\n -\ttime_t expire_unreachable;\n +\ttimestamp_t expire_total;\n +\ttimestamp_t expire_unreachable;\n  \tchar pattern[FLEX_ARRAY];\n  } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n  \n @@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n  \treturn ent;\n  }\n  \n -static int parse_expire_cfg_value(const char *var, const char *value, time_t *expire)\n +static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n  {\n  \tif (!value)\n  \t\treturn config_error_nonbool(var);\n @@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n  {\n  \tconst char *pattern, *key;\n  \tint pattern_len;\n -\ttime_t expire;\n +\ttimestamp_t expire;\n  \tint slot;\n  \tstruct reflog_expire_cfg *ent;\n  \n @@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n  static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n  {\n  \tstruct expire_reflog_policy_cb cb;\n -\ttime_t now = time(NULL);\n +\ttimestamp_t now = time(NULL);\n  \tint i, status, do_all;\n  \tint explicit_expiry = 0;\n  \tunsigned int flags = 0;\n diff --git a/builtin/rev-list.c b/builtin/rev-list.c\n index 0aa93d58919..a30fbce3341 100644\n --- a/builtin/rev-list.c\n +++ b/builtin/rev-list.c\n @@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n  \t}\n  \n  \tif (info->show_timestamp)\n -\t\tprintf(\"%lu \", commit->date);\n +\t\tprintf(\"%\"PRItime\" \", commit->date);\n  \tif (info->header_prefix)\n  \t\tfputs(info->header_prefix, stdout);\n  \n diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\n index 9e53a1a7ca4..f1c26ca6e62 100644\n --- a/builtin/rev-parse.c\n +++ b/builtin/rev-parse.c\n @@ -218,7 +218,8 @@ static void show_datestring(const char *flag, const char *datestr)\n  \t/* date handling requires both flags and revs */\n  \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n  \t\treturn;\n -\tsnprintf(buffer, sizeof(buffer), \"%s%lu\", flag, approxidate(datestr));\n +\tsnprintf(buffer, sizeof(buffer), \"%s%\"PRItime,\n +\t\t flag, approxidate(datestr));\n  \tshow(buffer);\n  }\n  \n diff --git a/builtin/show-branch.c b/builtin/show-branch.c\n index ebd46fe6363..8860f429b06 100644\n --- a/builtin/show-branch.c\n +++ b/builtin/show-branch.c\n @@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n  \t\t\tbase = strtoul(reflog_base, &ep, 10);\n  \t\t\tif (*ep) {\n  \t\t\t\t/* Ah, that is a date spec... */\n -\t\t\t\ttime_t at;\n +\t\t\t\ttimestamp_t at;\n  \t\t\t\tat = approxidate(reflog_base);\n  \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n  \t\t\t\t\t    NULL, NULL, &base);\n @@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n  \t\t\tchar *logmsg;\n  \t\t\tchar *nth_desc;\n  \t\t\tconst char *msg;\n -\t\t\ttime_t timestamp;\n +\t\t\ttimestamp_t timestamp;\n  \t\t\tint tz;\n  \n  \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\n diff --git a/builtin/worktree.c b/builtin/worktree.c\n index 15e29e9e385..74f9b18d40c 100644\n --- a/builtin/worktree.c\n +++ b/builtin/worktree.c\n @@ -30,7 +30,7 @@ struct add_opts {\n  \n  static int show_only;\n  static int verbose;\n -static time_t expire;\n +static timestamp_t expire;\n  \n  static int prune_worktree(const char *id, struct strbuf *reason)\n  {\n diff --git a/bundle.c b/bundle.c\n index 75b82e6b653..05e014fc5ab 100644\n --- a/bundle.c\n +++ b/bundle.c\n @@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n  \tunsigned long size;\n  \tenum object_type type;\n  \tchar *buf = NULL, *line, *lineend;\n -\ttime_t date;\n +\ttimestamp_t date;\n  \tint result = 1;\n  \n  \tif (revs->max_age == -1 && revs->min_age == -1)\n diff --git a/cache.h b/cache.h\n index 6226634bf23..38f5c7dd3a5 100644\n --- a/cache.h\n +++ b/cache.h\n @@ -1472,18 +1472,18 @@ struct date_mode {\n  #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n  struct date_mode *date_mode_from_type(enum date_mode_type type);\n  \n -const char *show_date(time_t time, int timezone, const struct date_mode *mode);\n -void show_date_relative(time_t time, int tz, const struct timeval *now,\n +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n  \t\t\tstruct strbuf *timebuf);\n  int parse_date(const char *date, struct strbuf *out);\n -int parse_date_basic(const char *date, time_t *timestamp, int *offset);\n -int parse_expiry_date(const char *date, time_t *timestamp);\n +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n +int parse_expiry_date(const char *date, timestamp_t *timestamp);\n  void datestamp(struct strbuf *out);\n  #define approxidate(s) approxidate_careful((s), NULL)\n -time_t approxidate_careful(const char *, int *);\n -time_t approxidate_relative(const char *date, const struct timeval *now);\n +timestamp_t approxidate_careful(const char *, int *);\n +timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n  void parse_date_format(const char *format, struct date_mode *mode);\n -int date_overflows(time_t date);\n +int date_overflows(timestamp_t date);\n  \n  #define IDENT_STRICT\t       1\n  #define IDENT_NO_DATE\t       2\n diff --git a/commit.c b/commit.c\n index 5ddaa939ce4..99a62b90ee2 100644\n --- a/commit.c\n +++ b/commit.c\n @@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n  \treturn commit;\n  }\n  \n -static time_t parse_commit_date(const char *buf, const char *tail)\n +static timestamp_t parse_commit_date(const char *buf, const char *tail)\n  {\n  \tconst char *dateptr;\n  \n @@ -89,7 +89,7 @@ static time_t parse_commit_date(const char *buf, const char *tail)\n  \t\t/* nada */;\n  \tif (buf >= tail)\n  \t\treturn 0;\n -\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n +\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n  \treturn parse_timestamp(dateptr, NULL, 10);\n  }\n  \n @@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n  \n  static int commit_list_compare_by_date(const void *a, const void *b)\n  {\n -\ttime_t a_date = ((const struct commit_list *)a)->item->date;\n -\ttime_t b_date = ((const struct commit_list *)b)->item->date;\n +\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n +\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n  \tif (a_date < b_date)\n  \t\treturn 1;\n  \tif (a_date > b_date)\n @@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n  \tconst char *ident_line;\n  \tsize_t ident_len;\n  \tchar *date_end;\n -\ttime_t date;\n +\ttimestamp_t date;\n  \n  \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n  \tif (!ident_line)\n @@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n  {\n  \tconst struct commit *a = a_, *b = b_;\n  \tstruct author_date_slab *author_date = cb_data;\n -\ttime_t a_date = *(author_date_slab_at(author_date, a));\n -\ttime_t b_date = *(author_date_slab_at(author_date, b));\n +\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n +\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n  \n  \t/* newer commits with larger date first */\n  \tif (a_date < b_date)\n diff --git a/commit.h b/commit.h\n index f445fbea49b..5f2a837b067 100644\n --- a/commit.h\n +++ b/commit.h\n @@ -17,7 +17,7 @@ struct commit {\n  \tstruct object object;\n  \tvoid *util;\n  \tunsigned int index;\n -\ttime_t date;\n +\ttimestamp_t date;\n  \tstruct commit_list *parents;\n  \tstruct tree *tree;\n  };\n diff --git a/config.c b/config.c\n index 1a4d85537b3..3247bfaa020 100644\n --- a/config.c\n +++ b/config.c\n @@ -1926,7 +1926,7 @@ int git_config_get_expiry(const char *key, const char **output)\n  \tif (ret)\n  \t\treturn ret;\n  \tif (strcmp(*output, \"now\")) {\n -\t\tunsigned long now = approxidate(\"now\");\n +\t\ttimestamp_t now = approxidate(\"now\");\n  \t\tif (approxidate(*output) >= now)\n  \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n  \t}\n diff --git a/config.mak.uname b/config.mak.uname\n index aa18ed0af4d..399fe192719 100644\n --- a/config.mak.uname\n +++ b/config.mak.uname\n @@ -357,7 +357,6 @@ ifeq ($(uname_S),Windows)\n  \tNO_INET_PTON = YesPlease\n  \tNO_INET_NTOP = YesPlease\n  \tNO_POSIX_GOODIES = UnfortunatelyYes\n -\tTIME_T_IS_INT64 = YesItIs\n  \tNATIVE_CRLF = YesPlease\n  \tDEFAULT_HELP_FORMAT = html\n  \n @@ -504,7 +503,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))\n  \tNO_INET_PTON = YesPlease\n  \tNO_INET_NTOP = YesPlease\n  \tNO_POSIX_GOODIES = UnfortunatelyYes\n -\tTIME_T_IS_INT64 = YesItIs\n  \tDEFAULT_HELP_FORMAT = html\n  \tCOMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32\n  \tCOMPAT_CFLAGS += -DSTRIP_EXTENSION=\\\".exe\\\"\n diff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\n index 364e5e0c5be..f3814cc47a0 100644\n --- a/credential-cache--daemon.c\n +++ b/credential-cache--daemon.c\n @@ -8,7 +8,7 @@ static struct tempfile socket_file;\n  \n  struct credential_cache_entry {\n  \tstruct credential item;\n -\ttime_t expiration;\n +\ttimestamp_t expiration;\n  };\n  static struct credential_cache_entry *entries;\n  static int entries_nr;\n @@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n  \t\te->expiration = 0;\n  }\n  \n -static time_t check_expirations(void)\n +static timestamp_t check_expirations(void)\n  {\n -\tstatic time_t wait_for_entry_until;\n +\tstatic timestamp_t wait_for_entry_until;\n  \tint i = 0;\n -\ttime_t now = time(NULL);\n -\ttime_t next = TIME_MAX;\n +\ttimestamp_t now = time(NULL);\n +\ttimestamp_t next = TIME_MAX;\n  \n  \t/*\n  \t * Initially give the client 30 seconds to actually contact us\n @@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n  static int serve_cache_loop(int fd)\n  {\n  \tstruct pollfd pfd;\n -\ttime_t wakeup;\n +\ttimestamp_t wakeup;\n  \n  \twakeup = check_expirations();\n  \tif (!wakeup)\n diff --git a/date.c b/date.c\n index dad2d0c807e..db3435df3e4 100644\n --- a/date.c\n +++ b/date.c\n @@ -39,14 +39,17 @@ static const char *weekday_names[] = {\n  \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n  };\n  \n -static time_t gm_time_t(time_t time, int tz)\n +static time_t gm_time_t(timestamp_t time, int tz)\n  {\n  \tint minutes;\n  \n +\tif (date_overflows(time))\n +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n +\n  \tminutes = tz < 0 ? -tz : tz;\n  \tminutes = (minutes / 100)*60 + (minutes % 100);\n  \tminutes = tz < 0 ? -minutes : minutes;\n -\treturn time + minutes * 60;\n +\treturn (time_t)time + minutes * 60;\n  }\n  \n  /*\n @@ -54,9 +57,14 @@ static time_t gm_time_t(time_t time, int tz)\n   * thing, which means that tz -0100 is passed in as the integer -100,\n   * even though it means \"sixty minutes off\"\n   */\n -static struct tm *time_to_tm(time_t time, int tz)\n +static struct tm *time_to_tm(timestamp_t time, int tz)\n  {\n -\ttime_t t = gm_time_t(time, tz);\n +\ttime_t t;\n +\n +\tif (date_overflows(time))\n +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n +\n +\tt = gm_time_t((time_t)time, tz);\n  \treturn gmtime(&t);\n  }\n  \n @@ -64,13 +72,16 @@ static struct tm *time_to_tm(time_t time, int tz)\n   * What value of \"tz\" was in effect back then at \"time\" in the\n   * local timezone?\n   */\n -static int local_tzoffset(time_t time)\n +static int local_tzoffset(timestamp_t time)\n  {\n  \ttime_t t, t_local;\n  \tstruct tm tm;\n  \tint offset, eastwest;\n  \n -\tt = time;\n +\tif (date_overflows(time))\n +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n +\n +\tt = (time_t)time;\n  \tlocaltime_r(&t, &tm);\n  \tt_local = tm_to_time_t(&tm);\n  \n @@ -88,11 +99,11 @@ static int local_tzoffset(time_t time)\n  \treturn offset * eastwest;\n  }\n  \n -void show_date_relative(time_t time, int tz,\n +void show_date_relative(timestamp_t time, int tz,\n  \t\t\t       const struct timeval *now,\n  \t\t\t       struct strbuf *timebuf)\n  {\n -\ttime_t diff;\n +\ttimestamp_t diff;\n  \tif (now->tv_sec < time) {\n  \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n  \t\treturn;\n @@ -140,9 +151,9 @@ void show_date_relative(time_t time, int tz,\n  \t}\n  \t/* Give years and months for 5 years or so */\n  \tif (diff < 1825) {\n -\t\ttime_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n -\t\ttime_t years = totalmonths / 12;\n -\t\ttime_t months = totalmonths % 12;\n +\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n +\t\ttimestamp_t years = totalmonths / 12;\n +\t\ttimestamp_t months = totalmonths % 12;\n  \t\tif (months) {\n  \t\t\tstruct strbuf sb = STRBUF_INIT;\n  \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n @@ -172,7 +183,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n  \treturn &mode;\n  }\n  \n -const char *show_date(time_t time, int tz, const struct date_mode *mode)\n +const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n  {\n  \tstruct tm *tm;\n  \tstatic struct strbuf timebuf = STRBUF_INIT;\n @@ -425,7 +436,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n  \treturn 0;\n  }\n  \n -static int match_multi_number(time_t num, char c, const char *date,\n +static int match_multi_number(timestamp_t num, char c, const char *date,\n  \t\t\t      char *end, struct tm *tm, time_t now)\n  {\n  \tstruct tm now_tm;\n @@ -508,7 +519,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n  {\n  \tint n;\n  \tchar *end;\n -\ttime_t num;\n +\ttimestamp_t num;\n  \n  \tnum = parse_timestamp(date, &end, 10);\n  \n @@ -635,7 +646,7 @@ static int match_tz(const char *date, int *offp)\n  \treturn end - date;\n  }\n  \n -static void date_string(time_t date, int offset, struct strbuf *buf)\n +static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n  {\n  \tint sign = '+';\n  \n @@ -650,10 +661,10 @@ static void date_string(time_t date, int offset, struct strbuf *buf)\n   * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n   * only when it appears not as part of any other string.\n   */\n -static int match_object_header_date(const char *date, time_t *timestamp, int *offset)\n +static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n  {\n  \tchar *end;\n -\ttime_t stamp;\n +\ttimestamp_t stamp;\n  \tint ofs;\n  \n  \tif (*date < '0' || '9' < *date)\n @@ -675,11 +686,11 @@ static int match_object_header_date(const char *date, time_t *timestamp, int *of\n  \n  /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n     (i.e. English) day/month names, and it doesn't work correctly with %z. */\n -int parse_date_basic(const char *date, time_t *timestamp, int *offset)\n +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n  {\n  \tstruct tm tm;\n  \tint tm_gmt;\n -\ttime_t dummy_timestamp;\n +\ttimestamp_t dummy_timestamp;\n  \tint dummy_offset;\n  \n  \tif (!timestamp)\n @@ -747,7 +758,7 @@ int parse_date_basic(const char *date, time_t *timestamp, int *offset)\n  \treturn 0; /* success */\n  }\n  \n -int parse_expiry_date(const char *date, time_t *timestamp)\n +int parse_expiry_date(const char *date, timestamp_t *timestamp)\n  {\n  \tint errors = 0;\n  \n @@ -771,7 +782,7 @@ int parse_expiry_date(const char *date, time_t *timestamp)\n  \n  int parse_date(const char *date, struct strbuf *result)\n  {\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tint offset;\n  \tif (parse_date_basic(date, &timestamp, &offset))\n  \t\treturn -1;\n @@ -1066,7 +1077,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n  \t\t\t\t     time_t now)\n  {\n  \tchar *end;\n -\ttime_t number = parse_timestamp(date, &end, 10);\n +\ttimestamp_t number = parse_timestamp(date, &end, 10);\n  \n  \tswitch (*end) {\n  \tcase ':':\n @@ -1114,9 +1125,9 @@ static void pending_number(struct tm *tm, int *num)\n  \t}\n  }\n  \n -static time_t approxidate_str(const char *date,\n -\t\t\t\t     const struct timeval *tv,\n -\t\t\t\t     int *error_ret)\n +static timestamp_t approxidate_str(const char *date,\n +\t\t\t\t   const struct timeval *tv,\n +\t\t\t\t   int *error_ret)\n  {\n  \tint number = 0;\n  \tint touched = 0;\n @@ -1148,12 +1159,12 @@ static time_t approxidate_str(const char *date,\n  \tpending_number(&tm, &number);\n  \tif (!touched)\n  \t\t*error_ret = 1;\n -\treturn update_tm(&tm, &now, 0);\n +\treturn (timestamp_t)update_tm(&tm, &now, 0);\n  }\n  \n -time_t approxidate_relative(const char *date, const struct timeval *tv)\n +timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n  {\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tint offset;\n  \tint errors = 0;\n  \n @@ -1162,10 +1173,10 @@ time_t approxidate_relative(const char *date, const struct timeval *tv)\n  \treturn approxidate_str(date, tv, &errors);\n  }\n  \n -time_t approxidate_careful(const char *date, int *error_ret)\n +timestamp_t approxidate_careful(const char *date, int *error_ret)\n  {\n  \tstruct timeval tv;\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tint offset;\n  \tint dummy = 0;\n  \tif (!error_ret)\n @@ -1180,7 +1191,7 @@ time_t approxidate_careful(const char *date, int *error_ret)\n  \treturn approxidate_str(date, &tv, error_ret);\n  }\n  \n -int date_overflows(time_t t)\n +int date_overflows(timestamp_t t)\n  {\n  \ttime_t sys;\n  \n diff --git a/fetch-pack.c b/fetch-pack.c\n index bea2f59299d..b4b2475e7a6 100644\n --- a/fetch-pack.c\n +++ b/fetch-pack.c\n @@ -392,7 +392,7 @@ static int find_common(struct fetch_pack_args *args,\n  \tif (args->depth > 0)\n  \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n  \tif (args->deepen_since) {\n -\t\ttime_t max_age = approxidate(args->deepen_since);\n +\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n  \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n  \t}\n  \tif (args->deepen_not) {\n @@ -581,7 +581,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n  }\n  \n  static void mark_recent_complete_commits(struct fetch_pack_args *args,\n -\t\t\t\t\t time_t cutoff)\n +\t\t\t\t\t timestamp_t cutoff)\n  {\n  \twhile (complete && cutoff <= complete->item->date) {\n  \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n @@ -668,7 +668,7 @@ static int everything_local(struct fetch_pack_args *args,\n  {\n  \tstruct ref *ref;\n  \tint retval;\n -\ttime_t cutoff = 0;\n +\ttimestamp_t cutoff = 0;\n  \n  \tsave_commit_buffer = 0;\n  \n diff --git a/git-compat-util.h b/git-compat-util.h\n index cb68e700d5e..c678ca94b8f 100644\n --- a/git-compat-util.h\n +++ b/git-compat-util.h\n @@ -319,14 +319,13 @@ extern char *gitdirname(char *);\n  #define PRIo32 \"o\"\n  #endif\n  \n -#ifdef TIME_T_IS_INT64\n -#define PRItime PRId64\n -#define parse_timestamp strtoull\n -#define TIME_MAX INT64_MAX\n +typedef uintmax_t timestamp_t;\n +#define PRItime PRIuMAX\n +#define parse_timestamp strtoumax\n +#ifdef ULLONG_MAX\n +#define TIME_MAX ULLONG_MAX\n  #else\n -#define PRItime \"lu\"\n -#define parse_timestamp strtoul\n -#define TIME_MAX LONG_MAX\n +#define TIME_MAX ULONG_MAX\n  #endif\n  \n  #ifndef PATH_SEP\n diff --git a/http-backend.c b/http-backend.c\n index 4e88735a9e3..d6ea6075339 100644\n --- a/http-backend.c\n +++ b/http-backend.c\n @@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n  \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n  }\n  \n -static void hdr_date(struct strbuf *hdr, const char *name, time_t when)\n +static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n  {\n  \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n  \thdr_str(hdr, name, value);\n @@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n  \n  static void hdr_cache_forever(struct strbuf *hdr)\n  {\n -\ttime_t now = time(NULL);\n +\ttimestamp_t now = time(NULL);\n  \thdr_date(hdr, \"Date\", now);\n  \thdr_date(hdr, \"Expires\", now + 31536000);\n  \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\n diff --git a/parse-options-cb.c b/parse-options-cb.c\n index a560d8d0b8c..ff3b7fa7aaa 100644\n --- a/parse-options-cb.c\n +++ b/parse-options-cb.c\n @@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n  int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n  \t\t\t     int unset)\n  {\n -\t*(time_t *)(opt->value) = approxidate(arg);\n +\t*(timestamp_t *)(opt->value) = approxidate(arg);\n  \treturn 0;\n  }\n  \n  int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n  \t\t\t     int unset)\n  {\n -\treturn parse_expiry_date(arg, (time_t *)opt->value);\n +\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n  }\n  \n  int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n diff --git a/pretty.c b/pretty.c\n index 703eaf66586..587d48371b0 100644\n --- a/pretty.c\n +++ b/pretty.c\n @@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n  const char *show_ident_date(const struct ident_split *ident,\n  \t\t\t    const struct date_mode *mode)\n  {\n -\ttime_t date = 0;\n +\ttimestamp_t date = 0;\n  \tlong tz = 0;\n  \n  \tif (ident->date_begin && ident->date_end)\n diff --git a/reachable.c b/reachable.c\n index f6285f66726..682418f5d23 100644\n --- a/reachable.c\n +++ b/reachable.c\n @@ -55,7 +55,7 @@ static void mark_commit(struct commit *c, void *data)\n  \n  struct recent_data {\n  \tstruct rev_info *revs;\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  };\n  \n  static void add_recent_object(const struct object_id *oid,\n @@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n  }\n  \n  int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n -\t\t\t\t\t   time_t timestamp)\n +\t\t\t\t\t   timestamp_t timestamp)\n  {\n  \tstruct recent_data data;\n  \tint r;\n @@ -156,7 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n  }\n  \n  void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n -\t\t\t    time_t mark_recent, struct progress *progress)\n +\t\t\t    timestamp_t mark_recent, struct progress *progress)\n  {\n  \tstruct connectivity_progress cp;\n  \n diff --git a/reachable.h b/reachable.h\n index 2a7f6588941..3c00fa0526c 100644\n --- a/reachable.h\n +++ b/reachable.h\n @@ -3,8 +3,8 @@\n  \n  struct progress;\n  extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n -\t\t\t\t\t\t  time_t timestamp);\n +\t\t\t\t\t\t  timestamp_t timestamp);\n  extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n -\t\t\t\t   time_t mark_recent, struct progress *);\n +\t\t\t\t   timestamp_t mark_recent, struct progress *);\n  \n  #endif\n diff --git a/ref-filter.c b/ref-filter.c\n index 08ded90f363..4fdacda0887 100644\n --- a/ref-filter.c\n +++ b/ref-filter.c\n @@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n  {\n  \tconst char *eoemail = strstr(buf, \"> \");\n  \tchar *zone;\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tlong tz;\n  \tstruct date_mode date_mode = { DATE_NORMAL };\n  \tconst char *formatp;\n diff --git a/reflog-walk.c b/reflog-walk.c\n index 674930e47d3..3ca5ed8415a 100644\n --- a/reflog-walk.c\n +++ b/reflog-walk.c\n @@ -12,7 +12,7 @@ struct complete_reflogs {\n  \tstruct reflog_info {\n  \t\tstruct object_id ooid, noid;\n  \t\tchar *email;\n -\t\ttime_t timestamp;\n +\t\ttimestamp_t timestamp;\n  \t\tint tz;\n  \t\tchar *message;\n  \t} *items;\n @@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n  }\n  \n  static int get_reflog_recno_by_time(struct complete_reflogs *array,\n -\ttime_t timestamp)\n +\ttimestamp_t timestamp)\n  {\n  \tint i;\n  \tfor (i = array->nr - 1; i >= 0; i--)\n @@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n  int add_reflog_for_walk(struct reflog_walk_info *info,\n  \t\tstruct commit *commit, const char *name)\n  {\n -\ttime_t timestamp = 0;\n +\ttimestamp_t timestamp = 0;\n  \tint recno = -1;\n  \tstruct string_list_item *item;\n  \tstruct complete_reflogs *reflogs;\n diff --git a/refs.c b/refs.c\n index 2549caa9403..6018b3104c6 100644\n --- a/refs.c\n +++ b/refs.c\n @@ -659,7 +659,7 @@ int is_branch(const char *refname)\n  \n  struct read_ref_at_cb {\n  \tconst char *refname;\n -\ttime_t at_time;\n +\ttimestamp_t at_time;\n  \tint cnt;\n  \tint reccnt;\n  \tunsigned char *sha1;\n @@ -668,9 +668,9 @@ struct read_ref_at_cb {\n  \tunsigned char osha1[20];\n  \tunsigned char nsha1[20];\n  \tint tz;\n -\ttime_t date;\n +\ttimestamp_t date;\n  \tchar **msg;\n -\ttime_t *cutoff_time;\n +\ttimestamp_t *cutoff_time;\n  \tint *cutoff_tz;\n  \tint *cutoff_cnt;\n  };\n @@ -743,9 +743,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n  \treturn 1;\n  }\n  \n -int read_ref_at(const char *refname, unsigned int flags, time_t at_time, int cnt,\n +int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n  \t\tunsigned char *sha1, char **msg,\n -\t\ttime_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n +\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n  {\n  \tstruct read_ref_at_cb cb;\n  \n diff --git a/refs.h b/refs.h\n index 747cd10af46..cc79ae4b8ed 100644\n --- a/refs.h\n +++ b/refs.h\n @@ -262,9 +262,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n  \n  /** Reads log for the value of ref during at_time. **/\n  int read_ref_at(const char *refname, unsigned int flags,\n -\t\ttime_t at_time, int cnt,\n +\t\ttimestamp_t at_time, int cnt,\n  \t\tunsigned char *sha1, char **msg,\n -\t\ttime_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n +\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n  \n  /** Check if a particular reflog exists */\n  int reflog_exists(const char *refname);\n @@ -537,7 +537,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n  typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n  \t\t\t\t\t  unsigned char *nsha1,\n  \t\t\t\t\t  const char *email,\n -\t\t\t\t\t  time_t timestamp, int tz,\n +\t\t\t\t\t  timestamp_t timestamp, int tz,\n  \t\t\t\t\t  const char *message, void *cb_data);\n  typedef void reflog_expiry_cleanup_fn(void *cb_data);\n  \n diff --git a/refs/files-backend.c b/refs/files-backend.c\n index a5486577b47..a27a67dd2ad 100644\n --- a/refs/files-backend.c\n +++ b/refs/files-backend.c\n @@ -3104,7 +3104,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n  {\n  \tstruct object_id ooid, noid;\n  \tchar *email_end, *message;\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tint tz;\n  \tconst char *p = sb->buf;\n  \n @@ -3114,7 +3114,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n  \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n  \t    !(email_end = strchr(p, '>')) ||\n  \t    email_end[1] != ' ' ||\n -\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n +\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n  \t    !message || message[0] != ' ' ||\n  \t    (message[1] != '+' && message[1] != '-') ||\n  \t    !isdigit(message[2]) || !isdigit(message[3]) ||\n @@ -3976,7 +3976,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n  \t\t\tprintf(\"prune %s\", message);\n  \t} else {\n  \t\tif (cb->newlog) {\n -\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n +\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n  \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n  \t\t\t\temail, timestamp, tz, message);\n  \t\t\toidcpy(&cb->last_kept_oid, noid);\n diff --git a/revision.c b/revision.c\n index e95d680ca68..8a8c1789c7b 100644\n --- a/revision.c\n +++ b/revision.c\n @@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n  /* How many extra uninteresting commits we want to see.. */\n  #define SLOP 5\n  \n -static int still_interesting(struct commit_list *src, time_t date, int slop,\n +static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n  \t\t\t     struct commit **interesting_cache)\n  {\n  \t/*\n @@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n  static int limit_list(struct rev_info *revs)\n  {\n  \tint slop = SLOP;\n -\ttime_t date = ~0ul;\n +\ttimestamp_t date = TIME_MAX;\n  \tstruct commit_list *list = revs->commits;\n  \tstruct commit_list *newlist = NULL;\n  \tstruct commit_list **p = &newlist;\n diff --git a/revision.h b/revision.h\n index 623bb588cb1..0d9e68b36e9 100644\n --- a/revision.h\n +++ b/revision.h\n @@ -181,8 +181,8 @@ struct rev_info {\n  \t/* special limits */\n  \tint skip_count;\n  \tint max_count;\n -\ttime_t max_age;\n -\ttime_t min_age;\n +\ttimestamp_t max_age;\n +\ttimestamp_t min_age;\n  \tint min_parents;\n  \tint max_parents;\n  \tint (*include_check)(struct commit *, void *);\n diff --git a/sha1_name.c b/sha1_name.c\n index 42e794d4c0b..8ab1744ebab 100644\n --- a/sha1_name.c\n +++ b/sha1_name.c\n @@ -658,8 +658,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n  \n  \tif (reflog_len) {\n  \t\tint nth, i;\n -\t\ttime_t at_time;\n -\t\ttime_t co_time;\n +\t\ttimestamp_t at_time;\n +\t\ttimestamp_t co_time;\n  \t\tint co_tz, co_cnt;\n  \n  \t\t/* Is it asking for N-th entry, or approxidate? */\n diff --git a/t/helper/test-date.c b/t/helper/test-date.c\n index 371f9d259c6..f414a3ac670 100644\n --- a/t/helper/test-date.c\n +++ b/t/helper/test-date.c\n @@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n  \"  test-date show:<format> [time_t]...\\n\"\n  \"  test-date parse [date]...\\n\"\n  \"  test-date approxidate [date]...\\n\"\n -\"  test-date is64bit\\n\";\n +\"  test-date is64bit\\n\"\n +\"  test-date time_t-is64bit\\n\";\n  \n  static void show_relative_dates(const char **argv, struct timeval *now)\n  {\n @@ -26,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n  \tparse_date_format(format, &mode);\n  \tfor (; *argv; argv++) {\n  \t\tchar *arg;\n -\t\ttime_t t;\n +\t\ttimestamp_t t;\n  \t\tint tz;\n  \n  \t\t/*\n @@ -47,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n  \tstruct strbuf result = STRBUF_INIT;\n  \n  \tfor (; *argv; argv++) {\n -\t\ttime_t t;\n +\t\ttimestamp_t t;\n  \t\tint tz;\n  \n  \t\tstrbuf_reset(&result);\n @@ -64,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n  static void parse_approxidate(const char **argv, struct timeval *now)\n  {\n  \tfor (; *argv; argv++) {\n -\t\ttime_t t;\n +\t\ttimestamp_t t;\n  \t\tt = approxidate_relative(*argv, now);\n  \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n  \t}\n @@ -95,6 +96,8 @@ int cmd_main(int argc, const char **argv)\n  \telse if (!strcmp(*argv, \"approxidate\"))\n  \t\tparse_approxidate(argv+1, &now);\n  \telse if (!strcmp(*argv, \"is64bit\"))\n +\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n +\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n  \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n  \telse\n  \t\tusage(usage_msg);\n diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\n index 8af62dd7501..75fe883aac1 100644\n --- a/t/helper/test-parse-options.c\n +++ b/t/helper/test-parse-options.c\n @@ -5,7 +5,7 @@\n  static int boolean = 0;\n  static int integer = 0;\n  static unsigned long magnitude = 0;\n -static time_t timestamp;\n +static timestamp_t timestamp;\n  static int abbrev = 7;\n  static int verbose = -1; /* unspecified */\n  static int dry_run = 0, quiet = 0;\n diff --git a/t/t0006-date.sh b/t/t0006-date.sh\n index 9539b425ffb..42d4ea61ef5 100755\n --- a/t/t0006-date.sh\n +++ b/t/t0006-date.sh\n @@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n  \n  # arbitrary time absurdly far in the future\n  FUTURE=\"5758122296 -0400\"\n -check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n -check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n +check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n +check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n  \n  check_parse() {\n  \techo \"$1 -> $2\" >expect\n diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\n index 997aa9dea28..fe2d4f15a73 100755\n --- a/t/t5000-tar-tree.sh\n +++ b/t/t5000-tar-tree.sh\n @@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n  \tgit archive HEAD >future.tar\n  '\n  \n -test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n +test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n  \techo 4147 >expect &&\n  \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n  \ttest_cmp expect actual\n diff --git a/t/test-lib.sh b/t/test-lib.sh\n index beee1d847ff..8d25cb7c183 100644\n --- a/t/test-lib.sh\n +++ b/t/test-lib.sh\n @@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n  '\n  \n  test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n +test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n diff --git a/tag.c b/tag.c\n index a0b22c788b6..d71b67e8d83 100644\n --- a/tag.c\n +++ b/tag.c\n @@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n  \treturn object_as_type(obj, OBJ_TAG, 0);\n  }\n  \n -static time_t parse_tag_date(const char *buf, const char *tail)\n +static timestamp_t parse_tag_date(const char *buf, const char *tail)\n  {\n  \tconst char *dateptr;\n  \n @@ -110,7 +110,7 @@ static time_t parse_tag_date(const char *buf, const char *tail)\n  \t\t/* nada */;\n  \tif (buf >= tail)\n  \t\treturn 0;\n -\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n +\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n  \treturn parse_timestamp(dateptr, NULL, 10);\n  }\n  \n diff --git a/tag.h b/tag.h\n index aaf56849de8..2abb3726fb5 100644\n --- a/tag.h\n +++ b/tag.h\n @@ -9,7 +9,7 @@ struct tag {\n  \tstruct object object;\n  \tstruct object *tagged;\n  \tchar *tag;\n -\ttime_t date;\n +\ttimestamp_t date;\n  };\n  \n  extern struct tag *lookup_tag(const unsigned char *sha1);\n diff --git a/upload-pack.c b/upload-pack.c\n index df9b8476991..97da13e6a54 100644\n --- a/upload-pack.c\n +++ b/upload-pack.c\n @@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n  #define CLIENT_SHALLOW\t(1u << 18)\n  #define HIDDEN_REF\t(1u << 19)\n  \n -static time_t oldest_have;\n +static timestamp_t oldest_have;\n  \n  static int deepen_relative;\n  static int multi_ack;\n @@ -735,7 +735,7 @@ static void receive_needs(void)\n  \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n  \tint depth = 0;\n  \tint has_non_tip = 0;\n -\ttime_t deepen_since = 0;\n +\ttimestamp_t deepen_since = 0;\n  \tint deepen_rev_list = 0;\n  \n  \tshallow_nr = 0;\n diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\n index 5df87ce6bb4..5a89db30e3f 100644\n --- a/vcs-svn/fast_export.c\n +++ b/vcs-svn/fast_export.c\n @@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n  }\n  \n  void fast_export_begin_note(uint32_t revision, const char *author,\n -\t\tconst char *log, time_t timestamp, const char *note_ref)\n +\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n  {\n  \tstatic int firstnote = 1;\n  \tsize_t loglen = strlen(log);\n @@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n  void fast_export_begin_commit(uint32_t revision, const char *author,\n  \t\t\tconst struct strbuf *log,\n  \t\t\tconst char *uuid, const char *url,\n -\t\t\ttime_t timestamp, const char *local_ref)\n +\t\t\ttimestamp_t timestamp, const char *local_ref)\n  {\n  \tstatic const struct strbuf empty = STRBUF_INIT;\n  \tif (!log)\n diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\n index 864dada2b31..b9a3b71c99f 100644\n --- a/vcs-svn/fast_export.h\n +++ b/vcs-svn/fast_export.h\n @@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n  void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n  void fast_export_note(const char *committish, const char *dataref);\n  void fast_export_begin_note(uint32_t revision, const char *author,\n -\t\tconst char *log, time_t timestamp, const char *note_ref);\n +\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n  void fast_export_begin_commit(uint32_t revision, const char *author,\n  \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n -\t\t\ttime_t timestamp, const char *local_ref);\n +\t\t\ttimestamp_t timestamp, const char *local_ref);\n  void fast_export_end_commit(uint32_t revision);\n  void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n  void fast_export_buf_to_data(const struct strbuf *data);\n diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\n index 9e1eb8d4176..1846685a21a 100644\n --- a/vcs-svn/svndump.c\n +++ b/vcs-svn/svndump.c\n @@ -47,7 +47,7 @@ static struct {\n  \n  static struct {\n  \tuint32_t revision;\n -\ttime_t timestamp;\n +\ttimestamp_t timestamp;\n  \tstruct strbuf log, author, note;\n  } rev_ctx;\n  \n\n-- \n2.12.2.windows.1\n\n"},{"id":"316062","messageId":"bf91c11bd145a2f4b049ac02c02a18e58c496834.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:10Z","receivedAt":"2017-04-02T19:06:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply change that field to use `uintmax_t` instead.\n\nThis patch is a bit larger than the mere change of the data type\nbecause the field's name was tied to its data type, which has been fixed\nat the same time.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 9c82b5b9d63..8538328fc7f 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -351,7 +351,7 @@ struct ref_formatting_state {\n struct atom_value {\n \tconst char *s;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n \tstruct used_atom *atom;\n };\n \n@@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -875,11 +875,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1934,9 +1934,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316063","messageId":"83688a824b97d99b5a7476501b71b3d40eabe957.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 2/8] t0006 & t5000: prepare for 64-bit timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:15Z","receivedAt":"2017-04-02T19:06:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply uses an incorrect data type for timestamps, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) papered over this\nissue simply by skipping the respective test cases on platforms where\nthey would fail due to the data type in use.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`,\nconflating the two issues.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, after we\nswitch to a larger data type, we can flip that prerequisite to test\n`time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 13b5696822d..beee1d847ff 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1164,3 +1164,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316064","messageId":"f78a0270f1cadd3228006ce81c217ad5c3f9bedb.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 3/8] t0006 & t5000: skip \"far in the future\" test when time_t is too limited","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:20Z","receivedAt":"2017-04-02T19:06:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned long, which is\nill-defined, as there is no guarantee about the number of bits that\ndata type has.\n\nIn preparation of switching to another data type that is large enough\nto hold \"far in the future\" dates, we need to prepare the t0006-date.sh\nscript for the case where we *still* cannot format those dates if the\nsystem library uses 32-bit time_t.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 2 +-\n t/test-lib.sh        | 1 +\n 4 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..ac7c66c733b 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n \"  test-date approxidate [date]...\\n\"\n-\"  test-date is64bit\\n\";\n+\"  test-date is64bit\\n\"\n+\"  test-date time_t-is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -96,6 +97,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n \t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 9539b425ffb..42d4ea61ef5 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 997aa9dea28..fe2d4f15a73 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex beee1d847ff..8d25cb7c183 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n '\n \n test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n+test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316065","messageId":"7876460edaa85d93b60c0cc1b2f9a715de97180c.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 4/8] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:40Z","receivedAt":"2017-04-02T19:06:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using a more appropriate data type, let's\nintroduce a symbol `parse_timestamp` (currently being defined to\n`strtoul`) where appropriate, so that we can later easily switch to,\nsay, use `strtoull()` instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c           | 2 +-\n builtin/receive-pack.c | 4 ++--\n bundle.c               | 2 +-\n commit.c               | 6 +++---\n date.c                 | 6 +++---\n fsck.c                 | 2 +-\n git-compat-util.h      | 2 ++\n pretty.c               | 2 +-\n ref-filter.c           | 2 +-\n refs/files-backend.c   | 2 +-\n t/helper/test-date.c   | 2 +-\n tag.c                  | 4 ++--\n upload-pack.c          | 2 +-\n 13 files changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex f7a7a971fbe..2c93adc69c3 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -882,7 +882,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex aca9c33d8d8..fd8a24dd47e 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n \t}\n-\tstamp = strtoul(nonce, &bohmac, 10);\n+\tstamp = parse_timestamp(nonce, &bohmac, 10);\n \tif (bohmac == nonce || bohmac[0] != '-') {\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n@@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t * would mean it was issued by another server with its clock\n \t * skewed in the future.\n \t */\n-\tostamp = strtoul(push_cert_nonce, NULL, 10);\n+\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n \n \tif (nonce_stamp_slop_limit &&\ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 73c78c2b80c..0d2d0fa1984 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -89,8 +89,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -607,7 +607,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..495c207c64f 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\tunsigned long number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex 939792752bf..33a66e68a83 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -690,7 +690,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 8a4a3f85e7b..fc1b5fe1a6c 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex d0f86f5d85c..24fb0c79062 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 8538328fc7f..d81dd938579 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -868,7 +868,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 50188e92f9f..fe3e2ac8afe 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3114,7 +3114,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n \t    !(email_end = strchr(p, '>')) ||\n \t    email_end[1] != ' ' ||\n-\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n+\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n \t    !message || message[0] != ' ' ||\n \t    (message[1] != '+' && message[1] != '-') ||\n \t    !isdigit(message[2]) || !isdigit(message[3]) ||\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ac7c66c733b..52d1fc34454 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -34,7 +34,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..9b6725e02c9 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -110,8 +110,8 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ffb028d6231..f17f4dd1233 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316066","messageId":"6a209fb5df18b4be1315314f0100ed8ca64c0e4c.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 5/8] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:47Z","receivedAt":"2017-04-02T19:06:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\naway from the ill-specified `unsigned long` data type.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\ndefined to \"lu\") to make it easier to change the data type used for\ntimestamps.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n builtin/rev-list.c            |  2 +-\n builtin/rev-parse.c           |  3 ++-\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n refs/files-backend.c          |  2 +-\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 14 files changed, 31 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex f7aa95f4bab..ff7b2df023b 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1844,7 +1844,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex f76e4163abb..af7b985c6eb 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 670229cbb4c..079c659c754 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -903,7 +903,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex fd8a24dd47e..8814e49893e 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -459,12 +459,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 0aa93d58919..a30fbce3341 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n \t}\n \n \tif (info->show_timestamp)\n-\t\tprintf(\"%lu \", commit->date);\n+\t\tprintf(\"%\"PRItime\" \", commit->date);\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 9e53a1a7ca4..f1c26ca6e62 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -218,7 +218,8 @@ static void show_datestring(const char *flag, const char *datestr)\n \t/* date handling requires both flags and revs */\n \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n \t\treturn;\n-\tsnprintf(buffer, sizeof(buffer), \"%s%lu\", flag, approxidate(datestr));\n+\tsnprintf(buffer, sizeof(buffer), \"%s%\"PRItime,\n+\t\t flag, approxidate(datestr));\n \tshow(buffer);\n }\n \ndiff --git a/date.c b/date.c\nindex 495c207c64f..5c33dfd8ee7 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex d07d85ce302..fb268e328a4 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -393,7 +393,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex fc1b5fe1a6c..cd522903eda 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex fe3e2ac8afe..9b486980722 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3976,7 +3976,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n \t\t\tprintf(\"prune %s\", message);\n \t} else {\n \t\tif (cb->newlog) {\n-\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n+\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n \t\t\t\temail, timestamp, tz, message);\n \t\t\toidcpy(&cb->last_kept_oid, noid);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 52d1fc34454..269040f028f 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -53,7 +53,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex f17f4dd1233..4966f0b8a09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -863,7 +863,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316067","messageId":"fb0026d6f28ad3a9271091412b283b6eb5613368.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 6/8] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:06:52Z","receivedAt":"2017-04-02T19:07:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. Which is incorrect, and causes a lot of problems, in particular\nwhere unsigned long is only 32-bit (notably on Windows, even in 64-bit\nversions).\n\nSo let's just use a more appropriate data type instead. In preparation\nfor this, we introduce the new `timestamp_t` data type.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs we will use a data type that is not necessarily identical to `time_t`,\nwe need to be very careful to use `time_t` whenever we interact with the\nsystem functions, and `timestamp_t` everywhere else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++--\n archive-tar.c                                 |  5 +-\n archive-zip.c                                 |  6 ++-\n archive.h                                     |  2 +-\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++--\n builtin/fsck.c                                |  4 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +--\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        |  6 +--\n builtin/reflog.c                              | 24 +++++-----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 +++---\n commit.c                                      | 12 ++---\n commit.h                                      |  2 +-\n config.c                                      |  2 +-\n credential-cache--daemon.c                    | 12 ++---\n date.c                                        | 66 +++++++++++++--------------\n fetch-pack.c                                  |  6 +--\n git-compat-util.h                             |  2 +\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  2 +-\n reachable.c                                   |  9 ++--\n reachable.h                                   |  4 +-\n ref-filter.c                                  |  4 +-\n reflog-walk.c                                 |  8 ++--\n refs.c                                        | 14 +++---\n refs.h                                        |  8 ++--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +--\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +--\n t/helper/test-date.c                          |  8 ++--\n t/helper/test-parse-options.c                 |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +-\n vcs-svn/fast_export.c                         |  4 +-\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 48 files changed, 162 insertions(+), 156 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 36768b479e1..829b5581105 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,13 +183,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..695339a2369 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n #define USTAR_MAX_SIZE 077777777777UL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/archive-zip.c b/archive-zip.c\nindex b429a8d974a..4f715d40450 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -545,10 +545,12 @@ static void write_zip_trailer(const unsigned char *sha1)\n \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n }\n \n-static void dos_time(time_t *time, int *dos_date, int *dos_time)\n+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n {\n-\tstruct tm *t = localtime(time);\n+\ttime_t time;\n+\tstruct tm *t = localtime(&time);\n \n+\t*timestamp = time;\n \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n \t            (t->tm_year + 1900 - 1980) * 512;\n \t*dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e2c..62d1d82c1af 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -9,7 +9,7 @@ struct archiver_args {\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n-\ttime_t time;\n+\ttimestamp_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 2c93adc69c3..89914ed8757 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -877,7 +877,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex ff7b2df023b..e508694f9ab 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttimestamp_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttimestamp_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1578,7 +1578,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttimestamp_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(timestamp_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex af7b985c6eb..ea3a9f8a70a 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n }\n \n static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex c2c61a57bb3..d38677cf44c 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -33,7 +33,7 @@ static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 50;\n static int detach_auto = 1;\n-static unsigned long gc_log_expire_time;\n+static timestamp_t gc_log_expire_time;\n static const char *gc_log_expire = \"1.day.ago\";\n static const char *prune_expire = \"2.weeks.ago\";\n static const char *prune_worktrees_expire = \"3.months.ago\";\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 079c659c754..6d457f3b54a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -904,7 +904,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (timestamp_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex cfe2a796f85..8ed96391c1d 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 8bdc3eaa6fa..ee4b6950e5a 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttimestamp_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, timestamp_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\ttimestamp_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 84af7c2324b..9d0fef2e49a 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static timestamp_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct sha1_array recent_objects;\n \n static int loosened_object_can_be_discarded(const unsigned char *sha1,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    timestamp_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 42633e0c6e6..8dcfecde0f3 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 8814e49893e..f8f4242719b 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static timestamp_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttimestamp_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 74727757785..4228d9ff4db 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static timestamp_t default_reflog_expire;\n+static timestamp_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttimestamp_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttimestamp_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 19756595d57..8860f429b06 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttimestamp_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9993ded41aa..74f9b18d40c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..05e014fc5ab 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex 5c8078291c4..38f5c7dd3a5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1472,18 +1472,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, timestamp_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+timestamp_t approxidate_careful(const char *, int *);\n+timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(timestamp_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 0d2d0fa1984..99a62b90ee2 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static timestamp_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n+\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 528272ac9ba..5f2a837b067 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.c b/config.c\nindex 1a4d85537b3..3247bfaa020 100644\n--- a/config.c\n+++ b/config.c\n@@ -1926,7 +1926,7 @@ int git_config_get_expiry(const char *key, const char **output)\n \tif (ret)\n \t\treturn ret;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttimestamp_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..f3814cc47a0 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttimestamp_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static timestamp_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic timestamp_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\ttimestamp_t now = time(NULL);\n+\ttimestamp_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttimestamp_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 5c33dfd8ee7..92ab31aa441 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(timestamp_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttimestamp_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttimestamp_t years = totalmonths / 12;\n+\t\ttimestamp_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(timestamp_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttimestamp_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttimestamp_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttimestamp_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, timestamp_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = parse_timestamp(date, &end, 10);\n+\ttimestamp_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\n@@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n-\t\t\t\t     const struct timeval *tv,\n-\t\t\t\t     int *error_ret)\n+static timestamp_t approxidate_str(const char *date,\n+\t\t\t\t   const struct timeval *tv,\n+\t\t\t\t   int *error_ret)\n {\n \tint number = 0;\n \tint touched = 0;\n@@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,\n \tpending_number(&tm, &number);\n \tif (!touched)\n \t\t*error_ret = 1;\n-\treturn update_tm(&tm, &now, 0);\n+\treturn (timestamp_t)update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+timestamp_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(timestamp_t t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex fb268e328a4..b4b2475e7a6 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -392,7 +392,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -581,7 +581,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t timestamp_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -668,7 +668,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttimestamp_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex cd522903eda..72c12173a14 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+typedef unsigned long timestamp_t;\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..d6ea6075339 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex b7d8f7dcb2c..ff3b7fa7aaa 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(timestamp_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 24fb0c79062..587d48371b0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttimestamp_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4fc..682418f5d23 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n };\n \n static void add_recent_object(const struct object_id *oid,\n-\t\t\t      unsigned long mtime,\n+\t\t\t      timestamp_t mtime,\n \t\t\t      struct recent_data *data)\n {\n \tstruct object *obj;\n@@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    timestamp_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..3c00fa0526c 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  timestamp_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   timestamp_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex d81dd938579..4fdacda0887 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\n@@ -869,7 +869,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 99679f58255..3ca5ed8415a 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tstruct object_id ooid, noid;\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttimestamp_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttimestamp_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex 0272e332cc9..6018b3104c6 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -659,7 +659,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttimestamp_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -668,15 +668,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttimestamp_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -723,7 +723,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n }\n \n static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -743,9 +743,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 3df0d45ebb6..cc79ae4b8ed 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -262,9 +262,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttimestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int reflog_exists(const char *refname);\n@@ -293,7 +293,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tstruct object_id *old_oid, struct object_id *new_oid,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, timestamp_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);\n@@ -537,7 +537,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  timestamp_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 9b486980722..a27a67dd2ad 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3104,7 +3104,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tstruct object_id ooid, noid;\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint tz;\n \tconst char *p = sb->buf;\n \n@@ -3959,7 +3959,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, timestamp_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f73..8a8c1789c7b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttimestamp_t date = TIME_MAX;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n }\n \n static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(ooid, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 14886ec92b4..0d9e68b36e9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttimestamp_t max_age;\n+\ttimestamp_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex d9d1b2fce8d..8ab1744ebab 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -658,8 +658,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttimestamp_t at_time;\n+\t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1052,7 +1052,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 269040f028f..f414a3ac670 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -27,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n \tparse_date_format(format, &mode);\n \tfor (; *argv; argv++) {\n \t\tchar *arg;\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\t/*\n@@ -48,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -65,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n static void parse_approxidate(const char **argv, struct timeval *now)\n {\n \tfor (; *argv; argv++) {\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tt = approxidate_relative(*argv, now);\n \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n \t}\n@@ -96,7 +96,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n \telse if (!strcmp(*argv, \"time_t-is64bit\"))\n \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..75fe883aac1 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static timestamp_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/tag.c b/tag.c\nindex 9b6725e02c9..d71b67e8d83 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..2abb3726fb5 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttimestamp_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4966f0b8a09..97da13e6a54 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static timestamp_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttimestamp_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5a89db30e3f 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttimestamp_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..b9a3b71c99f 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttimestamp_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..1846685a21a 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 308cf3779eb..c2a9cba50aa 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1374,7 +1374,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, timestamp_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.12.2.windows.1\n\n\n"},{"id":"316068","messageId":"3b22b3545c38c0026a08aaec43b9a0f16762e5bc.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 7/8] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:07:13Z","receivedAt":"2017-04-02T19:07:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We are about to switch to a new data type for time stamps that is\ndefinitely not smaller or equal, but larger or equal to time_t.\n\nSo before using the system functions to process or format timestamps,\nlet's make extra certain that they can handle what we feed them.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n date.c | 17 ++++++++++++++---\n 1 file changed, 14 insertions(+), 3 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 92ab31aa441..db3435df3e4 100644\n--- a/date.c\n+++ b/date.c\n@@ -43,10 +43,13 @@ static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n \tminutes = tz < 0 ? -tz : tz;\n \tminutes = (minutes / 100)*60 + (minutes % 100);\n \tminutes = tz < 0 ? -minutes : minutes;\n-\treturn time + minutes * 60;\n+\treturn (time_t)time + minutes * 60;\n }\n \n /*\n@@ -56,7 +59,12 @@ static time_t gm_time_t(timestamp_t time, int tz)\n  */\n static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n-\ttime_t t = gm_time_t(time, tz);\n+\ttime_t t;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = gm_time_t((time_t)time, tz);\n \treturn gmtime(&t);\n }\n \n@@ -70,7 +78,10 @@ static int local_tzoffset(timestamp_t time)\n \tstruct tm tm;\n \tint offset, eastwest;\n \n-\tt = time;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = (time_t)time;\n \tlocaltime_r(&t, &tm);\n \tt_local = tm_to_time_t(&tm);\n \n-- \n2.12.2.windows.1\n\n\n"},{"id":"316069","messageId":"129b286d19fc47cf44a1517be11fe35b543495a0.1491159939.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v2 8/8] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-02T19:07:19Z","receivedAt":"2017-04-02T19:07:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we used `unsigned long` for timestamps. This was only a good\nchoice on Linux, where we know implicitly that `unsigned long` is what is\nused for `time_t`.\n\nHowever, we want to use a different data type for timestamps for two\nreasons:\n\n- there is nothing that says that `unsigned long` should be the same data\n  type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n  `unsigned long` is 32-bit but `time_t` is 64-bit.\n\n- even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n  32-bit, we *want* to be able to encode timestamps in Git that are\n  currently absurdly far in the future, *even if* the system library is\n  not able to format those timestamps into date strings.\n\nSo let's just switch to the maximal integer type available, which should\nbe at least 64-bit for all practical purposes these days. It certainly\ncannot be worse than `unsigned long`, so...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-compat-util.h | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 72c12173a14..c678ca94b8f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,10 +319,14 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n-typedef unsigned long timestamp_t;\n-#define PRItime \"lu\"\n-#define parse_timestamp strtoul\n+typedef uintmax_t timestamp_t;\n+#define PRItime PRIuMAX\n+#define parse_timestamp strtoumax\n+#ifdef ULLONG_MAX\n+#define TIME_MAX ULLONG_MAX\n+#else\n #define TIME_MAX ULONG_MAX\n+#endif\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n-- \n2.12.2.windows.1\n"},{"id":"316083","messageId":"342cae56-ef58-3542-202d-6dd04d5777e8@web.de","threadId":"45241","inReplyTo":"bf91c11bd145a2f4b049ac02c02a18e58c496834.1491159939.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2017-04-03T04:22:24Z","receivedAt":"2017-04-03T04:21:33Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n\nOn 02/04/17 21:06, Johannes Schindelin wrote:\n> In its `atom_value` struct, the ref-filter source code wants to store\n> different values in a field called `ul` (for `unsigned long`), e.g.\n> timestamps.\n>\n> However, as we are about to switch the data type of timestamps away from\n> `unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\n> that data type is not large enough.\n>\n> Simply change that field to use `uintmax_t` instead.\n>\n> This patch is a bit larger than the mere change of the data type\n> because the field's name was tied to its data type, which has been fixed\n> at the same time.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  ref-filter.c | 16 ++++++++--------\n>  1 file changed, 8 insertions(+), 8 deletions(-)\n>\n> diff --git a/ref-filter.c b/ref-filter.c\n> index 9c82b5b9d63..8538328fc7f 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -351,7 +351,7 @@ struct ref_formatting_state {\n>  struct atom_value {\n>  \tconst char *s;\n>  \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n> -\tunsigned long ul; /* used for sorting when not FIELD_STR */\n> +\tuintmax_t value; /* used for sorting when not FIELD_STR */\n>  \tstruct used_atom *atom;\n>  };\n>\n> @@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n>  \t\tif (!strcmp(name, \"objecttype\"))\n>  \t\t\tv->s = typename(obj->type);\n>  \t\telse if (!strcmp(name, \"objectsize\")) {\n> -\t\t\tv->ul = sz;\n> +\t\t\tv->value = sz;\n>  \t\t\tv->s = xstrfmt(\"%lu\", sz);\n>  \t\t}\n>  \t\telse if (deref)\n> @@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n>  \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n>  \t\t}\n>  \t\telse if (!strcmp(name, \"numparent\")) {\n> -\t\t\tv->ul = commit_list_count(commit->parents);\n> -\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n> +\t\t\tv->value = commit_list_count(commit->parents);\n> +\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n\nIf we want to get rid of \"%lu\" at some day, we can do like this:\nv->s = xstrfmt(\"%\" PRIuMAX, v->value);\nOr, to make clear that under all circumstances an unsigned long is big enough to\nhold the counter, for readers in the future, use something like this:\n\t\t\tv->s = xstrfmt(\"%lu\", (xulong_t)v->value);\n\n(this is more a reminder to myself, to send such a patch )\n"},{"id":"316084","messageId":"1485481a-f2b3-a0a2-89f6-8f55dc241b19@web.de","threadId":"45241","inReplyTo":"7876460edaa85d93b60c0cc1b2f9a715de97180c.1491159939.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2 4/8] Specify explicitly where we parse timestamps","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2017-04-03T04:26:16Z","receivedAt":"2017-04-03T04:25:24Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"[]\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n>  #define PRIo32 \"o\"\n>  #endif\n>\n> +#define parse_timestamp strtoul\n> +\n\nWould\n#define parse_timestamp(a,b,c)  strtoul((a),(b),(c))\nbe more strict ?\n\n"},{"id":"316119","messageId":"alpine.DEB.2.20.1704040044420.4268@virtualbox","threadId":"45241","inReplyTo":"342cae56-ef58-3542-202d-6dd04d5777e8@web.de","subject":"Re: [PATCH v2 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-03T22:47:58Z","receivedAt":"2017-04-03T22:48:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Mon, 3 Apr 2017, Torsten Bögershausen wrote:\n\n> On 02/04/17 21:06, Johannes Schindelin wrote:\n> > In its `atom_value` struct, the ref-filter source code wants to store\n> > different values in a field called `ul` (for `unsigned long`), e.g.\n> > timestamps.\n> >\n> > However, as we are about to switch the data type of timestamps away from\n> > `unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\n> > that data type is not large enough.\n> >\n> > Simply change that field to use `uintmax_t` instead.\n> >\n> > This patch is a bit larger than the mere change of the data type\n> > because the field's name was tied to its data type, which has been fixed\n> > at the same time.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  ref-filter.c | 16 ++++++++--------\n> >  1 file changed, 8 insertions(+), 8 deletions(-)\n> >\n> > diff --git a/ref-filter.c b/ref-filter.c\n> > index 9c82b5b9d63..8538328fc7f 100644\n> > --- a/ref-filter.c\n> > +++ b/ref-filter.c\n> > @@ -351,7 +351,7 @@ struct ref_formatting_state {\n> >  struct atom_value {\n> >   const char *s;\n> >   void (*handler)(struct atom_value *atomv, struct ref_formatting_state\n> >   *state);\n> > -\tunsigned long ul; /* used for sorting when not FIELD_STR */\n> > +\tuintmax_t value; /* used for sorting when not FIELD_STR */\n> >  \tstruct used_atom *atom;\n> >  };\n> >\n> > @@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val,\n> > int deref, struct object\n> >    if (!strcmp(name, \"objecttype\"))\n> >    \tv->s = typename(obj->type);\n> > \t\telse if (!strcmp(name, \"objectsize\")) {\n> > -\t\t\tv->ul = sz;\n> > +\t\t\tv->value = sz;\n> >    \tv->s = xstrfmt(\"%lu\", sz);\n> >    }\n> >    else if (deref)\n> > @@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val,\n> > int deref, struct object\n> >    \tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n> >    }\n> >    else if (!strcmp(name, \"numparent\")) {\n> > -\t\t\tv->ul = commit_list_count(commit->parents);\n> > -\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n> > +\t\t\tv->value = commit_list_count(commit->parents);\n> > +\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n> \n> If we want to get rid of \"%lu\" at some day, we can do like this:\n> v->s = xstrfmt(\"%\" PRIuMAX, v->value);\n> Or, to make clear that under all circumstances an unsigned long is big enough\n> to\n> hold the counter, for readers in the future, use something like this:\n> \t\t\tv->s = xstrfmt(\"%lu\", (xulong_t)v->value);\n\nWe could do that, yes.\n\nBut part of my patch series is to clarify in a semantic way what the\npurpose of the code is. Your solution would keep it syntactically correct,\nof course, but it would also make it semantically unclear again.\n\nBy writing \"%\"PRIutime *instead of* \"%\"PRIuMAX, we are saying: look, we\nare talking about a timestamp here. That would not at all be clear if we\nwrote \"%\"PRIuMAX.\n\nCiao,\nJohannes"},{"id":"316121","messageId":"alpine.DEB.2.20.1704040048480.4268@virtualbox","threadId":"45241","inReplyTo":"1485481a-f2b3-a0a2-89f6-8f55dc241b19@web.de","subject":"Re: [PATCH v2 4/8] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-03T22:50:43Z","receivedAt":"2017-04-03T22:50:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Torsten,\n\nOn Mon, 3 Apr 2017, Torsten Bögershausen wrote:\n\n> []\n> > --- a/git-compat-util.h\n> > +++ b/git-compat-util.h\n> > @@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n> >  #define PRIo32 \"o\"\n> >  #endif\n> >\n> > +#define parse_timestamp strtoul\n> > +\n> \n> Would\n> #define parse_timestamp(a,b,c)  strtoul((a),(b),(c))\n> be more strict ?\n\nIt would be more pedantic. But I fail to see how it would be more strict:\nonce the preprocessor substituted `parse_timestamp` for whatever we\n#define'd it to, the C compiler will then validate the calls against the\nsignature of the real function. That validation will be much more strict\nthan merely testing for the correct number of parameters.\n\nCiao,\nJohannes"},{"id":"317384","messageId":"35bb906d44605aef36efc1dd505045cd73a8c27e.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:52:09Z","receivedAt":"2017-04-20T20:52:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply change that field to use `uintmax_t` instead.\n\nThis patch is a bit larger than the mere change of the data type\nbecause the field's name was tied to its data type, which has been fixed\nat the same time.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3a640448fd8..92871266001 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -351,7 +351,7 @@ struct ref_formatting_state {\n struct atom_value {\n \tconst char *s;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n \tstruct used_atom *atom;\n };\n \n@@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -875,11 +875,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1941,9 +1941,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317385","messageId":"cover.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1491159939.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:52:05Z","receivedAt":"2017-04-20T20:52:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as we already make use of\n64-bit data types internally. There is no good reason why we should not\nuse the same for timestamps. Hence, let's use uintmax_t for timestamps.\n\nNote: while the `time_t` data type exists and is meant to be used for\ntimestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\nused `time_t` for that reason, but it came with a few serious downsides:\nas `time_t` can be signed (and indeed, on Windows it is an int64_t),\nGit's expectation that 0 is the minimal value does no longer hold true,\nintroducing its own set of interesting challenges. Besides, if we *can*\nhandle far in the future timestamps (except for formatting them using\nthe system libraries), it is more consistent to do so.\n\nThe upside of using `uintmax_t` for timestamps is that we do a much\nbetter job to support far in the future timestamps across all platforms,\nincluding 32-bit ones. The downside is that those platforms that use a\n32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nThis iteration has no new changes, only conflict resolutions necessary\ndue to `master` introducing nearby changes. Maybe this iteration will\nbe noticed enough to make it into `pu`?\n\nChanges since v2:\n\n- resolved merge conflicts while rebasing to the current `master`\n\n- fixed a bug where archive-zip.c's dos_time() was passing an\n  uninitialized time_t to localtime()\n\n\nJohannes Schindelin (8):\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  t0006 & t5000: prepare for 64-bit timestamps\n  t0006 & t5000: skip \"far in the future\" test when time_t is too\n    limited\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Introduce a new data type for timestamps\n  Abort if the system time cannot handle one of our timestamps\n  Use uintmax_t for timestamps\n\n Documentation/technical/api-parse-options.txt |   8 +-\n archive-tar.c                                 |   5 +-\n archive-zip.c                                 |  11 ++-\n archive.h                                     |   2 +-\n builtin/am.c                                  |   4 +-\n builtin/blame.c                               |  14 ++--\n builtin/fsck.c                                |   6 +-\n builtin/gc.c                                  |   2 +-\n builtin/log.c                                 |   4 +-\n builtin/merge-base.c                          |   2 +-\n builtin/name-rev.c                            |   6 +-\n builtin/pack-objects.c                        |   4 +-\n builtin/prune.c                               |   4 +-\n builtin/receive-pack.c                        |  14 ++--\n builtin/reflog.c                              |  24 +++---\n builtin/rev-list.c                            |   2 +-\n builtin/rev-parse.c                           |   2 +-\n builtin/show-branch.c                         |   4 +-\n builtin/worktree.c                            |   4 +-\n bundle.c                                      |   4 +-\n cache.h                                       |  14 ++--\n commit.c                                      |  18 ++--\n commit.h                                      |   2 +-\n config.c                                      |   2 +-\n credential-cache--daemon.c                    |  12 +--\n date.c                                        | 113 ++++++++++++++------------\n fetch-pack.c                                  |   8 +-\n fsck.c                                        |   2 +-\n git-compat-util.h                             |   9 ++\n http-backend.c                                |   4 +-\n parse-options-cb.c                            |   4 +-\n pretty.c                                      |   4 +-\n reachable.c                                   |   9 +-\n reachable.h                                   |   4 +-\n ref-filter.c                                  |  22 ++---\n reflog-walk.c                                 |   8 +-\n refs.c                                        |  14 ++--\n refs.h                                        |   8 +-\n refs/files-backend.c                          |   8 +-\n revision.c                                    |   6 +-\n revision.h                                    |   4 +-\n sha1_name.c                                   |   6 +-\n t/helper/test-date.c                          |  18 ++--\n t/helper/test-parse-options.c                 |   4 +-\n t/t0006-date.sh                               |   4 +-\n t/t5000-tar-tree.sh                           |   6 +-\n t/test-lib.sh                                 |   3 +\n tag.c                                         |   6 +-\n tag.h                                         |   2 +-\n upload-pack.c                                 |   8 +-\n vcs-svn/fast_export.c                         |   8 +-\n vcs-svn/fast_export.h                         |   4 +-\n vcs-svn/svndump.c                             |   2 +-\n wt-status.c                                   |   2 +-\n 54 files changed, 256 insertions(+), 218 deletions(-)\n\n\nbase-commit: 6a2c2f8d34fa1e8f3bb85d159d354810ed63692e\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v3\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v3\n\nInterdiff vs v2:\n\n diff --git a/archive-zip.c b/archive-zip.c\n index 4f715d40450..bb117a74d45 100644\n --- a/archive-zip.c\n +++ b/archive-zip.c\n @@ -548,9 +548,14 @@ static void write_zip_trailer(const unsigned char *sha1)\n  static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n  {\n  \ttime_t time;\n -\tstruct tm *t = localtime(&time);\n +\tstruct tm *t;\n  \n +\tif (date_overflows(*timestamp))\n +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n +\ttime = (time_t)*timestamp;\n +\tt = localtime(&time);\n  \t*timestamp = time;\n +\n  \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n  \t            (t->tm_year + 1900 - 1980) * 512;\n  \t*dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048;\n\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n"},{"id":"317386","messageId":"4061101de2cea4e2b55b6b58bfd4bbd30fe5465e.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 2/8] t0006 & t5000: prepare for 64-bit timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:52:13Z","receivedAt":"2017-04-20T20:52:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply uses an incorrect data type for timestamps, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) papered over this\nissue simply by skipping the respective test cases on platforms where\nthey would fail due to the data type in use.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`,\nconflating the two issues.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, after we\nswitch to a larger data type, we can flip that prerequisite to test\n`time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 13b5696822d..beee1d847ff 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1164,3 +1164,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317387","messageId":"31900a70120b443f90dd52b5fb653f62895b104d.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 3/8] t0006 & t5000: skip \"far in the future\" test when time_t is too limited","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:58:21Z","receivedAt":"2017-04-20T20:58:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned long, which is\nill-defined, as there is no guarantee about the number of bits that\ndata type has.\n\nIn preparation of switching to another data type that is large enough\nto hold \"far in the future\" dates, we need to prepare the t0006-date.sh\nscript for the case where we *still* cannot format those dates if the\nsystem library uses 32-bit time_t.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 2 +-\n t/test-lib.sh        | 1 +\n 4 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..ac7c66c733b 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n \"  test-date approxidate [date]...\\n\"\n-\"  test-date is64bit\\n\";\n+\"  test-date is64bit\\n\"\n+\"  test-date time_t-is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -96,6 +97,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n \t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 9539b425ffb..42d4ea61ef5 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 997aa9dea28..fe2d4f15a73 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex beee1d847ff..8d25cb7c183 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n '\n \n test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n+test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317388","messageId":"403936fa1df1b1c6d8daade2bfe853579b97bad3.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 4/8] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:58:26Z","receivedAt":"2017-04-20T20:58:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using a more appropriate data type, let's\nintroduce a symbol `parse_timestamp` (currently being defined to\n`strtoul`) where appropriate, so that we can later easily switch to,\nsay, use `strtoull()` instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c           | 2 +-\n builtin/receive-pack.c | 4 ++--\n bundle.c               | 2 +-\n commit.c               | 6 +++---\n date.c                 | 6 +++---\n fsck.c                 | 2 +-\n git-compat-util.h      | 2 ++\n pretty.c               | 2 +-\n ref-filter.c           | 2 +-\n refs/files-backend.c   | 2 +-\n t/helper/test-date.c   | 2 +-\n tag.c                  | 4 ++--\n upload-pack.c          | 2 +-\n 13 files changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex f7a7a971fbe..2c93adc69c3 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -882,7 +882,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 3cba3fd278f..9a4c2a7ade4 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n \t}\n-\tstamp = strtoul(nonce, &bohmac, 10);\n+\tstamp = parse_timestamp(nonce, &bohmac, 10);\n \tif (bohmac == nonce || bohmac[0] != '-') {\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n@@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t * would mean it was issued by another server with its clock\n \t * skewed in the future.\n \t */\n-\tostamp = strtoul(push_cert_nonce, NULL, 10);\n+\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n \n \tif (nonce_stamp_slop_limit &&\ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 73c78c2b80c..0d2d0fa1984 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -89,8 +89,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -607,7 +607,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..495c207c64f 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\tunsigned long number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex e6152e4e6d4..d589341cddf 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -691,7 +691,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 8a4a3f85e7b..fc1b5fe1a6c 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex d0f86f5d85c..24fb0c79062 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 92871266001..c7836ae07bd 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -868,7 +868,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4d705b4037e..dae0522673b 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3247,7 +3247,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n \t    !(email_end = strchr(p, '>')) ||\n \t    email_end[1] != ' ' ||\n-\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n+\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n \t    !message || message[0] != ' ' ||\n \t    (message[1] != '+' && message[1] != '-') ||\n \t    !isdigit(message[2]) || !isdigit(message[3]) ||\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ac7c66c733b..52d1fc34454 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -34,7 +34,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..9b6725e02c9 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -110,8 +110,8 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ffb028d6231..f17f4dd1233 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317389","messageId":"e0a6dccfceac7f414f885ece81049c8d337be33d.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 5/8] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:58:31Z","receivedAt":"2017-04-20T20:58:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\naway from the ill-specified `unsigned long` data type.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\ndefined to \"lu\") to make it easier to change the data type used for\ntimestamps.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n builtin/rev-list.c            |  2 +-\n builtin/rev-parse.c           |  2 +-\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n refs/files-backend.c          |  2 +-\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 14 files changed, 30 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 07506a3e457..e4b3c7b0ebf 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1844,7 +1844,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex f76e4163abb..af7b985c6eb 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b3b10cc1edb..f93ef6c7100 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -910,7 +910,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 9a4c2a7ade4..c49333c9b66 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -459,12 +459,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex bcf77f0b8a2..3b292c99bda 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n \t}\n \n \tif (info->show_timestamp)\n-\t\tprintf(\"%lu \", commit->date);\n+\t\tprintf(\"%\"PRItime\" \", commit->date);\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 05133309106..b4509002435 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -218,7 +218,7 @@ static void show_datestring(const char *flag, const char *datestr)\n \t/* date handling requires both flags and revs */\n \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n \t\treturn;\n-\tbuffer = xstrfmt(\"%s%lu\", flag, approxidate(datestr));\n+\tbuffer = xstrfmt(\"%s%\"PRItime, flag, approxidate(datestr));\n \tshow(buffer);\n \tfree(buffer);\n }\ndiff --git a/date.c b/date.c\nindex 495c207c64f..5c33dfd8ee7 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 42969353d67..a1b8ea59e8d 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -393,7 +393,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex fc1b5fe1a6c..cd522903eda 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex dae0522673b..ecbb13dc4b8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4131,7 +4131,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n \t\t\tprintf(\"prune %s\", message);\n \t} else {\n \t\tif (cb->newlog) {\n-\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n+\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n \t\t\t\temail, timestamp, tz, message);\n \t\t\toidcpy(&cb->last_kept_oid, noid);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 52d1fc34454..269040f028f 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -53,7 +53,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex f17f4dd1233..4966f0b8a09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -863,7 +863,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317390","messageId":"57a98dbbf20a944a455aa6092a4be601817fdb0c.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 6/8] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:58:53Z","receivedAt":"2017-04-20T20:59:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. Which is incorrect, and causes a lot of problems, in particular\nwhere unsigned long is only 32-bit (notably on Windows, even in 64-bit\nversions).\n\nSo let's just use a more appropriate data type instead. In preparation\nfor this, we introduce the new `timestamp_t` data type.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs we will use a data type that is not necessarily identical to `time_t`,\nwe need to be very careful to use `time_t` whenever we interact with the\nsystem functions, and `timestamp_t` everywhere else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++--\n archive-tar.c                                 |  5 +-\n archive-zip.c                                 | 11 ++++-\n archive.h                                     |  2 +-\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++--\n builtin/fsck.c                                |  4 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +--\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        |  6 +--\n builtin/reflog.c                              | 24 +++++-----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 +++---\n commit.c                                      | 12 ++---\n commit.h                                      |  2 +-\n config.c                                      |  2 +-\n credential-cache--daemon.c                    | 12 ++---\n date.c                                        | 66 +++++++++++++--------------\n fetch-pack.c                                  |  6 +--\n git-compat-util.h                             |  2 +\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  2 +-\n reachable.c                                   |  9 ++--\n reachable.h                                   |  4 +-\n ref-filter.c                                  |  4 +-\n reflog-walk.c                                 |  8 ++--\n refs.c                                        | 14 +++---\n refs.h                                        |  8 ++--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +--\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +--\n t/helper/test-date.c                          |  8 ++--\n t/helper/test-parse-options.c                 |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +-\n vcs-svn/fast_export.c                         |  4 +-\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 48 files changed, 167 insertions(+), 156 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 36768b479e1..829b5581105 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,13 +183,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..695339a2369 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n #define USTAR_MAX_SIZE 077777777777UL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/archive-zip.c b/archive-zip.c\nindex b429a8d974a..bb117a74d45 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -545,9 +545,16 @@ static void write_zip_trailer(const unsigned char *sha1)\n \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n }\n \n-static void dos_time(time_t *time, int *dos_date, int *dos_time)\n+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n {\n-\tstruct tm *t = localtime(time);\n+\ttime_t time;\n+\tstruct tm *t;\n+\n+\tif (date_overflows(*timestamp))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\ttime = (time_t)*timestamp;\n+\tt = localtime(&time);\n+\t*timestamp = time;\n \n \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n \t            (t->tm_year + 1900 - 1980) * 512;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e2c..62d1d82c1af 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -9,7 +9,7 @@ struct archiver_args {\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n-\ttime_t time;\n+\ttimestamp_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 2c93adc69c3..89914ed8757 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -877,7 +877,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e4b3c7b0ebf..f00eda16378 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttimestamp_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttimestamp_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1578,7 +1578,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttimestamp_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(timestamp_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex af7b985c6eb..ea3a9f8a70a 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n }\n \n static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 2daede78205..cb1e20aae4a 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -33,7 +33,7 @@ static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 50;\n static int detach_auto = 1;\n-static unsigned long gc_log_expire_time;\n+static timestamp_t gc_log_expire_time;\n static const char *gc_log_expire = \"1.day.ago\";\n static const char *prune_expire = \"2.weeks.ago\";\n static const char *prune_worktrees_expire = \"3.months.ago\";\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f93ef6c7100..fd3d10ec217 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -911,7 +911,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (timestamp_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex cfe2a796f85..8ed96391c1d 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 92a5d8a5d26..44374750170 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttimestamp_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, timestamp_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\ttimestamp_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 0fe35d1b5ae..9b4ba8a80d7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static timestamp_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct oid_array recent_objects;\n \n static int loosened_object_can_be_discarded(const struct object_id *oid,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    timestamp_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 42633e0c6e6..8dcfecde0f3 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex c49333c9b66..b4e22f44497 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static timestamp_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttimestamp_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 74727757785..4228d9ff4db 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static timestamp_t default_reflog_expire;\n+static timestamp_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttimestamp_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttimestamp_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 19756595d57..8860f429b06 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttimestamp_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9993ded41aa..74f9b18d40c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..05e014fc5ab 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex ba27595d54d..f3a02993b20 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1476,18 +1476,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, timestamp_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+timestamp_t approxidate_careful(const char *, int *);\n+timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(timestamp_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 0d2d0fa1984..99a62b90ee2 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static timestamp_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n+\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 7b1986d5c8a..c9d887b5e53 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.c b/config.c\nindex 1a4d85537b3..3247bfaa020 100644\n--- a/config.c\n+++ b/config.c\n@@ -1926,7 +1926,7 @@ int git_config_get_expiry(const char *key, const char **output)\n \tif (ret)\n \t\treturn ret;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttimestamp_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..f3814cc47a0 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttimestamp_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static timestamp_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic timestamp_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\ttimestamp_t now = time(NULL);\n+\ttimestamp_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttimestamp_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 5c33dfd8ee7..92ab31aa441 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(timestamp_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttimestamp_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttimestamp_t years = totalmonths / 12;\n+\t\ttimestamp_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(timestamp_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttimestamp_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttimestamp_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttimestamp_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, timestamp_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = parse_timestamp(date, &end, 10);\n+\ttimestamp_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\n@@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n-\t\t\t\t     const struct timeval *tv,\n-\t\t\t\t     int *error_ret)\n+static timestamp_t approxidate_str(const char *date,\n+\t\t\t\t   const struct timeval *tv,\n+\t\t\t\t   int *error_ret)\n {\n \tint number = 0;\n \tint touched = 0;\n@@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,\n \tpending_number(&tm, &number);\n \tif (!touched)\n \t\t*error_ret = 1;\n-\treturn update_tm(&tm, &now, 0);\n+\treturn (timestamp_t)update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+timestamp_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(timestamp_t t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a1b8ea59e8d..fbe52f02346 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -392,7 +392,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -581,7 +581,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t timestamp_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -668,7 +668,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttimestamp_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex cd522903eda..72c12173a14 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+typedef unsigned long timestamp_t;\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..d6ea6075339 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 7419780a9b6..a6810f295cb 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(timestamp_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 24fb0c79062..587d48371b0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttimestamp_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4fc..682418f5d23 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n };\n \n static void add_recent_object(const struct object_id *oid,\n-\t\t\t      unsigned long mtime,\n+\t\t\t      timestamp_t mtime,\n \t\t\t      struct recent_data *data)\n {\n \tstruct object *obj;\n@@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    timestamp_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..3c00fa0526c 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  timestamp_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   timestamp_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c7836ae07bd..1fc5e9970db 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\n@@ -869,7 +869,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 99679f58255..3ca5ed8415a 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tstruct object_id ooid, noid;\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttimestamp_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttimestamp_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex d1e1b4399b3..6841bd9f712 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -712,7 +712,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttimestamp_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -721,15 +721,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttimestamp_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -776,7 +776,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n }\n \n static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -796,9 +796,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 49e97d7d5fd..2b80d37fd34 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -317,9 +317,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttimestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int refs_reflog_exists(struct ref_store *refs, const char *refname);\n@@ -356,7 +356,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tstruct object_id *old_oid, struct object_id *new_oid,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, timestamp_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n@@ -616,7 +616,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  timestamp_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ecbb13dc4b8..6646dcfc838 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3237,7 +3237,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tstruct object_id ooid, noid;\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint tz;\n \tconst char *p = sb->buf;\n \n@@ -4114,7 +4114,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, timestamp_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f73..8a8c1789c7b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttimestamp_t date = TIME_MAX;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n }\n \n static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(ooid, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 14886ec92b4..0d9e68b36e9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttimestamp_t max_age;\n+\ttimestamp_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 8eec9f7c1bb..35c1e2a9e32 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -660,8 +660,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttimestamp_t at_time;\n+\t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1054,7 +1054,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 269040f028f..f414a3ac670 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -27,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n \tparse_date_format(format, &mode);\n \tfor (; *argv; argv++) {\n \t\tchar *arg;\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\t/*\n@@ -48,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -65,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n static void parse_approxidate(const char **argv, struct timeval *now)\n {\n \tfor (; *argv; argv++) {\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tt = approxidate_relative(*argv, now);\n \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n \t}\n@@ -96,7 +96,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n \telse if (!strcmp(*argv, \"time_t-is64bit\"))\n \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..75fe883aac1 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static timestamp_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/tag.c b/tag.c\nindex 9b6725e02c9..d71b67e8d83 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..2abb3726fb5 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttimestamp_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4966f0b8a09..97da13e6a54 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static timestamp_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttimestamp_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5a89db30e3f 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttimestamp_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..b9a3b71c99f 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttimestamp_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..1846685a21a 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 03754849626..1b1d644b85f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1387,7 +1387,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, timestamp_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317391","messageId":"b80136aa71dca8d6e6e977e0aa8b28228529ec7a.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 8/8] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:59:01Z","receivedAt":"2017-04-20T20:59:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we used `unsigned long` for timestamps. This was only a good\nchoice on Linux, where we know implicitly that `unsigned long` is what is\nused for `time_t`.\n\nHowever, we want to use a different data type for timestamps for two\nreasons:\n\n- there is nothing that says that `unsigned long` should be the same data\n  type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n  `unsigned long` is 32-bit but `time_t` is 64-bit.\n\n- even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n  32-bit, we *want* to be able to encode timestamps in Git that are\n  currently absurdly far in the future, *even if* the system library is\n  not able to format those timestamps into date strings.\n\nSo let's just switch to the maximal integer type available, which should\nbe at least 64-bit for all practical purposes these days. It certainly\ncannot be worse than `unsigned long`, so...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-compat-util.h | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 72c12173a14..c678ca94b8f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,10 +319,14 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n-typedef unsigned long timestamp_t;\n-#define PRItime \"lu\"\n-#define parse_timestamp strtoul\n+typedef uintmax_t timestamp_t;\n+#define PRItime PRIuMAX\n+#define parse_timestamp strtoumax\n+#ifdef ULLONG_MAX\n+#define TIME_MAX ULLONG_MAX\n+#else\n #define TIME_MAX ULONG_MAX\n+#endif\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n"},{"id":"317392","messageId":"31e6035de94c95660003575edffe8a96714ef519.1492721487.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v3 7/8] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-20T20:58:57Z","receivedAt":"2017-04-20T20:59:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We are about to switch to a new data type for time stamps that is\ndefinitely not smaller or equal, but larger or equal to time_t.\n\nSo before using the system functions to process or format timestamps,\nlet's make extra certain that they can handle what we feed them.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n date.c | 17 ++++++++++++++---\n 1 file changed, 14 insertions(+), 3 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 92ab31aa441..db3435df3e4 100644\n--- a/date.c\n+++ b/date.c\n@@ -43,10 +43,13 @@ static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n \tminutes = tz < 0 ? -tz : tz;\n \tminutes = (minutes / 100)*60 + (minutes % 100);\n \tminutes = tz < 0 ? -minutes : minutes;\n-\treturn time + minutes * 60;\n+\treturn (time_t)time + minutes * 60;\n }\n \n /*\n@@ -56,7 +59,12 @@ static time_t gm_time_t(timestamp_t time, int tz)\n  */\n static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n-\ttime_t t = gm_time_t(time, tz);\n+\ttime_t t;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = gm_time_t((time_t)time, tz);\n \treturn gmtime(&t);\n }\n \n@@ -70,7 +78,10 @@ static int local_tzoffset(timestamp_t time)\n \tstruct tm tm;\n \tint offset, eastwest;\n \n-\tt = time;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = (time_t)time;\n \tlocaltime_r(&t, &tm);\n \tt_local = tm_to_time_t(&tm);\n \n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317459","messageId":"xmqqpog647of.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v3 0/8] Introduce timestamp_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-21T06:05:20Z","receivedAt":"2017-04-21T06:05:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Note: while the `time_t` data type exists and is meant to be used for\n> timestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\n> used `time_t` for that reason, but it came with a few serious downsides:\n> as `time_t` can be signed (and indeed, on Windows it is an int64_t),\n> Git's expectation that 0 is the minimal value does no longer hold true,\n> introducing its own set of interesting challenges. Besides, if we *can*\n> handle far in the future timestamps (except for formatting them using\n> the system libraries), it is more consistent to do so.\n\nI somehow had an impression that the list consensus during the\ndiscussion on an earlier round of this series was that time_t is\nmore appropriate, as platforms with time_t with inadequent range\nwill be updated before it gets too late at around 2038 (or they will\ndie off).  After all, at some point we need to interact with the\nplatform functions that expect time_t as their interface and they do\nnot take our own timestamp_t without casting.\n\nBut that is provided if not introducing timestamp_t and using time_t\nresults in a simpler code.  I do not know if that is the case.\n\nFor timestamps in the distant past, even though time_t could be\nunsigned, I do not think anybody came up with a concrete example of\na platform with such a problem during the previous discussions,\nwhile I do recall people wanting to use Git to store historical\ndocuments with timestamps before 1970.  We do expect 0 can be used\nas a sentinel, which needs to be updated once we seriously start\nsupporting such use cases.  I think that (i.e. should the timestamp\nbe signed?) is more or less unrelated to the focus of the discussion\nthat stemed from this topic, which was \"ulong that is often 32-bit\ndoes not necessarily fit the notion of time on a platform, which is\ntime_t, and we need to widen it\", which all involved in the discussion\nagreed.\n\nIn any case, when merged to 'pu', this had a slight conflict with\ntopics in flight in builtin/name-rev.c and I think I resolved it\ncorrectly, but please double check.  I will have to revamp the\nresolution rerere remembered when the next version of this series\nstarts using time_t instead of timestamp_t anyway, but it is better\nto always get conflict resolution right.  That is what maintainers\ndo and what they are for ;-)\n\nThanks.\n\n"},{"id":"317471","messageId":"alpine.DEB.2.20.1704211219460.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqpog647of.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v3 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:44:40Z","receivedAt":"2017-04-21T10:44:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 20 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Note: while the `time_t` data type exists and is meant to be used for\n> > timestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\n> > used `time_t` for that reason, but it came with a few serious\n> > downsides: as `time_t` can be signed (and indeed, on Windows it is an\n> > int64_t), Git's expectation that 0 is the minimal value does no longer\n> > hold true, introducing its own set of interesting challenges. Besides,\n> > if we *can* handle far in the future timestamps (except for formatting\n> > them using the system libraries), it is more consistent to do so.\n> \n> I somehow had an impression that the list consensus during the\n> discussion on an earlier round of this series was that time_t is\n> more appropriate, as platforms with time_t with inadequent range\n> will be updated before it gets too late at around 2038 (or they will\n> die off).\n\nThere was this sentiment, but that would require a change in Git's source\ncode where it can handle unsigned *and* signed data types for timestamps,\nand that was too much of a change to bring in that late in the patch\nseries.\n\nBesides, supporting a signed timestamp data type is a separate issue from\ntrying to support dates that are insanely far in the future.\n\n> After all, at some point we need to interact with the\n> platform functions that expect time_t as their interface and they do\n> not take our own timestamp_t without casting.\n\nNo, not necessarily. When we generate a .zip archive, for example, we may\nnever need to parse or format the timestamps. When we log with a format\nthat does not require the system routines to format the date (e.g. Unix\nepoch). And when we do not parse nor format the timestamps to begin with,\ne.g. fetching and pushing or committing.\n\nIt is *only* when we try to parse or format timestamps, *and* the system's\ntime_t is not large enough, that we run into trouble.\n\nThis is an improvement from before, where we would run into trouble\nwhenever time_t was larger than unsigned long, *or* whenever time_t is too\nsmall for those timestamps.\n\nYour comment, and my reaction, reminded me that I had planned to look into\nall calls to date_overflow() and remove those that are now unnecessary, or\nat least move them to the place where they are absolutely necessary.\n\n> But that is provided if not introducing timestamp_t and using time_t\n> results in a simpler code.  I do not know if that is the case.\n\nAs I had pointed out in my reply to Peff: removing the assumption that 0\nis the minimal timestamp is something I am unwilling to tackle, it looks\nway too fragile/dangerous to me to do this in the time I could allocate\nfor that.\n\n> For timestamps in the distant past, even though time_t could be\n> unsigned, I do not think anybody came up with a concrete example of a\n> platform with such a problem during the previous discussions, while I do\n> recall people wanting to use Git to store historical documents with\n> timestamps before 1970.  We do expect 0 can be used as a sentinel, which\n> needs to be updated once we seriously start supporting such use cases.\n> I think that (i.e. should the timestamp be signed?) is more or less\n> unrelated to the focus of the discussion that stemed from this topic,\n> which was \"ulong that is often 32-bit does not necessarily fit the\n> notion of time on a platform, which is time_t, and we need to widen it\",\n> which all involved in the discussion agreed.\n\nIf anybody feels strongly enough about representing timestamps earlier\nthan the Jan 1 1970, they should feel very welcome to work on this.\n\nMy patch series would make that task slightly easier, even.\n\n> In any case, when merged to 'pu', this had a slight conflict with\n> topics in flight in builtin/name-rev.c and I think I resolved it\n> correctly, but please double check.\n\nI double-checked, there were just two conversions from `unsigned long\ntaggerdate` to `timestamp_t taggerdate`. I repeated the merge with my\nlatest iteration and resolved them the same way as you did.\n\nApart from the date_overflows() changes I mentioned above, I also fixed\nthe problems identified by Travis CI and VSTS Build.\n\nv4 is coming,\nDscho\n"},{"id":"317472","messageId":"cover.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492721487.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:00Z","receivedAt":"2017-04-21T10:45:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as we already make use of\n64-bit data types internally. There is no good reason why we should not\nuse the same for timestamps. Hence, let's use uintmax_t for timestamps.\n\nNote: while the `time_t` data type exists and is meant to be used for\ntimestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\nused `time_t` for that reason, but it came with a few serious downsides:\nas `time_t` can be signed (and indeed, on Windows it is an int64_t),\nGit's expectation that 0 is the minimal value does no longer hold true,\nintroducing its own set of interesting challenges. Besides, if we *can*\nhandle far in the future timestamps (except for formatting them using\nthe system libraries), it is more consistent to do so.\n\nThe upside of using `uintmax_t` for timestamps is that we do a much\nbetter job to support far in the future timestamps across all platforms,\nincluding 32-bit ones. The downside is that those platforms that use a\n32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nThis iteration has two fixes for issues reported by Travis CI (thank\ndeity for Continuous Testing, eh?), one by the MacOSX nodes (but not by\nthe Linux nor the Windows nodes), the other by the windows node (which\nreminds me to run tests after rebasing to `master` not only in a Linux\nVM but also on Windows, even if it takes ages there due to the heavy\nshell scripting).\n\nAfter reading Junio's comments on the cover letter of v2, I had another\nlook at the usage of date_overflows() and was able to relax two of them.\n\nChanges since v3:\n\n- fixed the fix in archive-zip.c that tried to report a too large\n  timestamp (and would have reported the uninitialized time_t instead)\n\n- adjusted the so-far forgotten each_reflog() function (that was\n  introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n  test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n  too\n\n- removed the date_overflows() check from time_to_tm(), as it calls\n  gm_time_t() which already performs that check\n\n- the date_overflows() check in show_ident_date() was removed, as we do\n  not know at that point yet whether we use the system functions to\n  render the date or not (and there would not be a problem in the latter\n  case)\n\n\nJohannes Schindelin (9):\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  t0006 & t5000: prepare for 64-bit timestamps\n  t0006 & t5000: skip \"far in the future\" test when time_t is too\n    limited\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Introduce a new data type for timestamps\n  Abort if the system time cannot handle one of our timestamps\n  Use uintmax_t for timestamps\n  show_date_ident(): defer date overflow check\n\n Documentation/technical/api-parse-options.txt |   8 +-\n archive-tar.c                                 |   5 +-\n archive-zip.c                                 |  12 ++-\n archive.h                                     |   2 +-\n builtin/am.c                                  |   4 +-\n builtin/blame.c                               |  14 ++--\n builtin/fsck.c                                |   6 +-\n builtin/gc.c                                  |   2 +-\n builtin/log.c                                 |   4 +-\n builtin/merge-base.c                          |   2 +-\n builtin/name-rev.c                            |   6 +-\n builtin/pack-objects.c                        |   4 +-\n builtin/prune.c                               |   4 +-\n builtin/receive-pack.c                        |  14 ++--\n builtin/reflog.c                              |  24 +++---\n builtin/rev-list.c                            |   2 +-\n builtin/rev-parse.c                           |   2 +-\n builtin/show-branch.c                         |   4 +-\n builtin/worktree.c                            |   4 +-\n bundle.c                                      |   4 +-\n cache.h                                       |  14 ++--\n commit.c                                      |  18 ++---\n commit.h                                      |   2 +-\n config.c                                      |   2 +-\n credential-cache--daemon.c                    |  12 +--\n date.c                                        | 106 ++++++++++++++------------\n fetch-pack.c                                  |   8 +-\n fsck.c                                        |   2 +-\n git-compat-util.h                             |   9 +++\n http-backend.c                                |   4 +-\n parse-options-cb.c                            |   4 +-\n pretty.c                                      |  16 ++--\n reachable.c                                   |   9 +--\n reachable.h                                   |   4 +-\n ref-filter.c                                  |  22 +++---\n reflog-walk.c                                 |   8 +-\n refs.c                                        |  14 ++--\n refs.h                                        |   8 +-\n refs/files-backend.c                          |   8 +-\n revision.c                                    |   6 +-\n revision.h                                    |   4 +-\n sha1_name.c                                   |   6 +-\n t/helper/test-date.c                          |  18 +++--\n t/helper/test-parse-options.c                 |   4 +-\n t/helper/test-ref-store.c                     |   4 +-\n t/t0006-date.sh                               |   4 +-\n t/t5000-tar-tree.sh                           |   6 +-\n t/test-lib.sh                                 |   3 +\n tag.c                                         |   6 +-\n tag.h                                         |   2 +-\n upload-pack.c                                 |   8 +-\n vcs-svn/fast_export.c                         |   8 +-\n vcs-svn/fast_export.h                         |   4 +-\n vcs-svn/svndump.c                             |   2 +-\n wt-status.c                                   |   2 +-\n 55 files changed, 257 insertions(+), 227 deletions(-)\n\n\nbase-commit: 6a2c2f8d34fa1e8f3bb85d159d354810ed63692e\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v4\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v4\n\nInterdiff vs v3:\n\n diff --git a/archive-zip.c b/archive-zip.c\n index bb117a74d45..68df3d64402 100644\n --- a/archive-zip.c\n +++ b/archive-zip.c\n @@ -551,7 +551,8 @@ static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n  \tstruct tm *t;\n  \n  \tif (date_overflows(*timestamp))\n -\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n +\t\tdie(\"timestamp too large for this system: %\"PRItime,\n +\t\t    *timestamp);\n  \ttime = (time_t)*timestamp;\n  \tt = localtime(&time);\n  \t*timestamp = time;\n diff --git a/date.c b/date.c\n index db3435df3e4..75f6335cd09 100644\n --- a/date.c\n +++ b/date.c\n @@ -43,12 +43,12 @@ static time_t gm_time_t(timestamp_t time, int tz)\n  {\n  \tint minutes;\n  \n -\tif (date_overflows(time))\n -\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n -\n  \tminutes = tz < 0 ? -tz : tz;\n  \tminutes = (minutes / 100)*60 + (minutes % 100);\n  \tminutes = tz < 0 ? -minutes : minutes;\n +\n +\tif (date_overflows(time + minutes * 60))\n +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n  \treturn (time_t)time + minutes * 60;\n  }\n  \n @@ -59,12 +59,7 @@ static time_t gm_time_t(timestamp_t time, int tz)\n   */\n  static struct tm *time_to_tm(timestamp_t time, int tz)\n  {\n -\ttime_t t;\n -\n -\tif (date_overflows(time))\n -\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n -\n -\tt = gm_time_t((time_t)time, tz);\n +\ttime_t t = gm_time_t(time, tz);\n  \treturn gmtime(&t);\n  }\n  \n diff --git a/pretty.c b/pretty.c\n index 587d48371b0..35fd290096a 100644\n --- a/pretty.c\n +++ b/pretty.c\n @@ -410,14 +410,10 @@ const char *show_ident_date(const struct ident_split *ident,\n  \n  \tif (ident->date_begin && ident->date_end)\n  \t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n -\tif (date_overflows(date))\n -\t\tdate = 0;\n -\telse {\n -\t\tif (ident->tz_begin && ident->tz_end)\n -\t\t\ttz = strtol(ident->tz_begin, NULL, 10);\n -\t\tif (tz >= INT_MAX || tz <= INT_MIN)\n -\t\t\ttz = 0;\n -\t}\n +\tif (ident->tz_begin && ident->tz_end)\n +\t\ttz = strtol(ident->tz_begin, NULL, 10);\n +\tif (tz >= INT_MAX || tz <= INT_MIN)\n +\t\ttz = 0;\n  \treturn show_date(date, tz, mode);\n  }\n  \n diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\n index 2d84c45ffe9..9077ec2c330 100644\n --- a/t/helper/test-ref-store.c\n +++ b/t/helper/test-ref-store.c\n @@ -138,10 +138,10 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)\n  }\n  \n  static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n -\t\t       const char *committer, unsigned long timestamp,\n +\t\t       const char *committer, timestamp_t timestamp,\n  \t\t       int tz, const char *msg, void *cb_data)\n  {\n -\tprintf(\"%s %s %s %lu %d %s\\n\",\n +\tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\n  \t       oid_to_hex(old_oid), oid_to_hex(new_oid),\n  \t       committer, timestamp, tz, msg);\n  \treturn 0;\n\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n"},{"id":"317473","messageId":"35bb906d44605aef36efc1dd505045cd73a8c27e.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 1/9] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:04Z","receivedAt":"2017-04-21T10:45:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply change that field to use `uintmax_t` instead.\n\nThis patch is a bit larger than the mere change of the data type\nbecause the field's name was tied to its data type, which has been fixed\nat the same time.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3a640448fd8..92871266001 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -351,7 +351,7 @@ struct ref_formatting_state {\n struct atom_value {\n \tconst char *s;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n \tstruct used_atom *atom;\n };\n \n@@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -875,11 +875,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1941,9 +1941,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317474","messageId":"4061101de2cea4e2b55b6b58bfd4bbd30fe5465e.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 2/9] t0006 & t5000: prepare for 64-bit timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:36Z","receivedAt":"2017-04-21T10:45:47Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply uses an incorrect data type for timestamps, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) papered over this\nissue simply by skipping the respective test cases on platforms where\nthey would fail due to the data type in use.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`,\nconflating the two issues.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, after we\nswitch to a larger data type, we can flip that prerequisite to test\n`time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 13b5696822d..beee1d847ff 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1164,3 +1164,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317475","messageId":"31900a70120b443f90dd52b5fb653f62895b104d.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 3/9] t0006 & t5000: skip \"far in the future\" test when time_t is too limited","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:41Z","receivedAt":"2017-04-21T10:45:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned long, which is\nill-defined, as there is no guarantee about the number of bits that\ndata type has.\n\nIn preparation of switching to another data type that is large enough\nto hold \"far in the future\" dates, we need to prepare the t0006-date.sh\nscript for the case where we *still* cannot format those dates if the\nsystem library uses 32-bit time_t.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 2 +-\n t/test-lib.sh        | 1 +\n 4 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..ac7c66c733b 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n \"  test-date approxidate [date]...\\n\"\n-\"  test-date is64bit\\n\";\n+\"  test-date is64bit\\n\"\n+\"  test-date time_t-is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -96,6 +97,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n \t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 9539b425ffb..42d4ea61ef5 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 997aa9dea28..fe2d4f15a73 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex beee1d847ff..8d25cb7c183 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n '\n \n test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n+test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317476","messageId":"403936fa1df1b1c6d8daade2bfe853579b97bad3.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 4/9] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:44Z","receivedAt":"2017-04-21T10:45:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using a more appropriate data type, let's\nintroduce a symbol `parse_timestamp` (currently being defined to\n`strtoul`) where appropriate, so that we can later easily switch to,\nsay, use `strtoull()` instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c           | 2 +-\n builtin/receive-pack.c | 4 ++--\n bundle.c               | 2 +-\n commit.c               | 6 +++---\n date.c                 | 6 +++---\n fsck.c                 | 2 +-\n git-compat-util.h      | 2 ++\n pretty.c               | 2 +-\n ref-filter.c           | 2 +-\n refs/files-backend.c   | 2 +-\n t/helper/test-date.c   | 2 +-\n tag.c                  | 4 ++--\n upload-pack.c          | 2 +-\n 13 files changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex f7a7a971fbe..2c93adc69c3 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -882,7 +882,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 3cba3fd278f..9a4c2a7ade4 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n \t}\n-\tstamp = strtoul(nonce, &bohmac, 10);\n+\tstamp = parse_timestamp(nonce, &bohmac, 10);\n \tif (bohmac == nonce || bohmac[0] != '-') {\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n@@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t * would mean it was issued by another server with its clock\n \t * skewed in the future.\n \t */\n-\tostamp = strtoul(push_cert_nonce, NULL, 10);\n+\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n \n \tif (nonce_stamp_slop_limit &&\ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 73c78c2b80c..0d2d0fa1984 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -89,8 +89,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -607,7 +607,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..495c207c64f 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\tunsigned long number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex e6152e4e6d4..d589341cddf 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -691,7 +691,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 8a4a3f85e7b..fc1b5fe1a6c 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex d0f86f5d85c..24fb0c79062 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 92871266001..c7836ae07bd 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -868,7 +868,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4d705b4037e..dae0522673b 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3247,7 +3247,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n \t    !(email_end = strchr(p, '>')) ||\n \t    email_end[1] != ' ' ||\n-\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n+\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n \t    !message || message[0] != ' ' ||\n \t    (message[1] != '+' && message[1] != '-') ||\n \t    !isdigit(message[2]) || !isdigit(message[3]) ||\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ac7c66c733b..52d1fc34454 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -34,7 +34,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..9b6725e02c9 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -110,8 +110,8 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ffb028d6231..f17f4dd1233 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317477","messageId":"7d066c59c8983d822c095f342b6a12297b26a70a.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 5/9] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:48Z","receivedAt":"2017-04-21T10:45:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\naway from the ill-specified `unsigned long` data type.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\ndefined to \"lu\") to make it easier to change the data type used for\ntimestamps.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n builtin/rev-list.c            |  2 +-\n builtin/rev-parse.c           |  2 +-\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n refs/files-backend.c          |  2 +-\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n t/helper/test-ref-store.c     |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 15 files changed, 31 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 07506a3e457..e4b3c7b0ebf 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1844,7 +1844,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex f76e4163abb..af7b985c6eb 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b3b10cc1edb..f93ef6c7100 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -910,7 +910,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex 9a4c2a7ade4..c49333c9b66 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -459,12 +459,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex bcf77f0b8a2..3b292c99bda 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n \t}\n \n \tif (info->show_timestamp)\n-\t\tprintf(\"%lu \", commit->date);\n+\t\tprintf(\"%\"PRItime\" \", commit->date);\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 05133309106..b4509002435 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -218,7 +218,7 @@ static void show_datestring(const char *flag, const char *datestr)\n \t/* date handling requires both flags and revs */\n \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n \t\treturn;\n-\tbuffer = xstrfmt(\"%s%lu\", flag, approxidate(datestr));\n+\tbuffer = xstrfmt(\"%s%\"PRItime, flag, approxidate(datestr));\n \tshow(buffer);\n \tfree(buffer);\n }\ndiff --git a/date.c b/date.c\nindex 495c207c64f..5c33dfd8ee7 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 42969353d67..a1b8ea59e8d 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -393,7 +393,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex fc1b5fe1a6c..cd522903eda 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex dae0522673b..ecbb13dc4b8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4131,7 +4131,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n \t\t\tprintf(\"prune %s\", message);\n \t} else {\n \t\tif (cb->newlog) {\n-\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n+\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n \t\t\t\temail, timestamp, tz, message);\n \t\t\toidcpy(&cb->last_kept_oid, noid);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 52d1fc34454..269040f028f 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -53,7 +53,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 2d84c45ffe9..a436bfdb053 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -141,7 +141,7 @@ static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n \t\t       const char *committer, unsigned long timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n-\tprintf(\"%s %s %s %lu %d %s\\n\",\n+\tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\n \t       oid_to_hex(old_oid), oid_to_hex(new_oid),\n \t       committer, timestamp, tz, msg);\n \treturn 0;\ndiff --git a/upload-pack.c b/upload-pack.c\nindex f17f4dd1233..4966f0b8a09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -863,7 +863,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317478","messageId":"e4650b9bea37ddce5b044cd80ffa319ffa2acd1b.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 6/9] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:50Z","receivedAt":"2017-04-21T10:46:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. Which is incorrect, and causes a lot of problems, in particular\nwhere unsigned long is only 32-bit (notably on Windows, even in 64-bit\nversions).\n\nSo let's just use a more appropriate data type instead. In preparation\nfor this, we introduce the new `timestamp_t` data type.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs we will use a data type that is not necessarily identical to `time_t`,\nwe need to be very careful to use `time_t` whenever we interact with the\nsystem functions, and `timestamp_t` everywhere else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++--\n archive-tar.c                                 |  5 +-\n archive-zip.c                                 | 12 ++++-\n archive.h                                     |  2 +-\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++--\n builtin/fsck.c                                |  4 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +--\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        |  6 +--\n builtin/reflog.c                              | 24 +++++-----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 +++---\n commit.c                                      | 12 ++---\n commit.h                                      |  2 +-\n config.c                                      |  2 +-\n credential-cache--daemon.c                    | 12 ++---\n date.c                                        | 66 +++++++++++++--------------\n fetch-pack.c                                  |  6 +--\n git-compat-util.h                             |  2 +\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  2 +-\n reachable.c                                   |  9 ++--\n reachable.h                                   |  4 +-\n ref-filter.c                                  |  4 +-\n reflog-walk.c                                 |  8 ++--\n refs.c                                        | 14 +++---\n refs.h                                        |  8 ++--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +--\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +--\n t/helper/test-date.c                          |  8 ++--\n t/helper/test-parse-options.c                 |  2 +-\n t/helper/test-ref-store.c                     |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +-\n vcs-svn/fast_export.c                         |  4 +-\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 49 files changed, 169 insertions(+), 157 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 36768b479e1..829b5581105 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,13 +183,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..695339a2369 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n #define USTAR_MAX_SIZE 077777777777UL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/archive-zip.c b/archive-zip.c\nindex b429a8d974a..68df3d64402 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -545,9 +545,17 @@ static void write_zip_trailer(const unsigned char *sha1)\n \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n }\n \n-static void dos_time(time_t *time, int *dos_date, int *dos_time)\n+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n {\n-\tstruct tm *t = localtime(time);\n+\ttime_t time;\n+\tstruct tm *t;\n+\n+\tif (date_overflows(*timestamp))\n+\t\tdie(\"timestamp too large for this system: %\"PRItime,\n+\t\t    *timestamp);\n+\ttime = (time_t)*timestamp;\n+\tt = localtime(&time);\n+\t*timestamp = time;\n \n \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n \t            (t->tm_year + 1900 - 1980) * 512;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e2c..62d1d82c1af 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -9,7 +9,7 @@ struct archiver_args {\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n-\ttime_t time;\n+\ttimestamp_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 2c93adc69c3..89914ed8757 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -877,7 +877,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e4b3c7b0ebf..f00eda16378 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttimestamp_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttimestamp_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1578,7 +1578,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttimestamp_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(timestamp_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex af7b985c6eb..ea3a9f8a70a 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n }\n \n static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 2daede78205..cb1e20aae4a 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -33,7 +33,7 @@ static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 50;\n static int detach_auto = 1;\n-static unsigned long gc_log_expire_time;\n+static timestamp_t gc_log_expire_time;\n static const char *gc_log_expire = \"1.day.ago\";\n static const char *prune_expire = \"2.weeks.ago\";\n static const char *prune_worktrees_expire = \"3.months.ago\";\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f93ef6c7100..fd3d10ec217 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -911,7 +911,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (timestamp_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex cfe2a796f85..8ed96391c1d 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 92a5d8a5d26..44374750170 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttimestamp_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, timestamp_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\ttimestamp_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 0fe35d1b5ae..9b4ba8a80d7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static timestamp_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct oid_array recent_objects;\n \n static int loosened_object_can_be_discarded(const struct object_id *oid,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    timestamp_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 42633e0c6e6..8dcfecde0f3 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex c49333c9b66..b4e22f44497 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static timestamp_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttimestamp_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 74727757785..4228d9ff4db 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static timestamp_t default_reflog_expire;\n+static timestamp_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttimestamp_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttimestamp_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 19756595d57..8860f429b06 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttimestamp_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9993ded41aa..74f9b18d40c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..05e014fc5ab 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex ba27595d54d..f3a02993b20 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1476,18 +1476,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, timestamp_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+timestamp_t approxidate_careful(const char *, int *);\n+timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(timestamp_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 0d2d0fa1984..99a62b90ee2 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static timestamp_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n+\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 7b1986d5c8a..c9d887b5e53 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.c b/config.c\nindex 1a4d85537b3..3247bfaa020 100644\n--- a/config.c\n+++ b/config.c\n@@ -1926,7 +1926,7 @@ int git_config_get_expiry(const char *key, const char **output)\n \tif (ret)\n \t\treturn ret;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttimestamp_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..f3814cc47a0 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttimestamp_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static timestamp_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic timestamp_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\ttimestamp_t now = time(NULL);\n+\ttimestamp_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttimestamp_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 5c33dfd8ee7..92ab31aa441 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(timestamp_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttimestamp_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttimestamp_t years = totalmonths / 12;\n+\t\ttimestamp_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(timestamp_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttimestamp_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttimestamp_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttimestamp_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, timestamp_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = parse_timestamp(date, &end, 10);\n+\ttimestamp_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\n@@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n-\t\t\t\t     const struct timeval *tv,\n-\t\t\t\t     int *error_ret)\n+static timestamp_t approxidate_str(const char *date,\n+\t\t\t\t   const struct timeval *tv,\n+\t\t\t\t   int *error_ret)\n {\n \tint number = 0;\n \tint touched = 0;\n@@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,\n \tpending_number(&tm, &number);\n \tif (!touched)\n \t\t*error_ret = 1;\n-\treturn update_tm(&tm, &now, 0);\n+\treturn (timestamp_t)update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+timestamp_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(timestamp_t t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a1b8ea59e8d..fbe52f02346 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -392,7 +392,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -581,7 +581,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t timestamp_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -668,7 +668,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttimestamp_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex cd522903eda..72c12173a14 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+typedef unsigned long timestamp_t;\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..d6ea6075339 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 7419780a9b6..a6810f295cb 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(timestamp_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 24fb0c79062..587d48371b0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttimestamp_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4fc..682418f5d23 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n };\n \n static void add_recent_object(const struct object_id *oid,\n-\t\t\t      unsigned long mtime,\n+\t\t\t      timestamp_t mtime,\n \t\t\t      struct recent_data *data)\n {\n \tstruct object *obj;\n@@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    timestamp_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..3c00fa0526c 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  timestamp_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   timestamp_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c7836ae07bd..1fc5e9970db 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\n@@ -869,7 +869,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 99679f58255..3ca5ed8415a 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tstruct object_id ooid, noid;\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttimestamp_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttimestamp_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex d1e1b4399b3..6841bd9f712 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -712,7 +712,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttimestamp_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -721,15 +721,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttimestamp_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -776,7 +776,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n }\n \n static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -796,9 +796,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 49e97d7d5fd..2b80d37fd34 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -317,9 +317,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttimestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int refs_reflog_exists(struct ref_store *refs, const char *refname);\n@@ -356,7 +356,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tstruct object_id *old_oid, struct object_id *new_oid,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, timestamp_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n@@ -616,7 +616,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  timestamp_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ecbb13dc4b8..6646dcfc838 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3237,7 +3237,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tstruct object_id ooid, noid;\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint tz;\n \tconst char *p = sb->buf;\n \n@@ -4114,7 +4114,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, timestamp_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f73..8a8c1789c7b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttimestamp_t date = TIME_MAX;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n }\n \n static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(ooid, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 14886ec92b4..0d9e68b36e9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttimestamp_t max_age;\n+\ttimestamp_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 8eec9f7c1bb..35c1e2a9e32 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -660,8 +660,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttimestamp_t at_time;\n+\t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1054,7 +1054,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 269040f028f..f414a3ac670 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -27,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n \tparse_date_format(format, &mode);\n \tfor (; *argv; argv++) {\n \t\tchar *arg;\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\t/*\n@@ -48,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -65,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n static void parse_approxidate(const char **argv, struct timeval *now)\n {\n \tfor (; *argv; argv++) {\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tt = approxidate_relative(*argv, now);\n \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n \t}\n@@ -96,7 +96,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n \telse if (!strcmp(*argv, \"time_t-is64bit\"))\n \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..75fe883aac1 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static timestamp_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex a436bfdb053..9077ec2c330 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -138,7 +138,7 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)\n }\n \n static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n-\t\t       const char *committer, unsigned long timestamp,\n+\t\t       const char *committer, timestamp_t timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n \tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex 9b6725e02c9..d71b67e8d83 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..2abb3726fb5 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttimestamp_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4966f0b8a09..97da13e6a54 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static timestamp_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttimestamp_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5a89db30e3f 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttimestamp_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..b9a3b71c99f 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttimestamp_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..1846685a21a 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 03754849626..1b1d644b85f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1387,7 +1387,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, timestamp_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317479","messageId":"2b7f90c003a1f60ede39813530617edbbdf29607.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 7/9] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:45:53Z","receivedAt":"2017-04-21T10:46:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We are about to switch to a new data type for time stamps that is\ndefinitely not smaller or equal, but larger or equal to time_t.\n\nSo before using the system functions to process or format timestamps,\nlet's make extra certain that they can handle what we feed them.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n date.c | 10 ++++++++--\n 1 file changed, 8 insertions(+), 2 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 92ab31aa441..75f6335cd09 100644\n--- a/date.c\n+++ b/date.c\n@@ -46,7 +46,10 @@ static time_t gm_time_t(timestamp_t time, int tz)\n \tminutes = tz < 0 ? -tz : tz;\n \tminutes = (minutes / 100)*60 + (minutes % 100);\n \tminutes = tz < 0 ? -minutes : minutes;\n-\treturn time + minutes * 60;\n+\n+\tif (date_overflows(time + minutes * 60))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\treturn (time_t)time + minutes * 60;\n }\n \n /*\n@@ -70,7 +73,10 @@ static int local_tzoffset(timestamp_t time)\n \tstruct tm tm;\n \tint offset, eastwest;\n \n-\tt = time;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = (time_t)time;\n \tlocaltime_r(&t, &tm);\n \tt_local = tm_to_time_t(&tm);\n \n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317480","messageId":"b59a414793492786937e910f6cd588b8e1751b4b.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:46:01Z","receivedAt":"2017-04-21T10:46:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we used `unsigned long` for timestamps. This was only a good\nchoice on Linux, where we know implicitly that `unsigned long` is what is\nused for `time_t`.\n\nHowever, we want to use a different data type for timestamps for two\nreasons:\n\n- there is nothing that says that `unsigned long` should be the same data\n  type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n  `unsigned long` is 32-bit but `time_t` is 64-bit.\n\n- even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n  32-bit, we *want* to be able to encode timestamps in Git that are\n  currently absurdly far in the future, *even if* the system library is\n  not able to format those timestamps into date strings.\n\nSo let's just switch to the maximal integer type available, which should\nbe at least 64-bit for all practical purposes these days. It certainly\ncannot be worse than `unsigned long`, so...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-compat-util.h | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 72c12173a14..c678ca94b8f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,10 +319,14 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n-typedef unsigned long timestamp_t;\n-#define PRItime \"lu\"\n-#define parse_timestamp strtoul\n+typedef uintmax_t timestamp_t;\n+#define PRItime PRIuMAX\n+#define parse_timestamp strtoumax\n+#ifdef ULLONG_MAX\n+#define TIME_MAX ULLONG_MAX\n+#else\n #define TIME_MAX ULONG_MAX\n+#endif\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317481","messageId":"3a33b168e96c676592154dc1313a5bdea989831e.1492771484.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v4 9/9] show_date_ident(): defer date overflow check","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-21T10:46:06Z","receivedAt":"2017-04-21T10:46:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Now that we use uintmax_t for timestamps, we can represent timestamps\nthat would not fit inside the time_t data type. As long as we do not\nhave to use the system functions, we can even display them, e.g. as Unix\nepoch.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n pretty.c | 12 ++++--------\n 1 file changed, 4 insertions(+), 8 deletions(-)\n\ndiff --git a/pretty.c b/pretty.c\nindex 587d48371b0..35fd290096a 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -410,14 +410,10 @@ const char *show_ident_date(const struct ident_split *ident,\n \n \tif (ident->date_begin && ident->date_end)\n \t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n-\tif (date_overflows(date))\n-\t\tdate = 0;\n-\telse {\n-\t\tif (ident->tz_begin && ident->tz_end)\n-\t\t\ttz = strtol(ident->tz_begin, NULL, 10);\n-\t\tif (tz >= INT_MAX || tz <= INT_MIN)\n-\t\t\ttz = 0;\n-\t}\n+\tif (ident->tz_begin && ident->tz_end)\n+\t\ttz = strtol(ident->tz_begin, NULL, 10);\n+\tif (tz >= INT_MAX || tz <= INT_MIN)\n+\t\ttz = 0;\n \treturn show_date(date, tz, mode);\n }\n \n-- \n2.12.2.windows.2.406.gd14a8f8640f\n"},{"id":"317634","messageId":"xmqqr30i1omp.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"2b7f90c003a1f60ede39813530617edbbdf29607.1492771484.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 7/9] Abort if the system time cannot handle one of our timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-24T03:16:30Z","receivedAt":"2017-04-24T03:16:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> We are about to switch to a new data type for time stamps that is\n> definitely not smaller or equal, but larger or equal to time_t.\n>\n> So before using the system functions to process or format timestamps,\n> let's make extra certain that they can handle what we feed them.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  date.c | 10 ++++++++--\n>  1 file changed, 8 insertions(+), 2 deletions(-)\n>\n> diff --git a/date.c b/date.c\n> index 92ab31aa441..75f6335cd09 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -46,7 +46,10 @@ static time_t gm_time_t(timestamp_t time, int tz)\n>  \tminutes = tz < 0 ? -tz : tz;\n>  \tminutes = (minutes / 100)*60 + (minutes % 100);\n>  \tminutes = tz < 0 ? -minutes : minutes;\n> -\treturn time + minutes * 60;\n> +\n> +\tif (date_overflows(time + minutes * 60))\n> +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n> +\treturn (time_t)time + minutes * 60;\n>  }\n\nAll the other calls to date_overflows() take a variable that holds\ntimestamp_t and presumably they are checking for integer wraparound\nwhen the values are computed, but this one is not.  Perhaps we want\nto make it a bit more careful here?  I wonder if something like this \nis a good approach:\n\n    #define date_overflows(time) date_overflows_add(time, 0)\n\n    int date_overflows_add(timestamp_t base, timestamp_t minutes)\n    {\n\ttimestamp_t t;\n\tif (unsigned_add_overflows(base, minutes))\n\t    return 1;\n\tt = base + minutes;\n\tif ((uintmax_t) t >= TIME_MAX)\n            return 1;\n\t... what you have in date_overflows() ...\n    }\n\n"},{"id":"317635","messageId":"xmqqmvb61oh6.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"403936fa1df1b1c6d8daade2bfe853579b97bad3.1492771484.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 4/9] Specify explicitly where we parse timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-24T03:19:49Z","receivedAt":"2017-04-24T03:19:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Currently, Git's source code represents all timestamps as `unsigned\n> long`. In preparation for using a more appropriate data type, let's\n> introduce a symbol `parse_timestamp` (currently being defined to\n> `strtoul`) where appropriate, so that we can later easily switch to,\n> say, use `strtoull()` instead.\n\nApparently a very good first step in this series.\n"},{"id":"317637","messageId":"xmqqinlu1o8u.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"b59a414793492786937e910f6cd588b8e1751b4b.1492771484.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-24T03:24:49Z","receivedAt":"2017-04-24T03:25:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Previously, we used `unsigned long` for timestamps. This was only a good\n> choice on Linux, where we know implicitly that `unsigned long` is what is\n> used for `time_t`.\n>\n> However, we want to use a different data type for timestamps for two\n> reasons:\n>\n> - there is nothing that says that `unsigned long` should be the same data\n>   type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n>   `unsigned long` is 32-bit but `time_t` is 64-bit.\n>\n> - even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n>   32-bit, we *want* to be able to encode timestamps in Git that are\n>   currently absurdly far in the future, *even if* the system library is\n>   not able to format those timestamps into date strings.\n>\n> So let's just switch to the maximal integer type available, which should\n> be at least 64-bit for all practical purposes these days. It certainly\n> cannot be worse than `unsigned long`, so...\n\nShould we at least clamp in date_overflows() so that large values\nrepresentable with timestamp_t that will become unrepresentable when\nwe start allowing negative timestamps would be rejected?  That way\nwe won't have to hear complaints from the people who used timestamps\nfar in the future that we regressed the implementation for them by\nhalving the possible timestamp range.\n\n\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  git-compat-util.h | 10 +++++++---\n>  1 file changed, 7 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 72c12173a14..c678ca94b8f 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -319,10 +319,14 @@ extern char *gitdirname(char *);\n>  #define PRIo32 \"o\"\n>  #endif\n>  \n> -typedef unsigned long timestamp_t;\n> -#define PRItime \"lu\"\n> -#define parse_timestamp strtoul\n> +typedef uintmax_t timestamp_t;\n> +#define PRItime PRIuMAX\n> +#define parse_timestamp strtoumax\n> +#ifdef ULLONG_MAX\n> +#define TIME_MAX ULLONG_MAX\n> +#else\n>  #define TIME_MAX ULONG_MAX\n> +#endif\n>  \n>  #ifndef PATH_SEP\n>  #define PATH_SEP ':'\n"},{"id":"317638","messageId":"xmqqbmrm1o1k.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-24T03:29:11Z","receivedAt":"2017-04-24T03:29:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> Changes since v3:\n>\n> - fixed the fix in archive-zip.c that tried to report a too large\n>   timestamp (and would have reported the uninitialized time_t instead)\n>\n> - adjusted the so-far forgotten each_reflog() function (that was\n>   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n>   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n>   too\n>\n> - removed the date_overflows() check from time_to_tm(), as it calls\n>   gm_time_t() which already performs that check\n>\n> - the date_overflows() check in show_ident_date() was removed, as we do\n>   not know at that point yet whether we use the system functions to\n>   render the date or not (and there would not be a problem in the latter\n>   case)\n\nAssuming that the list consensus is to go with a separate\ntimestamp_t (for that added Cc for those whose comments I saw in an\nearlier round), the patches looked mostly good (I didn't read with\nfine toothed comb the largest one 6/8 to see if there were\ninadvertent or missed conversions from ulong to timestamp_t,\nthough), modulo a few minor \"huh?\" comments I sent separately.\n\nWill queue; thanks.\n"},{"id":"317646","messageId":"CA+P7+xoZ_dTvg9b6uckD4-=hHHNE42SCApzs9QO0YddpKXCR5g@mail.gmail.com","threadId":"45241","inReplyTo":"xmqqbmrm1o1k.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2017-04-24T06:15:09Z","receivedAt":"2017-04-24T06:15:36Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Sun, Apr 23, 2017 at 8:29 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>\n>> Changes since v3:\n>>\n>> - fixed the fix in archive-zip.c that tried to report a too large\n>>   timestamp (and would have reported the uninitialized time_t instead)\n>>\n>> - adjusted the so-far forgotten each_reflog() function (that was\n>>   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n>>   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n>>   too\n>>\n>> - removed the date_overflows() check from time_to_tm(), as it calls\n>>   gm_time_t() which already performs that check\n>>\n>> - the date_overflows() check in show_ident_date() was removed, as we do\n>>   not know at that point yet whether we use the system functions to\n>>   render the date or not (and there would not be a problem in the latter\n>>   case)\n>\n> Assuming that the list consensus is to go with a separate\n> timestamp_t (for that added Cc for those whose comments I saw in an\n> earlier round), the patches looked mostly good (I didn't read with\n> fine toothed comb the largest one 6/8 to see if there were\n> inadvertent or missed conversions from ulong to timestamp_t,\n> though), modulo a few minor \"huh?\" comments I sent separately.\n>\n> Will queue; thanks.\n\nI think that this timestamp_t makes sense. I didn't get a chance to\nreview the code to make sure nothing was forgotten, but I think the\ndirection makes sense to resolve the problems with current time_t and\nulong assumptions.\n\nThanks,\nJake\n"},{"id":"317663","messageId":"alpine.DEB.2.20.1704241226440.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqinlu1o8u.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T10:28:27Z","receivedAt":"2017-04-24T10:28:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 23 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Previously, we used `unsigned long` for timestamps. This was only a\n> > good choice on Linux, where we know implicitly that `unsigned long` is\n> > what is used for `time_t`.\n> >\n> > However, we want to use a different data type for timestamps for two\n> > reasons:\n> >\n> > - there is nothing that says that `unsigned long` should be the same data\n> >   type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n> >   `unsigned long` is 32-bit but `time_t` is 64-bit.\n> >\n> > - even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n> >   32-bit, we *want* to be able to encode timestamps in Git that are\n> >   currently absurdly far in the future, *even if* the system library is\n> >   not able to format those timestamps into date strings.\n> >\n> > So let's just switch to the maximal integer type available, which should\n> > be at least 64-bit for all practical purposes these days. It certainly\n> > cannot be worse than `unsigned long`, so...\n> \n> Should we at least clamp in date_overflows() so that large values\n> representable with timestamp_t that will become unrepresentable when\n> we start allowing negative timestamps would be rejected?  That way\n> we won't have to hear complaints from the people who used timestamps\n> far in the future that we regressed the implementation for them by\n> halving the possible timestamp range.\n\nPlease note that the date_overflows() command only tests when we are about\nto call system functions. I do not think that it does what you think it\ndoes (namely, validate timestamps when they enter Git).\n\nCiao,\nDscho\n"},{"id":"317671","messageId":"20170424113758.4orsjmicxbxdxdq4@sigill.intra.peff.net","threadId":"45241","inReplyTo":"xmqqbmrm1o1k.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-04-24T11:37:58Z","receivedAt":"2017-04-24T11:38:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Apr 23, 2017 at 08:29:11PM -0700, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Changes since v3:\n> >\n> > - fixed the fix in archive-zip.c that tried to report a too large\n> >   timestamp (and would have reported the uninitialized time_t instead)\n> >\n> > - adjusted the so-far forgotten each_reflog() function (that was\n> >   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n> >   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n> >   too\n> >\n> > - removed the date_overflows() check from time_to_tm(), as it calls\n> >   gm_time_t() which already performs that check\n> >\n> > - the date_overflows() check in show_ident_date() was removed, as we do\n> >   not know at that point yet whether we use the system functions to\n> >   render the date or not (and there would not be a problem in the latter\n> >   case)\n> \n> Assuming that the list consensus is to go with a separate\n> timestamp_t (for that added Cc for those whose comments I saw in an\n> earlier round), the patches looked mostly good (I didn't read with\n> fine toothed comb the largest one 6/8 to see if there were\n> inadvertent or missed conversions from ulong to timestamp_t,\n> though), modulo a few minor \"huh?\" comments I sent separately.\n> \n> Will queue; thanks.\n\nSorry, I haven't read the series carefully yet (but from a skim I'm\nhappy with the overall direction). It does seem to cause failures in\nt4212, though. For example:\n\n  expecting success: \n  \tcommit=$(munge_author_date HEAD 18446744073709551617) &&\n  \techo \"Thu Jan 1 00:00:00 1970 +0000\" >expect &&\n  \tgit log -1 --format=%ad $commit >actual &&\n  \ttest_cmp expect actual\n  \n  fatal: Timestamp too large for this system: 18446744073709551615\n  not ok 7 - date parser recognizes integer overflow\n\nWe used to convert overflows into a sentinel time, but now we die. I\noriginally chose the sentinel approach because it lets you use the tools\nto examine and recover from the broken state. I could be convinced that\ndying is better, but clearly we'd need to at least update the tests.\n\n-Peff\n"},{"id":"317679","messageId":"alpine.DEB.2.20.1704241228510.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqr30i1omp.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 7/9] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:57:28Z","receivedAt":"2017-04-24T13:57:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 23 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > diff --git a/date.c b/date.c\n> > index 92ab31aa441..75f6335cd09 100644\n> > --- a/date.c\n> > +++ b/date.c\n> > @@ -46,7 +46,10 @@ static time_t gm_time_t(timestamp_t time, int tz)\n> >  \tminutes = tz < 0 ? -tz : tz;\n> >  \tminutes = (minutes / 100)*60 + (minutes % 100);\n> >  \tminutes = tz < 0 ? -minutes : minutes;\n> > -\treturn time + minutes * 60;\n> > +\n> > +\tif (date_overflows(time + minutes * 60))\n> > +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n> > +\treturn (time_t)time + minutes * 60;\n> >  }\n> \n> All the other calls to date_overflows() take a variable that holds\n> timestamp_t and presumably they are checking for integer wraparound\n> when the values are computed, but this one is not.\n\nI was debating whether this extra check is necessary and had decided\nagainst it. Apparently I was wrong to do so.\n\n> Perhaps we want to make it a bit more careful here?  I wonder if\n> something like this is a good approach:\n> \n>     #define date_overflows(time) date_overflows_add(time, 0)\n> \n>     int date_overflows_add(timestamp_t base, timestamp_t minutes)\n>     {\n> \ttimestamp_t t;\n> \tif (unsigned_add_overflows(base, minutes))\n> \t    return 1;\n> \tt = base + minutes;\n> \tif ((uintmax_t) t >= TIME_MAX)\n>             return 1;\n> \t... what you have in date_overflows() ...\n>     }\n\nThat sounds like uglifying the common case for a single user. Let's not.\n\nThe code would also be incorrect, as the `minutes` variable can be\nnegative, which the `unsigned_add_overflows()` macro cannot handle (it\nwould report very, very false positives, and it would hurt you more than\nme because I live East of Greenwich).\n\nApart from that, the signature should use seconds, not minutes, or\nalternatively multiply by 60.\n\nI'll add a fixed extra check, to the single location that needs it.\n\nCiao,\nDscho\n"},{"id":"317680","messageId":"e801667c27e0dece4bc3489306831b4dfc9ad481.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:57:55Z","receivedAt":"2017-04-24T13:58:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply change that field to use `uintmax_t` instead.\n\nThis patch is a bit larger than the mere change of the data type\nbecause the field's name was tied to its data type, which has been fixed\nat the same time.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3a640448fd8..92871266001 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -351,7 +351,7 @@ struct ref_formatting_state {\n struct atom_value {\n \tconst char *s;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n \tstruct used_atom *atom;\n };\n \n@@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -875,11 +875,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1941,9 +1941,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317681","messageId":"7a71eddcd9c27661c29673e32f8ff7167240aff8.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 2/8] t0006 & t5000: prepare for 64-bit timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:57:58Z","receivedAt":"2017-04-24T13:58:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply uses an incorrect data type for timestamps, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) papered over this\nissue simply by skipping the respective test cases on platforms where\nthey would fail due to the data type in use.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`,\nconflating the two issues.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, after we\nswitch to a larger data type, we can flip that prerequisite to test\n`time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 13b5696822d..beee1d847ff 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1164,3 +1164,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317682","messageId":"cover.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1492771484.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:57:51Z","receivedAt":"2017-04-24T13:58:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as we already make use of\n64-bit data types internally. There is no good reason why we should not\nuse the same for timestamps. Hence, let's use uintmax_t for timestamps.\n\nNote: while the `time_t` data type exists and is meant to be used for\ntimestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\nused `time_t` for that reason, but it came with a few serious downsides:\nas `time_t` can be signed (and indeed, on Windows it is an int64_t),\nGit's expectation that 0 is the minimal value does no longer hold true,\nintroducing its own set of interesting challenges. Besides, if we *can*\nhandle far in the future timestamps (except for formatting them using\nthe system libraries), it is more consistent to do so.\n\nThe upside of using `uintmax_t` for timestamps is that we do a much\nbetter job to support far in the future timestamps across all platforms,\nincluding 32-bit ones. The downside is that those platforms that use a\n32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nThis iteration makes the date_overflows() check more stringent again.\n\nIt is arguably a bug to paper over too-large author/committer dates and\nto replace them with Jan 1 1970 without even telling the user that we do\nthat, but this is the behavior that t4212 verifies, so I reinstated that\nbehavior. The change in behavior was missed because of the missing\nunsigned_add_overflows() test.\n\nChanges since v4:\n\n- in gm_time_t(), we now test specifically that the timezone adjustment\n  neither underflows nor overflows.\n\n- the patch introduced in v4 that tried to defer the date_overflows()\n  check to gm_time_t() rather than replacing the ident timestamp by a 0\n  without any warning was dropped again: it broke t4212.\n\n\nJohannes Schindelin (8):\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  t0006 & t5000: prepare for 64-bit timestamps\n  t0006 & t5000: skip \"far in the future\" test when time_t is too\n    limited\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Introduce a new data type for timestamps\n  Abort if the system time cannot handle one of our timestamps\n  Use uintmax_t for timestamps\n\n Documentation/technical/api-parse-options.txt |   8 +-\n archive-tar.c                                 |   5 +-\n archive-zip.c                                 |  12 ++-\n archive.h                                     |   2 +-\n builtin/am.c                                  |   4 +-\n builtin/blame.c                               |  14 ++--\n builtin/fsck.c                                |   6 +-\n builtin/gc.c                                  |   2 +-\n builtin/log.c                                 |   4 +-\n builtin/merge-base.c                          |   2 +-\n builtin/name-rev.c                            |   6 +-\n builtin/pack-objects.c                        |   4 +-\n builtin/prune.c                               |   4 +-\n builtin/receive-pack.c                        |  14 ++--\n builtin/reflog.c                              |  24 +++---\n builtin/rev-list.c                            |   2 +-\n builtin/rev-parse.c                           |   2 +-\n builtin/show-branch.c                         |   4 +-\n builtin/worktree.c                            |   4 +-\n bundle.c                                      |   4 +-\n cache.h                                       |  14 ++--\n commit.c                                      |  18 ++--\n commit.h                                      |   2 +-\n config.c                                      |   2 +-\n credential-cache--daemon.c                    |  12 +--\n date.c                                        | 113 ++++++++++++++------------\n fetch-pack.c                                  |   8 +-\n fsck.c                                        |   2 +-\n git-compat-util.h                             |   9 ++\n http-backend.c                                |   4 +-\n parse-options-cb.c                            |   4 +-\n pretty.c                                      |   4 +-\n reachable.c                                   |   9 +-\n reachable.h                                   |   4 +-\n ref-filter.c                                  |  22 ++---\n reflog-walk.c                                 |   8 +-\n refs.c                                        |  14 ++--\n refs.h                                        |   8 +-\n refs/files-backend.c                          |   8 +-\n revision.c                                    |   6 +-\n revision.h                                    |   4 +-\n sha1_name.c                                   |   6 +-\n t/helper/test-date.c                          |  18 ++--\n t/helper/test-parse-options.c                 |   4 +-\n t/helper/test-ref-store.c                     |   4 +-\n t/t0006-date.sh                               |   4 +-\n t/t5000-tar-tree.sh                           |   6 +-\n t/test-lib.sh                                 |   3 +\n tag.c                                         |   6 +-\n tag.h                                         |   2 +-\n upload-pack.c                                 |   8 +-\n vcs-svn/fast_export.c                         |   8 +-\n vcs-svn/fast_export.h                         |   4 +-\n vcs-svn/svndump.c                             |   2 +-\n wt-status.c                                   |   2 +-\n 55 files changed, 260 insertions(+), 219 deletions(-)\n\n\nbase-commit: e2cb6ab84c94f147f1259260961513b40c36108a\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v5\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v5\n\nInterdiff vs v4:\n\n diff --git a/date.c b/date.c\n index 75f6335cd09..63fa99685e2 100644\n --- a/date.c\n +++ b/date.c\n @@ -47,9 +47,16 @@ static time_t gm_time_t(timestamp_t time, int tz)\n  \tminutes = (minutes / 100)*60 + (minutes % 100);\n  \tminutes = tz < 0 ? -minutes : minutes;\n  \n -\tif (date_overflows(time + minutes * 60))\n +\tif (minutes > 0) {\n +\t\tif (unsigned_add_overflows(time, minutes * 60))\n +\t\t\tdie(\"Timestamp+tz too large: %\"PRItime\" +%04d\",\n +\t\t\t    time, tz);\n +\t} else if (time < -minutes * 60)\n +\t\tdie(\"Timestamp before Unix epoch: %\"PRItime\" %04d\", time, tz);\n +\ttime += minutes * 60;\n +\tif (date_overflows(time))\n  \t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n -\treturn (time_t)time + minutes * 60;\n +\treturn (time_t)time;\n  }\n  \n  /*\n diff --git a/pretty.c b/pretty.c\n index 35fd290096a..587d48371b0 100644\n --- a/pretty.c\n +++ b/pretty.c\n @@ -410,10 +410,14 @@ const char *show_ident_date(const struct ident_split *ident,\n  \n  \tif (ident->date_begin && ident->date_end)\n  \t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n -\tif (ident->tz_begin && ident->tz_end)\n -\t\ttz = strtol(ident->tz_begin, NULL, 10);\n -\tif (tz >= INT_MAX || tz <= INT_MIN)\n -\t\ttz = 0;\n +\tif (date_overflows(date))\n +\t\tdate = 0;\n +\telse {\n +\t\tif (ident->tz_begin && ident->tz_end)\n +\t\t\ttz = strtol(ident->tz_begin, NULL, 10);\n +\t\tif (tz >= INT_MAX || tz <= INT_MIN)\n +\t\t\ttz = 0;\n +\t}\n  \treturn show_date(date, tz, mode);\n  }\n  \n\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n"},{"id":"317683","messageId":"b914a7e5689991edd275086ba299894c2ba4e2f8.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 3/8] t0006 & t5000: skip \"far in the future\" test when time_t is too limited","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:02Z","receivedAt":"2017-04-24T13:58:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned long, which is\nill-defined, as there is no guarantee about the number of bits that\ndata type has.\n\nIn preparation of switching to another data type that is large enough\nto hold \"far in the future\" dates, we need to prepare the t0006-date.sh\nscript for the case where we *still* cannot format those dates if the\nsystem library uses 32-bit time_t.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 2 +-\n t/test-lib.sh        | 1 +\n 4 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..ac7c66c733b 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n \"  test-date approxidate [date]...\\n\"\n-\"  test-date is64bit\\n\";\n+\"  test-date is64bit\\n\"\n+\"  test-date time_t-is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -96,6 +97,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n \t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 9539b425ffb..42d4ea61ef5 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 997aa9dea28..fe2d4f15a73 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex beee1d847ff..8d25cb7c183 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n '\n \n test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n+test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317684","messageId":"1950879477c86363f94add858394cc880d802ba6.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 5/8] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:24Z","receivedAt":"2017-04-24T13:58:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\naway from the ill-specified `unsigned long` data type.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\ndefined to \"lu\") to make it easier to change the data type used for\ntimestamps.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n builtin/rev-list.c            |  2 +-\n builtin/rev-parse.c           |  2 +-\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n refs/files-backend.c          |  2 +-\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n t/helper/test-ref-store.c     |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 15 files changed, 31 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 07506a3e457..e4b3c7b0ebf 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1844,7 +1844,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex b5e13a45560..c233eda21c8 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b3b10cc1edb..f93ef6c7100 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -910,7 +910,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex d25a57931f8..ab718f4402c 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -459,12 +459,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex bcf77f0b8a2..3b292c99bda 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n \t}\n \n \tif (info->show_timestamp)\n-\t\tprintf(\"%lu \", commit->date);\n+\t\tprintf(\"%\"PRItime\" \", commit->date);\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 05133309106..b4509002435 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -218,7 +218,7 @@ static void show_datestring(const char *flag, const char *datestr)\n \t/* date handling requires both flags and revs */\n \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n \t\treturn;\n-\tbuffer = xstrfmt(\"%s%lu\", flag, approxidate(datestr));\n+\tbuffer = xstrfmt(\"%s%\"PRItime, flag, approxidate(datestr));\n \tshow(buffer);\n \tfree(buffer);\n }\ndiff --git a/date.c b/date.c\nindex 495c207c64f..5c33dfd8ee7 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex afb8b050248..6004cea60d4 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -395,7 +395,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex d78cc36dd1a..b2451a12d54 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 801d26468e0..4e9e3628716 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4135,7 +4135,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n \t\t\tprintf(\"prune %s\", message);\n \t} else {\n \t\tif (cb->newlog) {\n-\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n+\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n \t\t\t\temail, timestamp, tz, message);\n \t\t\toidcpy(&cb->last_kept_oid, noid);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 52d1fc34454..269040f028f 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -53,7 +53,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 2d84c45ffe9..a436bfdb053 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -141,7 +141,7 @@ static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n \t\t       const char *committer, unsigned long timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n-\tprintf(\"%s %s %s %lu %d %s\\n\",\n+\tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\n \t       oid_to_hex(old_oid), oid_to_hex(new_oid),\n \t       committer, timestamp, tz, msg);\n \treturn 0;\ndiff --git a/upload-pack.c b/upload-pack.c\nindex f17f4dd1233..4966f0b8a09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -863,7 +863,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317685","messageId":"d6c1709475927a55c5bb0e6ce9d0b6be20b05735.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 4/8] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:05Z","receivedAt":"2017-04-24T13:58:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using a more appropriate data type, let's\nintroduce a symbol `parse_timestamp` (currently being defined to\n`strtoul`) where appropriate, so that we can later easily switch to,\nsay, use `strtoull()` instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c           | 2 +-\n builtin/receive-pack.c | 4 ++--\n bundle.c               | 2 +-\n commit.c               | 6 +++---\n date.c                 | 6 +++---\n fsck.c                 | 2 +-\n git-compat-util.h      | 2 ++\n pretty.c               | 2 +-\n ref-filter.c           | 2 +-\n refs/files-backend.c   | 2 +-\n t/helper/test-date.c   | 2 +-\n tag.c                  | 4 ++--\n upload-pack.c          | 2 +-\n 13 files changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 805f56cec2f..ffb7a6355fb 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -886,7 +886,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex f96834f42c9..d25a57931f8 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n \t}\n-\tstamp = strtoul(nonce, &bohmac, 10);\n+\tstamp = parse_timestamp(nonce, &bohmac, 10);\n \tif (bohmac == nonce || bohmac[0] != '-') {\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n@@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t * would mean it was issued by another server with its clock\n \t * skewed in the future.\n \t */\n-\tostamp = strtoul(push_cert_nonce, NULL, 10);\n+\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n \n \tif (nonce_stamp_slop_limit &&\ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 73c78c2b80c..0d2d0fa1984 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -89,8 +89,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -607,7 +607,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..495c207c64f 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\tunsigned long number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex e6152e4e6d4..d589341cddf 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -691,7 +691,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex bd04564a69a..d78cc36dd1a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex d0f86f5d85c..24fb0c79062 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 92871266001..c7836ae07bd 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -868,7 +868,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex c9d900fd128..801d26468e0 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3247,7 +3247,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n \t    !(email_end = strchr(p, '>')) ||\n \t    email_end[1] != ' ' ||\n-\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n+\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n \t    !message || message[0] != ' ' ||\n \t    (message[1] != '+' && message[1] != '-') ||\n \t    !isdigit(message[2]) || !isdigit(message[3]) ||\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ac7c66c733b..52d1fc34454 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -34,7 +34,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..9b6725e02c9 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -110,8 +110,8 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ffb028d6231..f17f4dd1233 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317686","messageId":"fea2df0e1ff5869572cf756d75fd3468d184457f.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 6/8] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:26Z","receivedAt":"2017-04-24T13:58:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. Which is incorrect, and causes a lot of problems, in particular\nwhere unsigned long is only 32-bit (notably on Windows, even in 64-bit\nversions).\n\nSo let's just use a more appropriate data type instead. In preparation\nfor this, we introduce the new `timestamp_t` data type.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs we will use a data type that is not necessarily identical to `time_t`,\nwe need to be very careful to use `time_t` whenever we interact with the\nsystem functions, and `timestamp_t` everywhere else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++--\n archive-tar.c                                 |  5 +-\n archive-zip.c                                 | 12 ++++-\n archive.h                                     |  2 +-\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++--\n builtin/fsck.c                                |  4 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +--\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        |  6 +--\n builtin/reflog.c                              | 24 +++++-----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 +++---\n commit.c                                      | 12 ++---\n commit.h                                      |  2 +-\n config.c                                      |  2 +-\n credential-cache--daemon.c                    | 12 ++---\n date.c                                        | 66 +++++++++++++--------------\n fetch-pack.c                                  |  6 +--\n git-compat-util.h                             |  2 +\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  2 +-\n reachable.c                                   |  9 ++--\n reachable.h                                   |  4 +-\n ref-filter.c                                  |  4 +-\n reflog-walk.c                                 |  8 ++--\n refs.c                                        | 14 +++---\n refs.h                                        |  8 ++--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +--\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +--\n t/helper/test-date.c                          |  8 ++--\n t/helper/test-parse-options.c                 |  2 +-\n t/helper/test-ref-store.c                     |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +-\n vcs-svn/fast_export.c                         |  4 +-\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 49 files changed, 169 insertions(+), 157 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 36768b479e1..829b5581105 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,13 +183,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..695339a2369 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n #define USTAR_MAX_SIZE 077777777777UL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/archive-zip.c b/archive-zip.c\nindex b429a8d974a..68df3d64402 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -545,9 +545,17 @@ static void write_zip_trailer(const unsigned char *sha1)\n \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n }\n \n-static void dos_time(time_t *time, int *dos_date, int *dos_time)\n+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n {\n-\tstruct tm *t = localtime(time);\n+\ttime_t time;\n+\tstruct tm *t;\n+\n+\tif (date_overflows(*timestamp))\n+\t\tdie(\"timestamp too large for this system: %\"PRItime,\n+\t\t    *timestamp);\n+\ttime = (time_t)*timestamp;\n+\tt = localtime(&time);\n+\t*timestamp = time;\n \n \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n \t            (t->tm_year + 1900 - 1980) * 512;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e2c..62d1d82c1af 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -9,7 +9,7 @@ struct archiver_args {\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n-\ttime_t time;\n+\ttimestamp_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex ffb7a6355fb..8bdbd53b618 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -881,7 +881,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e4b3c7b0ebf..f00eda16378 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttimestamp_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttimestamp_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1578,7 +1578,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttimestamp_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(timestamp_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex c233eda21c8..32a32e55c85 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n }\n \n static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 91f7696a85e..f484eda43ca 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -33,7 +33,7 @@ static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 50;\n static int detach_auto = 1;\n-static unsigned long gc_log_expire_time;\n+static timestamp_t gc_log_expire_time;\n static const char *gc_log_expire = \"1.day.ago\";\n static const char *prune_expire = \"2.weeks.ago\";\n static const char *prune_worktrees_expire = \"3.months.ago\";\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f93ef6c7100..fd3d10ec217 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -911,7 +911,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (timestamp_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex cfe2a796f85..8ed96391c1d 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 92a5d8a5d26..44374750170 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttimestamp_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, timestamp_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\ttimestamp_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 0fe35d1b5ae..9b4ba8a80d7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static timestamp_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct oid_array recent_objects;\n \n static int loosened_object_can_be_discarded(const struct object_id *oid,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    timestamp_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 42633e0c6e6..8dcfecde0f3 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex ab718f4402c..0bb36d584d7 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static timestamp_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttimestamp_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 74727757785..4228d9ff4db 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static timestamp_t default_reflog_expire;\n+static timestamp_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttimestamp_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttimestamp_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 19756595d57..8860f429b06 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttimestamp_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9993ded41aa..74f9b18d40c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..05e014fc5ab 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex ef0fe43a9df..e2482a510f7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1478,18 +1478,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, timestamp_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+timestamp_t approxidate_careful(const char *, int *);\n+timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(timestamp_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 0d2d0fa1984..99a62b90ee2 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static timestamp_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n+\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 7b1986d5c8a..c9d887b5e53 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.c b/config.c\nindex 0daaed338ea..4cf644b9fbf 100644\n--- a/config.c\n+++ b/config.c\n@@ -1943,7 +1943,7 @@ int git_config_get_expiry(const char *key, const char **output)\n \tif (ret)\n \t\treturn ret;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttimestamp_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..f3814cc47a0 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttimestamp_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static timestamp_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic timestamp_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\ttimestamp_t now = time(NULL);\n+\ttimestamp_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttimestamp_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 5c33dfd8ee7..92ab31aa441 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(timestamp_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttimestamp_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttimestamp_t years = totalmonths / 12;\n+\t\ttimestamp_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(timestamp_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttimestamp_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttimestamp_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttimestamp_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, timestamp_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = parse_timestamp(date, &end, 10);\n+\ttimestamp_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\n@@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n-\t\t\t\t     const struct timeval *tv,\n-\t\t\t\t     int *error_ret)\n+static timestamp_t approxidate_str(const char *date,\n+\t\t\t\t   const struct timeval *tv,\n+\t\t\t\t   int *error_ret)\n {\n \tint number = 0;\n \tint touched = 0;\n@@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,\n \tpending_number(&tm, &number);\n \tif (!touched)\n \t\t*error_ret = 1;\n-\treturn update_tm(&tm, &now, 0);\n+\treturn (timestamp_t)update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+timestamp_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(timestamp_t t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 6004cea60d4..5f15dd2c390 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -394,7 +394,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -583,7 +583,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t timestamp_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -670,7 +670,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttimestamp_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex b2451a12d54..594100e7652 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+typedef unsigned long timestamp_t;\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..d6ea6075339 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 7419780a9b6..a6810f295cb 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(timestamp_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 24fb0c79062..587d48371b0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttimestamp_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4fc..682418f5d23 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n };\n \n static void add_recent_object(const struct object_id *oid,\n-\t\t\t      unsigned long mtime,\n+\t\t\t      timestamp_t mtime,\n \t\t\t      struct recent_data *data)\n {\n \tstruct object *obj;\n@@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    timestamp_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..3c00fa0526c 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  timestamp_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   timestamp_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c7836ae07bd..1fc5e9970db 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\n@@ -869,7 +869,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 99679f58255..3ca5ed8415a 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tstruct object_id ooid, noid;\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttimestamp_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttimestamp_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex a3d5f42e373..f4944a658c7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -712,7 +712,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttimestamp_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -721,15 +721,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttimestamp_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -776,7 +776,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n }\n \n static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -796,9 +796,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 49e97d7d5fd..2b80d37fd34 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -317,9 +317,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttimestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int refs_reflog_exists(struct ref_store *refs, const char *refname);\n@@ -356,7 +356,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tstruct object_id *old_oid, struct object_id *new_oid,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, timestamp_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n@@ -616,7 +616,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  timestamp_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4e9e3628716..4d9d1144569 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3237,7 +3237,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tstruct object_id ooid, noid;\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint tz;\n \tconst char *p = sb->buf;\n \n@@ -4118,7 +4118,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, timestamp_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f73..8a8c1789c7b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttimestamp_t date = TIME_MAX;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n }\n \n static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(ooid, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 14886ec92b4..0d9e68b36e9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttimestamp_t max_age;\n+\ttimestamp_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 8eec9f7c1bb..35c1e2a9e32 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -660,8 +660,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttimestamp_t at_time;\n+\t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1054,7 +1054,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 269040f028f..f414a3ac670 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -27,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n \tparse_date_format(format, &mode);\n \tfor (; *argv; argv++) {\n \t\tchar *arg;\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\t/*\n@@ -48,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -65,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n static void parse_approxidate(const char **argv, struct timeval *now)\n {\n \tfor (; *argv; argv++) {\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tt = approxidate_relative(*argv, now);\n \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n \t}\n@@ -96,7 +96,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n \telse if (!strcmp(*argv, \"time_t-is64bit\"))\n \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..75fe883aac1 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static timestamp_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex a436bfdb053..9077ec2c330 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -138,7 +138,7 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)\n }\n \n static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n-\t\t       const char *committer, unsigned long timestamp,\n+\t\t       const char *committer, timestamp_t timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n \tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex 9b6725e02c9..d71b67e8d83 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..2abb3726fb5 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttimestamp_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4966f0b8a09..97da13e6a54 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static timestamp_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttimestamp_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5a89db30e3f 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttimestamp_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..b9a3b71c99f 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttimestamp_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..1846685a21a 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 03754849626..1b1d644b85f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1387,7 +1387,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, timestamp_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317687","messageId":"65d90090b7cf8046771879e2ebc881a055083d82.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 7/8] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:30Z","receivedAt":"2017-04-24T13:58:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We are about to switch to a new data type for time stamps that is\ndefinitely not smaller or equal, but larger or equal to time_t.\n\nSo before using the system functions to process or format timestamps,\nlet's make extra certain that they can handle what we feed them.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n date.c | 17 +++++++++++++++--\n 1 file changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 92ab31aa441..63fa99685e2 100644\n--- a/date.c\n+++ b/date.c\n@@ -46,7 +46,17 @@ static time_t gm_time_t(timestamp_t time, int tz)\n \tminutes = tz < 0 ? -tz : tz;\n \tminutes = (minutes / 100)*60 + (minutes % 100);\n \tminutes = tz < 0 ? -minutes : minutes;\n-\treturn time + minutes * 60;\n+\n+\tif (minutes > 0) {\n+\t\tif (unsigned_add_overflows(time, minutes * 60))\n+\t\t\tdie(\"Timestamp+tz too large: %\"PRItime\" +%04d\",\n+\t\t\t    time, tz);\n+\t} else if (time < -minutes * 60)\n+\t\tdie(\"Timestamp before Unix epoch: %\"PRItime\" %04d\", time, tz);\n+\ttime += minutes * 60;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\treturn (time_t)time;\n }\n \n /*\n@@ -70,7 +80,10 @@ static int local_tzoffset(timestamp_t time)\n \tstruct tm tm;\n \tint offset, eastwest;\n \n-\tt = time;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = (time_t)time;\n \tlocaltime_r(&t, &tm);\n \tt_local = tm_to_time_t(&tm);\n \n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317688","messageId":"50b62ed69c3239c076c28c5048bbd07396a25c5c.1493042239.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v5 8/8] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T13:58:34Z","receivedAt":"2017-04-24T13:58:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we used `unsigned long` for timestamps. This was only a good\nchoice on Linux, where we know implicitly that `unsigned long` is what is\nused for `time_t`.\n\nHowever, we want to use a different data type for timestamps for two\nreasons:\n\n- there is nothing that says that `unsigned long` should be the same data\n  type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n  `unsigned long` is 32-bit but `time_t` is 64-bit.\n\n- even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n  32-bit, we *want* to be able to encode timestamps in Git that are\n  currently absurdly far in the future, *even if* the system library is\n  not able to format those timestamps into date strings.\n\nSo let's just switch to the maximal integer type available, which should\nbe at least 64-bit for all practical purposes these days. It certainly\ncannot be worse than `unsigned long`, so...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-compat-util.h | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 594100e7652..b66995685af 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,10 +319,14 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n-typedef unsigned long timestamp_t;\n-#define PRItime \"lu\"\n-#define parse_timestamp strtoul\n+typedef uintmax_t timestamp_t;\n+#define PRItime PRIuMAX\n+#define parse_timestamp strtoumax\n+#ifdef ULLONG_MAX\n+#define TIME_MAX ULLONG_MAX\n+#else\n #define TIME_MAX ULONG_MAX\n+#endif\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n"},{"id":"317689","messageId":"alpine.DEB.2.20.1704241559460.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqbmrm1o1k.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T14:00:58Z","receivedAt":"2017-04-24T14:01:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sun, 23 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Changes since v3:\n> >\n> > - fixed the fix in archive-zip.c that tried to report a too large\n> >   timestamp (and would have reported the uninitialized time_t instead)\n> >\n> > - adjusted the so-far forgotten each_reflog() function (that was\n> >   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n> >   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n> >   too\n> >\n> > - removed the date_overflows() check from time_to_tm(), as it calls\n> >   gm_time_t() which already performs that check\n> >\n> > - the date_overflows() check in show_ident_date() was removed, as we do\n> >   not know at that point yet whether we use the system functions to\n> >   render the date or not (and there would not be a problem in the latter\n> >   case)\n> \n> Assuming that the list consensus is to go with a separate\n> timestamp_t (for that added Cc for those whose comments I saw in an\n> earlier round), the patches looked mostly good (I didn't read with\n> fine toothed comb the largest one 6/8 to see if there were\n> inadvertent or missed conversions from ulong to timestamp_t,\n> though), modulo a few minor \"huh?\" comments I sent separately.\n\nDang, I forgot to Cc: Peff and René... And I sent out v5 before adding\nthem, sorry!\n\nCiao,\nDscho"},{"id":"317690","messageId":"alpine.DEB.2.20.1704241601140.3480@virtualbox","threadId":"45241","inReplyTo":"CA+P7+xoZ_dTvg9b6uckD4-=hHHNE42SCApzs9QO0YddpKXCR5g@mail.gmail.com","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-24T14:02:26Z","receivedAt":"2017-04-24T14:02:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Jacob,\n\nOn Sun, 23 Apr 2017, Jacob Keller wrote:\n\n> On Sun, Apr 23, 2017 at 8:29 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> >\n> >> Changes since v3:\n> >>\n> >> - fixed the fix in archive-zip.c that tried to report a too large\n> >>   timestamp (and would have reported the uninitialized time_t instead)\n> >>\n> >> - adjusted the so-far forgotten each_reflog() function (that was\n> >>   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n> >>   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n> >>   too\n> >>\n> >> - removed the date_overflows() check from time_to_tm(), as it calls\n> >>   gm_time_t() which already performs that check\n> >>\n> >> - the date_overflows() check in show_ident_date() was removed, as we do\n> >>   not know at that point yet whether we use the system functions to\n> >>   render the date or not (and there would not be a problem in the latter\n> >>   case)\n> >\n> > Assuming that the list consensus is to go with a separate\n> > timestamp_t (for that added Cc for those whose comments I saw in an\n> > earlier round), the patches looked mostly good (I didn't read with\n> > fine toothed comb the largest one 6/8 to see if there were\n> > inadvertent or missed conversions from ulong to timestamp_t,\n> > though), modulo a few minor \"huh?\" comments I sent separately.\n> >\n> > Will queue; thanks.\n> \n> I think that this timestamp_t makes sense. I didn't get a chance to\n> review the code to make sure nothing was forgotten, but I think the\n> direction makes sense to resolve the problems with current time_t and\n> ulong assumptions.\n\nTBH I rely a bit on the combination of compiling on Windows and on 32-bit\nLinux to make sure that all the callers are converted. Originally, I was\nmore diligent, of course, but it took a while to get this patch series\ninto `pu` and there are so many possible new callers...\n\nCiao,\nDscho\n"},{"id":"317758","messageId":"xmqqzif5w6u9.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704241228510.3480@virtualbox","subject":"Re: [PATCH v4 7/9] Abort if the system time cannot handle one of our timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-25T02:37:18Z","receivedAt":"2017-04-25T02:37:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Junio,\n>\n> On Sun, 23 Apr 2017, Junio C Hamano wrote:\n>\n>> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n>> \n>> > diff --git a/date.c b/date.c\n>> > index 92ab31aa441..75f6335cd09 100644\n>> > --- a/date.c\n>> > +++ b/date.c\n>> > @@ -46,7 +46,10 @@ static time_t gm_time_t(timestamp_t time, int tz)\n>> >  \tminutes = tz < 0 ? -tz : tz;\n>> >  \tminutes = (minutes / 100)*60 + (minutes % 100);\n>> >  \tminutes = tz < 0 ? -minutes : minutes;\n>> > -\treturn time + minutes * 60;\n>> > +\n>> > +\tif (date_overflows(time + minutes * 60))\n>> > +\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n>> > +\treturn (time_t)time + minutes * 60;\n>> >  }\n>> \n>> All the other calls to date_overflows() take a variable that holds\n>> timestamp_t and presumably they are checking for integer wraparound\n>> when the values are computed, but this one is not.\n>\n> I was debating whether this extra check is necessary and had decided\n> against it. Apparently I was wrong to do so.\n\nNot so fast.  Apparently you had thought about it and I didn't think\nabout it as long as you did, hence I asked ...\n\n>\n>> Perhaps we want to make it a bit more careful here?  I wonder if\n>> something like this is a good approach:\n\nas a question, not a request to change things, and not a \"do not\ncome back until you rewrite it this way\" ;-).  Getting a question is\nnot a sign that you were wrong at all.\n\nIf you thought it was not needed, and if you can clearly explain to\nfuture readers of \"git log\" why it is the case, then I am prefectly\nfine without an extra check.\n\nIn a response to another message, you seem to indicate that existing\ncode does not do any range checking to make sure ulong (the current\ntype the existing code uses) does not wrap around and you kept that\n\"property\" of the code in this series (i.e.  date_overflows() range\ncheck was merely for downcasting timestamp_t to time_t before giving\nthe result to the system functions).  If that is the case, then NOT\nchecking for integer wraparound in \"+ minutes*60\" computation IS the\nconsistent thing to do within your series, I would think.\n"},{"id":"317766","messageId":"xmqqvaptw36d.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704241228510.3480@virtualbox","subject":"Re: [PATCH v4 7/9] Abort if the system time cannot handle one of our timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-25T03:56:26Z","receivedAt":"2017-04-25T03:56:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> The code would also be incorrect, as the `minutes` variable can be\n> negative, which the `unsigned_add_overflows()` macro cannot handle (it\n> would report very, very false positives, and it would hurt you more than\n> me because I live East of Greenwich).\n\nYes and no.  If we were to care about integer wraparound to do this\ncheck, we'd still have to worry about negative offset applied to a\ntime very close to the epoch that turns into a timestamp far far in\nthe future (unsigned_sub_underflows, that is).\n\n"},{"id":"317767","messageId":"xmqqr30hw31s.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704241226440.3480@virtualbox","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-25T03:59:11Z","receivedAt":"2017-04-25T03:59:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Should we at least clamp in date_overflows() so that large values\n>> representable with timestamp_t that will become unrepresentable when\n>> we start allowing negative timestamps would be rejected?  That way\n>> we won't have to hear complaints from the people who used timestamps\n>> far in the future that we regressed the implementation for them by\n>> halving the possible timestamp range.\n>\n> Please note that the date_overflows() command only tests when we are about\n> to call system functions. I do not think that it does what you think it\n> does (namely, validate timestamps when they enter Git).\n\nOK, then please read my question without date_overflows(), that is,\n\"should we at least clamp the values with some new mechanism to\nleave the door open for supporting times before the epoch, even if\n(and especially if) we leave the use of signed integral type for\ntimestamps out of the scope of this series?\"\n\n"},{"id":"317781","messageId":"xmqqtw5duiwo.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"d6c1709475927a55c5bb0e6ce9d0b6be20b05735.1493042239.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 4/8] Specify explicitly where we parse timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-25T05:59:35Z","receivedAt":"2017-04-25T05:59:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"oJohannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> diff --git a/pretty.c b/pretty.c\n> index d0f86f5d85c..24fb0c79062 100644\n> --- a/pretty.c\n> +++ b/pretty.c\n> @@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n>  \tlong tz = 0;\n>  \n>  \tif (ident->date_begin && ident->date_end)\n> -\t\tdate = strtoul(ident->date_begin, NULL, 10);\n> +\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n>  \tif (date_overflows(date))\n>  \t\tdate = 0;\n>  \telse {\n\nGood.  We'd need to choose a different sentinel when we allow signed\ntimestamps, but that is outside the scope of this series.  \n\nIt would not hurt if we used a symbolic constant instead of 0 here\nto save duplicated effort for future developers, though, and it is\nin line with the spirit of this exact patch where it uses a more\nspecific function name to differentiate strtoul() used for times\nfrom other uses of the same function.\n\nIn any case, I think another change to this section of the code made\nlater in another patch was where t4121 was broken in the previous\nround, and it is good to see the breakage go.  As Peff was hinting,\nwe might want to revisit \"should we substitute with a sentinel, or\nmake this a die?\" decision, but discussing it is totally outside the\nscope of this series.\n\n"},{"id":"317835","messageId":"alpine.DEB.2.20.1704252208520.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqr30hw31s.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-25T20:10:50Z","receivedAt":"2017-04-25T20:11:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 24 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Should we at least clamp in date_overflows() so that large values\n> >> representable with timestamp_t that will become unrepresentable when\n> >> we start allowing negative timestamps would be rejected?  That way we\n> >> won't have to hear complaints from the people who used timestamps far\n> >> in the future that we regressed the implementation for them by\n> >> halving the possible timestamp range.\n> >\n> > Please note that the date_overflows() command only tests when we are\n> > about to call system functions. I do not think that it does what you\n> > think it does (namely, validate timestamps when they enter Git).\n> \n> OK, then please read my question without date_overflows(), that is,\n> \"should we at least clamp the values with some new mechanism to leave\n> the door open for supporting times before the epoch, even if (and\n> especially if) we leave the use of signed integral type for timestamps\n> out of the scope of this series?\"\n\nYou are asking the wrong person because I do not care about timestamps\ndating before the dawn of Unix.\n\nIn any case, it is a question unrelated to the work I performed in this\npatch series: the raison d'être of these patches is to allow timestamps to\nrefer to dates that are currently insanely far in the future.\n\nCiao,\nDscho"},{"id":"317836","messageId":"alpine.DEB.2.20.1704252212160.3480@virtualbox","threadId":"45241","inReplyTo":"20170424113758.4orsjmicxbxdxdq4@sigill.intra.peff.net","subject":"Re: [PATCH v4 0/9] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-25T20:13:00Z","receivedAt":"2017-04-25T20:13:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Peff,\n\nOn Mon, 24 Apr 2017, Jeff King wrote:\n\n> On Sun, Apr 23, 2017 at 08:29:11PM -0700, Junio C Hamano wrote:\n> \n> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> > \n> > > Changes since v3:\n> > >\n> > > - fixed the fix in archive-zip.c that tried to report a too large\n> > >   timestamp (and would have reported the uninitialized time_t instead)\n> > >\n> > > - adjusted the so-far forgotten each_reflog() function (that was\n> > >   introduced after v1, in 80f2a6097c4 (t/helper: add test-ref-store to\n> > >   test ref-store functions, 2017-03-26)) to use timestamp_t and PRItime,\n> > >   too\n> > >\n> > > - removed the date_overflows() check from time_to_tm(), as it calls\n> > >   gm_time_t() which already performs that check\n> > >\n> > > - the date_overflows() check in show_ident_date() was removed, as we do\n> > >   not know at that point yet whether we use the system functions to\n> > >   render the date or not (and there would not be a problem in the latter\n> > >   case)\n> > \n> > Assuming that the list consensus is to go with a separate\n> > timestamp_t (for that added Cc for those whose comments I saw in an\n> > earlier round), the patches looked mostly good (I didn't read with\n> > fine toothed comb the largest one 6/8 to see if there were\n> > inadvertent or missed conversions from ulong to timestamp_t,\n> > though), modulo a few minor \"huh?\" comments I sent separately.\n> > \n> > Will queue; thanks.\n> \n> Sorry, I haven't read the series carefully yet (but from a skim I'm\n> happy with the overall direction). It does seem to cause failures in\n> t4212, though. For example:\n> \n>   expecting success: \n>   \tcommit=$(munge_author_date HEAD 18446744073709551617) &&\n>   \techo \"Thu Jan 1 00:00:00 1970 +0000\" >expect &&\n>   \tgit log -1 --format=%ad $commit >actual &&\n>   \ttest_cmp expect actual\n>   \n>   fatal: Timestamp too large for this system: 18446744073709551615\n>   not ok 7 - date parser recognizes integer overflow\n> \n> We used to convert overflows into a sentinel time, but now we die. I\n> originally chose the sentinel approach because it lets you use the tools\n> to examine and recover from the broken state. I could be convinced that\n> dying is better, but clearly we'd need to at least update the tests.\n\nSorry, I dropped this patch in v5 because I did not want to fight this\nbattle.\n\nCiao,\nDscho\n"},{"id":"317864","messageId":"7a2271ff-1386-18a6-5f6d-7eb13dc92509@web.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 0/8] Introduce timestamp_t for timestamps","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-04-25T21:54:46Z","receivedAt":"2017-04-25T21:55:00Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 24.04.2017 um 15:57 schrieb Johannes Schindelin:\n> Git v2.9.2 was released in a hurry to accomodate for platforms like\n> Windows, where the `unsigned long` data type is 32-bit even for 64-bit\n> setups.\n> \n> The quick fix was to simply disable all the testing with \"absurd\" future\n> dates.\n> \n> However, we can do much better than that, as we already make use of\n> 64-bit data types internally. There is no good reason why we should not\n> use the same for timestamps. Hence, let's use uintmax_t for timestamps.\n> \n> Note: while the `time_t` data type exists and is meant to be used for\n> timestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\n> used `time_t` for that reason, but it came with a few serious downsides:\n> as `time_t` can be signed (and indeed, on Windows it is an int64_t),\n> Git's expectation that 0 is the minimal value does no longer hold true,\n> introducing its own set of interesting challenges. Besides, if we *can*\n> handle far in the future timestamps (except for formatting them using\n> the system libraries), it is more consistent to do so.\n\ntime_t is signed on Linux and BSDs as well.\n\nUsing an unsigned type gives us the ability to represent times beyond\nthe 292 billion years in the future that int64_t would give us, but\nprevents recording events that occurred before the Epoch.  That doesn't\nsound like a good deal to me -- storing historical works (e.g. law\ntexts) with real time stamps is probably more interesting than fixing\nthe year 292277026596 problem within this decade.\n\n> The upside of using `uintmax_t` for timestamps is that we do a much\n> better job to support far in the future timestamps across all platforms,\n> including 32-bit ones. The downside is that those platforms that use a\n> 32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nIIUC this series has two aims: solving the year 2038 problem on 32-bit\nLinux by replacing time_t (int32_t), and solving the year 2106 problem\non Windows by replacing unsigned long (uint32_t), right?  The latter one\nsounds more interesting, because 32-bit platforms would still be unable\nto fully use bigger time values as you wrote above.\n\nCan we leave time_t alone and just do the part where you replace\nunsigned long with timestamp_t defined as uint64_t?  That should already\nhelp on Windows, correct?  When/if timestamp_t is later changed to a\nsigned type then we could easily convert the time_t cases to timestamp_t\nas well, or the other way around.\n\n> This iteration makes the date_overflows() check more stringent again.\n> \n> It is arguably a bug to paper over too-large author/committer dates and\n> to replace them with Jan 1 1970 without even telling the user that we do\n> that, but this is the behavior that t4212 verifies, so I reinstated that\n> behavior. The change in behavior was missed because of the missing\n> unsigned_add_overflows() test.\n\nI can't think of many ways to get future time stamps (broken clock,\nbroken CMOS battery, bit rot, time travel), so I wouldn't expect a\nchange towards better error reporting to affect a lot of users.  (Not\nnecessarily as part of this series, of course.)\n\n> Changes since v4:\n> \n> - in gm_time_t(), we now test specifically that the timezone adjustment\n>    neither underflows nor overflows.\n> \n> - the patch introduced in v4 that tried to defer the date_overflows()\n>    check to gm_time_t() rather than replacing the ident timestamp by a 0\n>    without any warning was dropped again: it broke t4212.\n> \n> \n> Johannes Schindelin (8):\n>    ref-filter: avoid using `unsigned long` for catch-all data type\n>    t0006 & t5000: prepare for 64-bit timestamps\n>    t0006 & t5000: skip \"far in the future\" test when time_t is too\n>      limited\n>    Specify explicitly where we parse timestamps\n>    Introduce a new \"printf format\" for timestamps\n>    Introduce a new data type for timestamps\n>    Abort if the system time cannot handle one of our timestamps\n>    Use uintmax_t for timestamps\n> \n>   Documentation/technical/api-parse-options.txt |   8 +-\n>   archive-tar.c                                 |   5 +-\n>   archive-zip.c                                 |  12 ++-\n>   archive.h                                     |   2 +-\n>   builtin/am.c                                  |   4 +-\n>   builtin/blame.c                               |  14 ++--\n>   builtin/fsck.c                                |   6 +-\n>   builtin/gc.c                                  |   2 +-\n>   builtin/log.c                                 |   4 +-\n>   builtin/merge-base.c                          |   2 +-\n>   builtin/name-rev.c                            |   6 +-\n>   builtin/pack-objects.c                        |   4 +-\n>   builtin/prune.c                               |   4 +-\n>   builtin/receive-pack.c                        |  14 ++--\n>   builtin/reflog.c                              |  24 +++---\n>   builtin/rev-list.c                            |   2 +-\n>   builtin/rev-parse.c                           |   2 +-\n>   builtin/show-branch.c                         |   4 +-\n>   builtin/worktree.c                            |   4 +-\n>   bundle.c                                      |   4 +-\n>   cache.h                                       |  14 ++--\n>   commit.c                                      |  18 ++--\n>   commit.h                                      |   2 +-\n>   config.c                                      |   2 +-\n>   credential-cache--daemon.c                    |  12 +--\n>   date.c                                        | 113 ++++++++++++++------------\n>   fetch-pack.c                                  |   8 +-\n>   fsck.c                                        |   2 +-\n>   git-compat-util.h                             |   9 ++\n>   http-backend.c                                |   4 +-\n>   parse-options-cb.c                            |   4 +-\n>   pretty.c                                      |   4 +-\n>   reachable.c                                   |   9 +-\n>   reachable.h                                   |   4 +-\n>   ref-filter.c                                  |  22 ++---\n>   reflog-walk.c                                 |   8 +-\n>   refs.c                                        |  14 ++--\n>   refs.h                                        |   8 +-\n>   refs/files-backend.c                          |   8 +-\n>   revision.c                                    |   6 +-\n>   revision.h                                    |   4 +-\n>   sha1_name.c                                   |   6 +-\n>   t/helper/test-date.c                          |  18 ++--\n>   t/helper/test-parse-options.c                 |   4 +-\n>   t/helper/test-ref-store.c                     |   4 +-\n>   t/t0006-date.sh                               |   4 +-\n>   t/t5000-tar-tree.sh                           |   6 +-\n>   t/test-lib.sh                                 |   3 +\n>   tag.c                                         |   6 +-\n>   tag.h                                         |   2 +-\n>   upload-pack.c                                 |   8 +-\n>   vcs-svn/fast_export.c                         |   8 +-\n>   vcs-svn/fast_export.h                         |   4 +-\n>   vcs-svn/svndump.c                             |   2 +-\n>   wt-status.c                                   |   2 +-\n>   55 files changed, 260 insertions(+), 219 deletions(-)\n\nHow did you find all the pieces of code that need to be touched?  Is\nthere a regex or something that can be used to spot new such places\nthat sneak in, e.g. through in-flight merges?\n\n> base-commit: e2cb6ab84c94f147f1259260961513b40c36108a\n> Published-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v5\n> Fetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v5\n> \n> Interdiff vs v4:\n> \n>   diff --git a/date.c b/date.c\n>   index 75f6335cd09..63fa99685e2 100644\n>   --- a/date.c\n>   +++ b/date.c\n>   @@ -47,9 +47,16 @@ static time_t gm_time_t(timestamp_t time, int tz)\n>    \tminutes = (minutes / 100)*60 + (minutes % 100);\n>    \tminutes = tz < 0 ? -minutes : minutes;\n>    \n>   -\tif (date_overflows(time + minutes * 60))\n>   +\tif (minutes > 0) {\n>   +\t\tif (unsigned_add_overflows(time, minutes * 60))\n>   +\t\t\tdie(\"Timestamp+tz too large: %\"PRItime\" +%04d\",\n>   +\t\t\t    time, tz);\n>   +\t} else if (time < -minutes * 60)\n>   +\t\tdie(\"Timestamp before Unix epoch: %\"PRItime\" %04d\", time, tz);\n>   +\ttime += minutes * 60;\n>   +\tif (date_overflows(time))\n>    \t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n>   -\treturn (time_t)time + minutes * 60;\n>   +\treturn (time_t)time;\n>    }\n>    \n>    /*\n>   diff --git a/pretty.c b/pretty.c\n>   index 35fd290096a..587d48371b0 100644\n>   --- a/pretty.c\n>   +++ b/pretty.c\n>   @@ -410,10 +410,14 @@ const char *show_ident_date(const struct ident_split *ident,\n>    \n>    \tif (ident->date_begin && ident->date_end)\n>    \t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n>   -\tif (ident->tz_begin && ident->tz_end)\n>   -\t\ttz = strtol(ident->tz_begin, NULL, 10);\n>   -\tif (tz >= INT_MAX || tz <= INT_MIN)\n>   -\t\ttz = 0;\n>   +\tif (date_overflows(date))\n>   +\t\tdate = 0;\n>   +\telse {\n>   +\t\tif (ident->tz_begin && ident->tz_end)\n>   +\t\t\ttz = strtol(ident->tz_begin, NULL, 10);\n>   +\t\tif (tz >= INT_MAX || tz <= INT_MIN)\n>   +\t\t\ttz = 0;\n>   +\t}\n>    \treturn show_date(date, tz, mode);\n>    }\n>    \n> \n"},{"id":"317868","messageId":"alpine.DEB.2.20.1704260005310.3480@virtualbox","threadId":"45241","inReplyTo":"7a2271ff-1386-18a6-5f6d-7eb13dc92509@web.de","subject":"Re: [PATCH v5 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-25T22:22:00Z","receivedAt":"2017-04-25T22:22:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi René,\n\nOn Tue, 25 Apr 2017, René Scharfe wrote:\n\n> Am 24.04.2017 um 15:57 schrieb Johannes Schindelin:\n> > Git v2.9.2 was released in a hurry to accomodate for platforms like\n> > Windows, where the `unsigned long` data type is 32-bit even for 64-bit\n> > setups.\n> > \n> > The quick fix was to simply disable all the testing with \"absurd\"\n> > future dates.\n> > \n> > However, we can do much better than that, as we already make use of\n> > 64-bit data types internally. There is no good reason why we should\n> > not use the same for timestamps. Hence, let's use uintmax_t for\n> > timestamps.\n> > \n> > Note: while the `time_t` data type exists and is meant to be used for\n> > timestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\n> > used `time_t` for that reason, but it came with a few serious\n> > downsides: as `time_t` can be signed (and indeed, on Windows it is an\n> > int64_t), Git's expectation that 0 is the minimal value does no longer\n> > hold true, introducing its own set of interesting challenges. Besides,\n> > if we *can* handle far in the future timestamps (except for formatting\n> > them using the system libraries), it is more consistent to do so.\n> \n> time_t is signed on Linux and BSDs as well.\n\ns/is/happens to be/.\n\nThe point is: we must not rely on time_t to be signed just because it\n*happens* to be the case on the setups to which we have access. We want\nGit to be portable, not only \"portable to our own setups\".\n\n> Using an unsigned type gives us the ability to represent times beyond\n> the 292 billion years in the future that int64_t would give us, but\n> prevents recording events that occurred before the Epoch.  That doesn't\n> sound like a good deal to me -- storing historical works (e.g. law\n> texts) with real time stamps is probably more interesting than fixing\n> the year 292277026596 problem within this decade.\n\nIt sounds like a good deal to me, if the alternative is that *I* have to\npatch Git's source code to support signed timestamps, when *I* am probably\nthe only one in this entire thread who does not even want them.\n\nSo could y'all please just stop talking about signed timestamps to me? I\nfeel that they are really, really start to irritate the hell out of me.\n\n> > The upside of using `uintmax_t` for timestamps is that we do a much\n> > better job to support far in the future timestamps across all\n> > platforms, including 32-bit ones. The downside is that those platforms\n> > that use a 32-bit `time_t` will barf when parsing or formatting those\n> > timestamps.\n> \n> IIUC this series has two aims: solving the year 2038 problem on 32-bit\n> Linux by replacing time_t (int32_t), and solving the year 2106 problem\n> on Windows by replacing unsigned long (uint32_t), right?\n\nNo. The series has one aim: to stop using `unsigned long` (which is\nill-defined to begin with) for timestamps.\n\n> The latter one sounds more interesting, because 32-bit platforms would\n> still be unable to fully use bigger time values as you wrote above.\n> \n> Can we leave time_t alone and just do the part where you replace\n> unsigned long with timestamp_t defined as uint64_t?  That should already\n> help on Windows, correct?  When/if timestamp_t is later changed to a\n> signed type then we could easily convert the time_t cases to timestamp_t\n> as well, or the other way around.\n\nThis patch series leaves time_t alone already, so your wish has been\nfulfilled preemptively.\n\n> > This iteration makes the date_overflows() check more stringent again.\n> > \n> > It is arguably a bug to paper over too-large author/committer dates and\n> > to replace them with Jan 1 1970 without even telling the user that we do\n> > that, but this is the behavior that t4212 verifies, so I reinstated that\n> > behavior. The change in behavior was missed because of the missing\n> > unsigned_add_overflows() test.\n> \n> I can't think of many ways to get future time stamps (broken clock,\n> broken CMOS battery, bit rot, time travel), so I wouldn't expect a\n> change towards better error reporting to affect a lot of users.  (Not\n> necessarily as part of this series, of course.)\n\nIf you want to suggest that we should stop verifying overflows when a\ncomplex reasoning can prove that the overflow is not happening in a\nbillion years, I disagree. Not only is it unnecessarily time-consuming to\nask readers to perform the complex reasoning, and not only is there enough\nroom for bugs to hide in plain sight (because of the complexity), it also\nmakes the same code harder to reuse in other software where a different\ntimestamp data type was chosen (or inherited from previous Git versions).\n\nI'd much rather have easy-to-reason code that does not cause head\nscratching (like the \"why do we ignore a too large timestamp?\" triggering\n`if (date_overflows(date)) date = 0;`) than pretending to be smart and\nclever and make everybody else feel stupid by forcing them through hoops\nof thinking bubbles until they also reached the conclusion that this\nactually won't happen. Unless there is a bug in the code.\n\n> >   Documentation/technical/api-parse-options.txt |   8 +-\n> >   archive-tar.c                                 |   5 +-\n> >   archive-zip.c                                 |  12 ++-\n> >   archive.h                                     |   2 +-\n> >   builtin/am.c                                  |   4 +-\n> >   builtin/blame.c                               |  14 ++--\n> >   builtin/fsck.c                                |   6 +-\n> >   builtin/gc.c                                  |   2 +-\n> >   builtin/log.c                                 |   4 +-\n> >   builtin/merge-base.c                          |   2 +-\n> >   builtin/name-rev.c                            |   6 +-\n> >   builtin/pack-objects.c                        |   4 +-\n> >   builtin/prune.c                               |   4 +-\n> >   builtin/receive-pack.c                        |  14 ++--\n> >   builtin/reflog.c                              |  24 +++---\n> >   builtin/rev-list.c                            |   2 +-\n> >   builtin/rev-parse.c                           |   2 +-\n> >   builtin/show-branch.c                         |   4 +-\n> >   builtin/worktree.c                            |   4 +-\n> >   bundle.c                                      |   4 +-\n> >   cache.h                                       |  14 ++--\n> >   commit.c                                      |  18 ++--\n> >   commit.h                                      |   2 +-\n> >   config.c                                      |   2 +-\n> >   credential-cache--daemon.c                    |  12 +--\n> >   date.c                                        | 113\n> >   ++++++++++++++------------\n> >   fetch-pack.c                                  |   8 +-\n> >   fsck.c                                        |   2 +-\n> >   git-compat-util.h                             |   9 ++\n> >   http-backend.c                                |   4 +-\n> >   parse-options-cb.c                            |   4 +-\n> >   pretty.c                                      |   4 +-\n> >   reachable.c                                   |   9 +-\n> >   reachable.h                                   |   4 +-\n> >   ref-filter.c                                  |  22 ++---\n> >   reflog-walk.c                                 |   8 +-\n> >   refs.c                                        |  14 ++--\n> >   refs.h                                        |   8 +-\n> >   refs/files-backend.c                          |   8 +-\n> >   revision.c                                    |   6 +-\n> >   revision.h                                    |   4 +-\n> >   sha1_name.c                                   |   6 +-\n> >   t/helper/test-date.c                          |  18 ++--\n> >   t/helper/test-parse-options.c                 |   4 +-\n> >   t/helper/test-ref-store.c                     |   4 +-\n> >   t/t0006-date.sh                               |   4 +-\n> >   t/t5000-tar-tree.sh                           |   6 +-\n> >   t/test-lib.sh                                 |   3 +\n> >   tag.c                                         |   6 +-\n> >   tag.h                                         |   2 +-\n> >   upload-pack.c                                 |   8 +-\n> >   vcs-svn/fast_export.c                         |   8 +-\n> >   vcs-svn/fast_export.h                         |   4 +-\n> >   vcs-svn/svndump.c                             |   2 +-\n> >   wt-status.c                                   |   2 +-\n> >   55 files changed, 260 insertions(+), 219 deletions(-)\n> \n> How did you find all the pieces of code that need to be touched?\n\nPain and suffering.\n\nSeriosly, for v1 of this patch series, I went painstakingly through `git\ngrep -Ovi \"unsigned long\"`. I determined for every single use of `unsigned\nlong` whether it referred to a timestamp and changed it accordingly.\n\nIn subsequent iterations, I went the cheaper route of compiling with\nDEVELOPER=1 on Windows and once I even went through replacing the 64-bit\nlibraries and compiler/linker in my Linux VM with 32-bit ones to imitate\nthe 32-bit Linux Travis coordinate (because I failed to get the Docker\nsetup to run in the VM). These build runs identified new callers of\nfunctions whose signature I had to change to avoid `unsigned long` for\ntimestamps.\n\nThis was no fun.\n\n> Is there a regex or something that can be used to spot new such places\n> that sneak in, e.g. through in-flight merges?\n\nNo, a regex would only work if we already had converted all `unsigned\nlong` uses to semantically meaningful data types.\n\nCiao,\nDscho\n\nP.S.: Please remove the quoted interdiff when there is no reason to keep\nit around."},{"id":"317888","messageId":"xmqqvapsszoo.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704252208520.3480@virtualbox","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-26T01:52:23Z","receivedAt":"2017-04-26T01:52:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> In any case, it is a question unrelated to the work I performed in this\n> patch series: the raison d'être of these patches is to allow timestamps to\n> refer to dates that are currently insanely far in the future.\n\nYes, but the job of the maintainer is to prevent narrow-focused\nindividual contributors from throwing us into a hole we cannot dig\nout of by closing the door for plausible future enhancements.\n\n"},{"id":"317889","messageId":"xmqqr30gszhh.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"7a2271ff-1386-18a6-5f6d-7eb13dc92509@web.de","subject":"Re: [PATCH v5 0/8] Introduce timestamp_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-26T01:56:42Z","receivedAt":"2017-04-26T01:56:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <l.s.r@web.de> writes:\n\n> I can't think of many ways to get future time stamps (broken clock,\n> broken CMOS battery, bit rot, time travel), so I wouldn't expect a\n> change towards better error reporting to affect a lot of users.  (Not\n> necessarily as part of this series, of course.)\n\nBetter error reporting is one thing, but we do not want to kill \"git\nlog\" in the middle by calling die().  \n\nDropping the patch v4 9/9 that caused us to call die() was a good\nthing to do within the scope of this series, I would think.\n\n"},{"id":"317896","messageId":"xmqqtw5bsufy.fsf@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"xmqqvapsszoo.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-26T03:45:37Z","receivedAt":"2017-04-26T03:45:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>\n>> In any case, it is a question unrelated to the work I performed in this\n>> patch series: the raison d'être of these patches is to allow timestamps to\n>> refer to dates that are currently insanely far in the future.\n>\n> Yes, but the job of the maintainer is to prevent narrow-focused\n> individual contributors from throwing us into a hole we cannot dig\n> out of by closing the door for plausible future enhancements.\n\nHaving said that, IIRC, this series does not tighten the existing\ncode to specifically check for integer wrap-around anyway, so in a\nsense, users who use a timestamp that is in an insanely distant\nfuture is already accepting the risk of getting broken in the\nfuture, so my answer to the question I asked is \"it would be extra\nnice to future-proof people's data, but not doing anything is\nprobably OK---at least we is not making things worse.\"\n\n"},{"id":"317914","messageId":"alpine.DEB.2.20.1704261131500.3480@virtualbox","threadId":"45241","inReplyTo":"xmqqvapsszoo.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T09:32:40Z","receivedAt":"2017-04-26T09:47:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 25 Apr 2017, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > In any case, it is a question unrelated to the work I performed in\n> > this patch series: the raison d'être of these patches is to allow\n> > timestamps to refer to dates that are currently insanely far in the\n> > future.\n> \n> Yes, but the job of the maintainer is to prevent narrow-focused\n> individual contributors from throwing us into a hole we cannot dig out\n> of by closing the door for plausible future enhancements.\n\nYou make it sound as if I made the code stricter in any way, or even\nintroduced a check that was not there before.\n\nAs I did no such thing, you may want to reword your statement?\n\nCiao,\nDscho"},{"id":"317931","messageId":"CAPc5daWzotQZoVQ40pmWrgWSPwrcgqEqAcEbjRcJ-Ev_9a73AA@mail.gmail.com","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704261131500.3480@virtualbox","subject":"Re: [PATCH v4 8/9] Use uintmax_t for timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-26T13:18:44Z","receivedAt":"2017-04-26T13:19:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"(in gmail so pardon top posting)\n\nAs I said, this series does *not* tighten the existing code anyway, so\nit is not like something that used to be accepted are now getting rejected.\n\nHappy?\n\nWhat I was worried about is actually the other way around, though.\n\n\nOn Wed, Apr 26, 2017 at 6:32 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> Hi Junio,\n>\n> On Tue, 25 Apr 2017, Junio C Hamano wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>>\n>> > In any case, it is a question unrelated to the work I performed in\n>> > this patch series: the raison d'être of these patches is to allow\n>> > timestamps to refer to dates that are currently insanely far in the\n>> > future.\n>>\n>> Yes, but the job of the maintainer is to prevent narrow-focused\n>> individual contributors from throwing us into a hole we cannot dig out\n>> of by closing the door for plausible future enhancements.\n>\n> You make it sound as if I made the code stricter in any way, or even\n> introduced a check that was not there before.\n>\n> As I did no such thing, you may want to reword your statement?\n>\n> Ciao,\n> Dscho\n"},{"id":"317934","messageId":"02b74d66-97e6-c633-888a-0c6a628cc5bd@kdbg.org","threadId":"45241","inReplyTo":"50b62ed69c3239c076c28c5048bbd07396a25c5c.1493042239.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 8/8] Use uintmax_t for timestamps","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2017-04-26T16:36:50Z","receivedAt":"2017-04-26T16:37:08Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 24.04.2017 um 15:58 schrieb Johannes Schindelin:\n>  #define PRIo32 \"o\"\n>  #endif\n>  \n> -typedef unsigned long timestamp_t;\n> -#define PRItime \"lu\"\n> -#define parse_timestamp strtoul\n> +typedef uintmax_t timestamp_t;\n> +#define PRItime PRIuMAX\n> +#define parse_timestamp strtoumax\n> +#ifdef ULLONG_MAX\n> +#define TIME_MAX ULLONG_MAX\n> +#else\n>  #define TIME_MAX ULONG_MAX\n> +#endif\n>  \n>  #ifndef PATH_SEP\n>  #define PATH_SEP ':'\n> \n\nI think you should squash in this:\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 26d2643667..b5f4a7bb2f 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -322,11 +322,7 @@ extern char *gitdirname(char *);\n typedef uintmax_t timestamp_t;\n #define PRItime PRIuMAX\n #define parse_timestamp strtoumax\n-#ifdef ULLONG_MAX\n-#define TIME_MAX ULLONG_MAX\n-#else\n-#define TIME_MAX ULONG_MAX\n-#endif\n+#define TIME_MAX UINTMAX_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n\nUINTMAX_MAX is already used git-compat-util.h\n\n-- Hannes\n\n"},{"id":"317935","messageId":"c6bcc382-f526-cf0c-8181-3985216e6c2b@kdbg.org","threadId":"45241","inReplyTo":"fea2df0e1ff5869572cf756d75fd3468d184457f.1493042239.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 6/8] Introduce a new data type for timestamps","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2017-04-26T16:43:50Z","receivedAt":"2017-04-26T16:44:04Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 24.04.2017 um 15:58 schrieb Johannes Schindelin:\n> diff --git a/archive-tar.c b/archive-tar.c\n> index 380e3aedd23..695339a2369 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n>   */\n>  #if ULONG_MAX == 0xFFFFFFFF\n>  #define USTAR_MAX_SIZE ULONG_MAX\n> -#define USTAR_MAX_MTIME ULONG_MAX\n>  #else\n>  #define USTAR_MAX_SIZE 077777777777UL\n> +#endif\n\nThis part of the hunk is fine: if ULONG_MAX is not 2^32-1, then 2^33-1\nwill fit in a long.\n\n> +#if TIME_MAX == 0xFFFFFFFF\n> +#define USTAR_MAX_MTIME TIME_MAX\n> +#else\n>  #define USTAR_MAX_MTIME 077777777777UL\n>  #endif\n\nBut this is not: just because TIME_MAX is not 32 bits, does not mean that\nlong is also more than 32 bits. We need this:\n\ndiff --git a/archive-tar.c b/archive-tar.c\nindex aadd5865f6..b5d6ce27d3 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -33,7 +33,7 @@ static int write_tar_filter_archive(const struct archiver *ar,\n #if TIME_MAX == 0xFFFFFFFF\n #define USTAR_MAX_MTIME TIME_MAX\n #else\n-#define USTAR_MAX_MTIME 077777777777UL\n+#define USTAR_MAX_MTIME 077777777777ULL\n #endif\n \n /* writes out the whole block, but only if it is full */\n\n"},{"id":"317946","messageId":"alpine.DEB.2.20.1704262108160.3480@virtualbox","threadId":"45241","inReplyTo":"02b74d66-97e6-c633-888a-0c6a628cc5bd@kdbg.org","subject":"Re: [PATCH v5 8/8] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:09:05Z","receivedAt":"2017-04-26T19:09:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Hannes,\n\nOn Wed, 26 Apr 2017, Johannes Sixt wrote:\n\n> Am 24.04.2017 um 15:58 schrieb Johannes Schindelin:\n> >  #define PRIo32 \"o\"\n> >  #endif\n> >  \n> > -typedef unsigned long timestamp_t;\n> > -#define PRItime \"lu\"\n> > -#define parse_timestamp strtoul\n> > +typedef uintmax_t timestamp_t;\n> > +#define PRItime PRIuMAX\n> > +#define parse_timestamp strtoumax\n> > +#ifdef ULLONG_MAX\n> > +#define TIME_MAX ULLONG_MAX\n> > +#else\n> >  #define TIME_MAX ULONG_MAX\n> > +#endif\n> >  \n> >  #ifndef PATH_SEP\n> >  #define PATH_SEP ':'\n> > \n> \n> I think you should squash in this:\n> \n> diff --git a/git-compat-util.h b/git-compat-util.h\n> index 26d2643667..b5f4a7bb2f 100644\n> --- a/git-compat-util.h\n> +++ b/git-compat-util.h\n> @@ -322,11 +322,7 @@ extern char *gitdirname(char *);\n>  typedef uintmax_t timestamp_t;\n>  #define PRItime PRIuMAX\n>  #define parse_timestamp strtoumax\n> -#ifdef ULLONG_MAX\n> -#define TIME_MAX ULLONG_MAX\n> -#else\n> -#define TIME_MAX ULONG_MAX\n> -#endif\n> +#define TIME_MAX UINTMAX_MAX\n>  \n>  #ifndef PATH_SEP\n>  #define PATH_SEP ':'\n> \n> UINTMAX_MAX is already used git-compat-util.h\n\nGood point. I very much appreciate your fresh eyes here, as I simply\noverlooked this in the humongous task to convert v1 to use uintmax_t\ninstead of time_t.\n\nCiao,\nDscho\n"},{"id":"317953","messageId":"alpine.DEB.2.20.1704262117550.3480@virtualbox","threadId":"45241","inReplyTo":"c6bcc382-f526-cf0c-8181-3985216e6c2b@kdbg.org","subject":"Re: [PATCH v5 6/8] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:18:18Z","receivedAt":"2017-04-26T19:18:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Hannes,\n\nOn Wed, 26 Apr 2017, Johannes Sixt wrote:\n\n> Am 24.04.2017 um 15:58 schrieb Johannes Schindelin:\n> > diff --git a/archive-tar.c b/archive-tar.c\n> > index 380e3aedd23..695339a2369 100644\n> > --- a/archive-tar.c\n> > +++ b/archive-tar.c\n> > @@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n> >   */\n> >  #if ULONG_MAX == 0xFFFFFFFF\n> >  #define USTAR_MAX_SIZE ULONG_MAX\n> > -#define USTAR_MAX_MTIME ULONG_MAX\n> >  #else\n> >  #define USTAR_MAX_SIZE 077777777777UL\n> > +#endif\n> \n> This part of the hunk is fine: if ULONG_MAX is not 2^32-1, then 2^33-1\n> will fit in a long.\n> \n> > +#if TIME_MAX == 0xFFFFFFFF\n> > +#define USTAR_MAX_MTIME TIME_MAX\n> > +#else\n> >  #define USTAR_MAX_MTIME 077777777777UL\n> >  #endif\n> \n> But this is not: just because TIME_MAX is not 32 bits, does not mean that\n> long is also more than 32 bits. We need this:\n> \n> diff --git a/archive-tar.c b/archive-tar.c\n> index aadd5865f6..b5d6ce27d3 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -33,7 +33,7 @@ static int write_tar_filter_archive(const struct archiver *ar,\n>  #if TIME_MAX == 0xFFFFFFFF\n>  #define USTAR_MAX_MTIME TIME_MAX\n>  #else\n> -#define USTAR_MAX_MTIME 077777777777UL\n> +#define USTAR_MAX_MTIME 077777777777ULL\n>  #endif\n>  \n>  /* writes out the whole block, but only if it is full */\n\nRight! Thank you, v6 coming up,\nDscho\n"},{"id":"317955","messageId":"cover.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493042239.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 0/8] Introduce timestamp_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:20:43Z","receivedAt":"2017-04-26T19:21:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git v2.9.2 was released in a hurry to accomodate for platforms like\nWindows, where the `unsigned long` data type is 32-bit even for 64-bit\nsetups.\n\nThe quick fix was to simply disable all the testing with \"absurd\" future\ndates.\n\nHowever, we can do much better than that, as we already make use of\n64-bit data types internally. There is no good reason why we should not\nuse the same for timestamps. Hence, let's use uintmax_t for timestamps.\n\nNote: while the `time_t` data type exists and is meant to be used for\ntimestamps, on 32-bit Linux it is *still* 32-bit. An earlier iteration\nused `time_t` for that reason, but it came with a few serious downsides:\nas `time_t` can be signed (and indeed, on Windows it is an int64_t),\nGit's expectation that 0 is the minimal value would no longer hold true,\nintroducing its own set of interesting challenges. Besides, if we *can*\nhandle far in the future timestamps (except for formatting them using\nthe system libraries), it is more consistent to do so.\n\nThe upside of using `uintmax_t` for timestamps is that we do a much\nbetter job to support far in the future timestamps across all platforms,\nincluding 32-bit ones. The downside is that those platforms that use a\n32-bit `time_t` will barf when parsing or formatting those timestamps.\n\nHannes Sixt found two more improvements which I incorporated into this\niteration.\n\nChanges since v5:\n\n- use UINTMAX_MAX as TIME_MAX instead of rolling funny ULLONG_MAX games\n  (thanks Hannes Sixt)\n\n- mark the large constant in archive-tar.c as unsigned long long, as we\n  cannot know that unsigned long is large enough (again, thanks Hannes\n  Sixt)\n\n\nJohannes Schindelin (8):\n  ref-filter: avoid using `unsigned long` for catch-all data type\n  t0006 & t5000: prepare for 64-bit timestamps\n  t0006 & t5000: skip \"far in the future\" test when time_t is too\n    limited\n  Specify explicitly where we parse timestamps\n  Introduce a new \"printf format\" for timestamps\n  Introduce a new data type for timestamps\n  Abort if the system time cannot handle one of our timestamps\n  Use uintmax_t for timestamps\n\n Documentation/technical/api-parse-options.txt |   8 +-\n archive-tar.c                                 |   7 +-\n archive-zip.c                                 |  12 ++-\n archive.h                                     |   2 +-\n builtin/am.c                                  |   4 +-\n builtin/blame.c                               |  14 ++--\n builtin/fsck.c                                |   6 +-\n builtin/gc.c                                  |   2 +-\n builtin/log.c                                 |   4 +-\n builtin/merge-base.c                          |   2 +-\n builtin/name-rev.c                            |   6 +-\n builtin/pack-objects.c                        |   4 +-\n builtin/prune.c                               |   4 +-\n builtin/receive-pack.c                        |  14 ++--\n builtin/reflog.c                              |  24 +++---\n builtin/rev-list.c                            |   2 +-\n builtin/rev-parse.c                           |   2 +-\n builtin/show-branch.c                         |   4 +-\n builtin/worktree.c                            |   4 +-\n bundle.c                                      |   4 +-\n cache.h                                       |  14 ++--\n commit.c                                      |  18 ++--\n commit.h                                      |   2 +-\n config.c                                      |   2 +-\n credential-cache--daemon.c                    |  12 +--\n date.c                                        | 113 ++++++++++++++------------\n fetch-pack.c                                  |   8 +-\n fsck.c                                        |   2 +-\n git-compat-util.h                             |   5 ++\n http-backend.c                                |   4 +-\n parse-options-cb.c                            |   4 +-\n pretty.c                                      |   4 +-\n reachable.c                                   |   9 +-\n reachable.h                                   |   4 +-\n ref-filter.c                                  |  22 ++---\n reflog-walk.c                                 |   8 +-\n refs.c                                        |  14 ++--\n refs.h                                        |   8 +-\n refs/files-backend.c                          |   8 +-\n revision.c                                    |   6 +-\n revision.h                                    |   4 +-\n sha1_name.c                                   |   6 +-\n t/helper/test-date.c                          |  18 ++--\n t/helper/test-parse-options.c                 |   4 +-\n t/helper/test-ref-store.c                     |   4 +-\n t/t0006-date.sh                               |   4 +-\n t/t5000-tar-tree.sh                           |   6 +-\n t/test-lib.sh                                 |   3 +\n tag.c                                         |   6 +-\n tag.h                                         |   2 +-\n upload-pack.c                                 |   8 +-\n vcs-svn/fast_export.c                         |   8 +-\n vcs-svn/fast_export.h                         |   4 +-\n vcs-svn/svndump.c                             |   2 +-\n wt-status.c                                   |   2 +-\n 55 files changed, 257 insertions(+), 220 deletions(-)\n\n\nbase-commit: e2cb6ab84c94f147f1259260961513b40c36108a\nPublished-As: https://github.com/dscho/git/releases/tag/time_t-may-be-int64-v6\nFetch-It-Via: git fetch https://github.com/dscho/git time_t-may-be-int64-v6\n\nInterdiff vs v5:\n\n diff --git a/archive-tar.c b/archive-tar.c\n index 695339a2369..319a5b1c7cd 100644\n --- a/archive-tar.c\n +++ b/archive-tar.c\n @@ -28,7 +28,7 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  #if ULONG_MAX == 0xFFFFFFFF\n  #define USTAR_MAX_SIZE ULONG_MAX\n  #else\n -#define USTAR_MAX_SIZE 077777777777UL\n +#define USTAR_MAX_SIZE 077777777777ULL\n  #endif\n  #if TIME_MAX == 0xFFFFFFFF\n  #define USTAR_MAX_MTIME TIME_MAX\n diff --git a/git-compat-util.h b/git-compat-util.h\n index b66995685af..f366180f4b9 100644\n --- a/git-compat-util.h\n +++ b/git-compat-util.h\n @@ -322,11 +322,7 @@ extern char *gitdirname(char *);\n  typedef uintmax_t timestamp_t;\n  #define PRItime PRIuMAX\n  #define parse_timestamp strtoumax\n -#ifdef ULLONG_MAX\n -#define TIME_MAX ULLONG_MAX\n -#else\n -#define TIME_MAX ULONG_MAX\n -#endif\n +#define TIME_MAX UINTMAX_MAX\n  \n  #ifndef PATH_SEP\n  #define PATH_SEP ':'\n\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n"},{"id":"317956","messageId":"alpine.DEB.2.20.1704262123080.3480@virtualbox","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 1/8] ref-filter: avoid using `unsigned long` for catch-all data type","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:26:16Z","receivedAt":"2017-04-26T19:26:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"In its `atom_value` struct, the ref-filter source code wants to store\ndifferent values in a field called `ul` (for `unsigned long`), e.g.\ntimestamps.\n\nHowever, as we are about to switch the data type of timestamps away from\n`unsigned long` (because it may be 32-bit even when `time_t` is 64-bit),\nthat data type is not large enough.\n\nSimply change that field to use `uintmax_t` instead.\n\nThis patch is a bit larger than the mere change of the data type\nbecause the field's name was tied to its data type, which has been fixed\nat the same time.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ref-filter.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3a640448fd8..92871266001 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -351,7 +351,7 @@ struct ref_formatting_state {\n struct atom_value {\n \tconst char *s;\n \tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);\n-\tunsigned long ul; /* used for sorting when not FIELD_STR */\n+\tuintmax_t value; /* used for sorting when not FIELD_STR */\n \tstruct used_atom *atom;\n };\n \n@@ -723,7 +723,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object\n \t\tif (!strcmp(name, \"objecttype\"))\n \t\t\tv->s = typename(obj->type);\n \t\telse if (!strcmp(name, \"objectsize\")) {\n-\t\t\tv->ul = sz;\n+\t\t\tv->value = sz;\n \t\t\tv->s = xstrfmt(\"%lu\", sz);\n \t\t}\n \t\telse if (deref)\n@@ -770,8 +770,8 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object\n \t\t\tv->s = xstrdup(oid_to_hex(&commit->tree->object.oid));\n \t\t}\n \t\telse if (!strcmp(name, \"numparent\")) {\n-\t\t\tv->ul = commit_list_count(commit->parents);\n-\t\t\tv->s = xstrfmt(\"%lu\", v->ul);\n+\t\t\tv->value = commit_list_count(commit->parents);\n+\t\t\tv->s = xstrfmt(\"%lu\", (unsigned long)v->value);\n \t\t}\n \t\telse if (!strcmp(name, \"parent\")) {\n \t\t\tstruct commit_list *parents;\n@@ -875,11 +875,11 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\n \t\tgoto bad;\n \tv->s = xstrdup(show_date(timestamp, tz, &date_mode));\n-\tv->ul = timestamp;\n+\tv->value = timestamp;\n \treturn;\n  bad:\n \tv->s = \"\";\n-\tv->ul = 0;\n+\tv->value = 0;\n }\n \n /* See grab_values */\n@@ -1941,9 +1941,9 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru\n \telse if (cmp_type == FIELD_STR)\n \t\tcmp = cmp_fn(va->s, vb->s);\n \telse {\n-\t\tif (va->ul < vb->ul)\n+\t\tif (va->value < vb->value)\n \t\t\tcmp = -1;\n-\t\telse if (va->ul == vb->ul)\n+\t\telse if (va->value == vb->value)\n \t\t\tcmp = cmp_fn(a->refname, b->refname);\n \t\telse\n \t\t\tcmp = 1;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317957","messageId":"7a71eddcd9c27661c29673e32f8ff7167240aff8.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 2/8] t0006 & t5000: prepare for 64-bit timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:26:23Z","receivedAt":"2017-04-26T19:26:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned longs. On 32-bit\nplatforms, as well as on Windows, unsigned long is not large enough to\ncapture dates that are \"absurdly far in the future\".\n\nIt is perfectly valid by the C standard, of course, for the `long` data\ntype to refer to 32-bit integers. That is why the `time_t` data type\nexists: so that it can be 64-bit even if `long` is 32-bit. Git's source\ncode simply uses an incorrect data type for timestamps, is all.\n\nThe earlier quick fix 6b9c38e14cd (t0006: skip \"far in the future\" test\nwhen unsigned long is not long enough, 2016-07-11) papered over this\nissue simply by skipping the respective test cases on platforms where\nthey would fail due to the data type in use.\n\nThis quick fix, however, tests for *long* to be 64-bit or not. What we\nneed, though, is a test that says whether *whatever data type we use for\ntimestamps* is 64-bit or not.\n\nThe same quick fix was used to handle the similar problem where Git's\nsource code uses `unsigned long` to represent size, instead of `size_t`,\nconflating the two issues.\n\nSo let's just add another prerequisite to test specifically whether\ntimestamps are represented by a 64-bit data type or not. Later, after we\nswitch to a larger data type, we can flip that prerequisite to test\n`time_t` instead of `long`.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 6 +++---\n t/test-lib.sh        | 2 ++\n 4 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 506054bcd5d..4727bea255c 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -4,7 +4,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date relative [time_t]...\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n-\"  test-date approxidate [date]...\\n\";\n+\"  test-date approxidate [date]...\\n\"\n+\"  test-date is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -93,6 +94,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_dates(argv+1, &now);\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n+\telse if (!strcmp(*argv, \"is64bit\"))\n+\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex c0c910867d7..9539b425ffb 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" LONG_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" LONG_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 886b6953e40..997aa9dea28 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -390,7 +390,7 @@ test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our huge size' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n+test_expect_success TIME_IS_64BIT 'set up repository with far-future commit' '\n \trm -f .git/index &&\n \techo content >file &&\n \tgit add file &&\n@@ -398,11 +398,11 @@ test_expect_success LONG_IS_64BIT 'set up repository with far-future commit' '\n \t\tgit commit -m \"tempori parendum\"\n '\n \n-test_expect_success LONG_IS_64BIT 'generate tar with future mtime' '\n+test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,LONG_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 13b5696822d..beee1d847ff 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1164,3 +1164,5 @@ build_option () {\n test_lazy_prereq LONG_IS_64BIT '\n \ttest 8 -le \"$(build_option sizeof-long)\"\n '\n+\n+test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317958","messageId":"b914a7e5689991edd275086ba299894c2ba4e2f8.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 3/8] t0006 & t5000: skip \"far in the future\" test when time_t is too limited","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:26:33Z","receivedAt":"2017-04-26T19:27:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code refers to timestamps as unsigned long, which is\nill-defined, as there is no guarantee about the number of bits that\ndata type has.\n\nIn preparation of switching to another data type that is large enough\nto hold \"far in the future\" dates, we need to prepare the t0006-date.sh\nscript for the case where we *still* cannot format those dates if the\nsystem library uses 32-bit time_t.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n t/helper/test-date.c | 5 ++++-\n t/t0006-date.sh      | 4 ++--\n t/t5000-tar-tree.sh  | 2 +-\n t/test-lib.sh        | 1 +\n 4 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 4727bea255c..ac7c66c733b 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -5,7 +5,8 @@ static const char *usage_msg = \"\\n\"\n \"  test-date show:<format> [time_t]...\\n\"\n \"  test-date parse [date]...\\n\"\n \"  test-date approxidate [date]...\\n\"\n-\"  test-date is64bit\\n\";\n+\"  test-date is64bit\\n\"\n+\"  test-date time_t-is64bit\\n\";\n \n static void show_relative_dates(const char **argv, struct timeval *now)\n {\n@@ -96,6 +97,8 @@ int cmd_main(int argc, const char **argv)\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n \t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\telse if (!strcmp(*argv, \"time_t-is64bit\"))\n+\t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\n \t\tusage(usage_msg);\n \treturn 0;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 9539b425ffb..42d4ea61ef5 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_show unix-local \"$TIME\" '1466000000'\n \n # arbitrary time absurdly far in the future\n FUTURE=\"5758122296 -0400\"\n-check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT\n-check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT\n+check_show iso       \"$FUTURE\" \"2152-06-19 18:24:56 -0400\" TIME_IS_64BIT,TIME_T_IS_64BIT\n+check_show iso-local \"$FUTURE\" \"2152-06-19 22:24:56 +0000\" TIME_IS_64BIT,TIME_T_IS_64BIT\n \n check_parse() {\n \techo \"$1 -> $2\" >expect\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 997aa9dea28..fe2d4f15a73 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -402,7 +402,7 @@ test_expect_success TIME_IS_64BIT 'generate tar with future mtime' '\n \tgit archive HEAD >future.tar\n '\n \n-test_expect_success TAR_HUGE,TIME_IS_64BIT 'system tar can read our future mtime' '\n+test_expect_success TAR_HUGE,TIME_IS_64BIT,TIME_T_IS_64BIT 'system tar can read our future mtime' '\n \techo 4147 >expect &&\n \ttar_info future.tar | cut -d\" \" -f2 >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex beee1d847ff..8d25cb7c183 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1166,3 +1166,4 @@ test_lazy_prereq LONG_IS_64BIT '\n '\n \n test_lazy_prereq TIME_IS_64BIT 'test-date is64bit'\n+test_lazy_prereq TIME_T_IS_64BIT 'test-date time_t-is64bit'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317959","messageId":"d6c1709475927a55c5bb0e6ce9d0b6be20b05735.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 4/8] Specify explicitly where we parse timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:26:58Z","receivedAt":"2017-04-26T19:27:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code represents all timestamps as `unsigned\nlong`. In preparation for using a more appropriate data type, let's\nintroduce a symbol `parse_timestamp` (currently being defined to\n`strtoul`) where appropriate, so that we can later easily switch to,\nsay, use `strtoull()` instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/am.c           | 2 +-\n builtin/receive-pack.c | 4 ++--\n bundle.c               | 2 +-\n commit.c               | 6 +++---\n date.c                 | 6 +++---\n fsck.c                 | 2 +-\n git-compat-util.h      | 2 ++\n pretty.c               | 2 +-\n ref-filter.c           | 2 +-\n refs/files-backend.c   | 2 +-\n t/helper/test-date.c   | 2 +-\n tag.c                  | 4 ++--\n upload-pack.c          | 2 +-\n 13 files changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 805f56cec2f..ffb7a6355fb 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -886,7 +886,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\t\tchar *end;\n \n \t\t\terrno = 0;\n-\t\t\ttimestamp = strtoul(str, &end, 10);\n+\t\t\ttimestamp = parse_timestamp(str, &end, 10);\n \t\t\tif (errno)\n \t\t\t\treturn error(_(\"invalid timestamp\"));\n \ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex f96834f42c9..d25a57931f8 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -534,7 +534,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n \t}\n-\tstamp = strtoul(nonce, &bohmac, 10);\n+\tstamp = parse_timestamp(nonce, &bohmac, 10);\n \tif (bohmac == nonce || bohmac[0] != '-') {\n \t\tretval = NONCE_BAD;\n \t\tgoto leave;\n@@ -552,7 +552,7 @@ static const char *check_nonce(const char *buf, size_t len)\n \t * would mean it was issued by another server with its clock\n \t * skewed in the future.\n \t */\n-\tostamp = strtoul(push_cert_nonce, NULL, 10);\n+\tostamp = parse_timestamp(push_cert_nonce, NULL, 10);\n \tnonce_stamp_slop = (long)ostamp - (long)stamp;\n \n \tif (nonce_stamp_slop_limit &&\ndiff --git a/bundle.c b/bundle.c\nindex bbf4efa0a0a..f43bfcf5ff3 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -227,7 +227,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tline = memchr(line, '>', lineend ? lineend - line : buf + size - line);\n \tif (!line++)\n \t\tgoto out;\n-\tdate = strtoul(line, NULL, 10);\n+\tdate = parse_timestamp(line, NULL, 10);\n \tresult = (revs->max_age == -1 || revs->max_age < date) &&\n \t\t(revs->min_age == -1 || revs->min_age > date);\n out:\ndiff --git a/commit.c b/commit.c\nindex 73c78c2b80c..0d2d0fa1984 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -89,8 +89,8 @@ static unsigned long parse_commit_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n static struct commit_graft **commit_graft;\n@@ -607,7 +607,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \t    !ident.date_begin || !ident.date_end)\n \t\tgoto fail_exit; /* malformed \"author\" line */\n \n-\tdate = strtoul(ident.date_begin, &date_end, 10);\n+\tdate = parse_timestamp(ident.date_begin, &date_end, 10);\n \tif (date_end != ident.date_end)\n \t\tgoto fail_exit; /* malformed date */\n \t*(author_date_slab_at(author_date, commit)) = date;\ndiff --git a/date.c b/date.c\nindex a996331f5b3..495c207c64f 100644\n--- a/date.c\n+++ b/date.c\n@@ -510,7 +510,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \tchar *end;\n \tunsigned long num;\n \n-\tnum = strtoul(date, &end, 10);\n+\tnum = parse_timestamp(date, &end, 10);\n \n \t/*\n \t * Seconds since 1970? We trigger on that for any numbers with\n@@ -658,7 +658,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n-\tstamp = strtoul(date, &end, 10);\n+\tstamp = parse_timestamp(date, &end, 10);\n \tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = strtoul(date, &end, 10);\n+\tunsigned long number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\ndiff --git a/fsck.c b/fsck.c\nindex e6152e4e6d4..d589341cddf 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -691,7 +691,7 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option\n \tp++;\n \tif (*p == '0' && p[1] != ' ')\n \t\treturn report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, \"invalid author/committer line - zero-padded date\");\n-\tif (date_overflows(strtoul(p, &end, 10)))\n+\tif (date_overflows(parse_timestamp(p, &end, 10)))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, \"invalid author/committer line - date causes integer overflow\");\n \tif ((end == p || *end != ' '))\n \t\treturn report(options, obj, FSCK_MSG_BAD_DATE, \"invalid author/committer line - bad date\");\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex bd04564a69a..d78cc36dd1a 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,8 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define parse_timestamp strtoul\n+\n #ifndef PATH_SEP\n #define PATH_SEP ':'\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex d0f86f5d85c..24fb0c79062 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -409,7 +409,7 @@ const char *show_ident_date(const struct ident_split *ident,\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\n-\t\tdate = strtoul(ident->date_begin, NULL, 10);\n+\t\tdate = parse_timestamp(ident->date_begin, NULL, 10);\n \tif (date_overflows(date))\n \t\tdate = 0;\n \telse {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 92871266001..c7836ae07bd 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -868,7 +868,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \n \tif (!eoemail)\n \t\tgoto bad;\n-\ttimestamp = strtoul(eoemail + 2, &zone, 10);\n+\ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n \tif (timestamp == ULONG_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex c9d900fd128..801d26468e0 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3247,7 +3247,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n \t    parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||\n \t    !(email_end = strchr(p, '>')) ||\n \t    email_end[1] != ' ' ||\n-\t    !(timestamp = strtoul(email_end + 2, &message, 10)) ||\n+\t    !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||\n \t    !message || message[0] != ' ' ||\n \t    (message[1] != '+' && message[1] != '-') ||\n \t    !isdigit(message[2]) || !isdigit(message[3]) ||\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex ac7c66c733b..52d1fc34454 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -34,7 +34,7 @@ static void show_dates(const char **argv, const char *format)\n \t\t * Do not use our normal timestamp parsing here, as the point\n \t\t * is to test the formatting code in isolation.\n \t\t */\n-\t\tt = strtol(*argv, &arg, 10);\n+\t\tt = parse_timestamp(*argv, &arg, 10);\n \t\twhile (*arg == ' ')\n \t\t\targ++;\n \t\ttz = atoi(arg);\ndiff --git a/tag.c b/tag.c\nindex 243d1fdbbcb..9b6725e02c9 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -110,8 +110,8 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)\n \t\t/* nada */;\n \tif (buf >= tail)\n \t\treturn 0;\n-\t/* dateptr < buf && buf[-1] == '\\n', so strtoul will stop at buf-1 */\n-\treturn strtoul(dateptr, NULL, 10);\n+\t/* dateptr < buf && buf[-1] == '\\n', so parsing will stop at buf-1 */\n+\treturn parse_timestamp(dateptr, NULL, 10);\n }\n \n int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ffb028d6231..f17f4dd1233 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -775,7 +775,7 @@ static void receive_needs(void)\n \t\t}\n \t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n \t\t\tchar *end = NULL;\n-\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tdeepen_since = parse_timestamp(arg, &end, 0);\n \t\t\tif (!end || *end || !deepen_since ||\n \t\t\t    /* revisions.c's max_age -1 is special */\n \t\t\t    deepen_since == -1)\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317960","messageId":"1950879477c86363f94add858394cc880d802ba6.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 5/8] Introduce a new \"printf format\" for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:29:26Z","receivedAt":"2017-04-26T19:29:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Currently, Git's source code treats all timestamps as if they were\nunsigned longs. Therefore, it is okay to write \"%lu\" when printing them.\n\nThere is a substantial problem with that, though: at least on Windows,\ntime_t is *larger* than unsigned long, and hence we will want to switch\naway from the ill-specified `unsigned long` data type.\n\nSo let's introduce the pseudo format \"PRItime\" (currently simply being\ndefined to \"lu\") to make it easier to change the data type used for\ntimestamps.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/blame.c               |  6 +++---\n builtin/fsck.c                |  2 +-\n builtin/log.c                 |  2 +-\n builtin/receive-pack.c        |  4 ++--\n builtin/rev-list.c            |  2 +-\n builtin/rev-parse.c           |  2 +-\n date.c                        | 26 +++++++++++++-------------\n fetch-pack.c                  |  2 +-\n git-compat-util.h             |  1 +\n refs/files-backend.c          |  2 +-\n t/helper/test-date.c          |  2 +-\n t/helper/test-parse-options.c |  2 +-\n t/helper/test-ref-store.c     |  2 +-\n upload-pack.c                 |  2 +-\n vcs-svn/fast_export.c         |  4 ++--\n 15 files changed, 31 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 07506a3e457..e4b3c7b0ebf 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1727,11 +1727,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \tget_commit_info(suspect->commit, &ci, 1);\n \tprintf(\"author %s\\n\", ci.author.buf);\n \tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n-\tprintf(\"author-time %lu\\n\", ci.author_time);\n+\tprintf(\"author-time %\"PRItime\"\\n\", ci.author_time);\n \tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n \tprintf(\"committer %s\\n\", ci.committer.buf);\n \tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n-\tprintf(\"committer-time %lu\\n\", ci.committer_time);\n+\tprintf(\"committer-time %\"PRItime\"\\n\", ci.committer_time);\n \tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n \tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n@@ -1844,7 +1844,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n \n \tstrbuf_reset(&time_buf);\n \tif (show_raw_time) {\n-\t\tstrbuf_addf(&time_buf, \"%lu %s\", time, tz_str);\n+\t\tstrbuf_addf(&time_buf, \"%\"PRItime\" %s\", time, tz_str);\n \t}\n \telse {\n \t\tconst char *time_str;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex b5e13a45560..c233eda21c8 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -407,7 +407,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n \t\t\tif (timestamp && name_objects)\n \t\t\t\tadd_decoration(fsck_walk_options.object_names,\n \t\t\t\t\tobj,\n-\t\t\t\t\txstrfmt(\"%s@{%ld}\", refname, timestamp));\n+\t\t\t\t\txstrfmt(\"%s@{%\"PRItime\"}\", refname, timestamp));\n \t\t\tobj->used = 1;\n \t\t\tmark_object_reachable(obj);\n \t\t} else {\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b3b10cc1edb..f93ef6c7100 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -910,7 +910,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)\n static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tstrbuf_addf(&buf, \"%s.%lu.git.%s\", base,\n+\tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n \t\t    (unsigned long) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex d25a57931f8..ab718f4402c 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -459,12 +459,12 @@ static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n \n-\tstrbuf_addf(&buf, \"%s:%lu\", path, stamp);\n+\tstrbuf_addf(&buf, \"%s:%\"PRItime, path, stamp);\n \thmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;\n \tstrbuf_release(&buf);\n \n \t/* RFC 2104 5. HMAC-SHA1-80 */\n-\tstrbuf_addf(&buf, \"%lu-%.*s\", stamp, 20, sha1_to_hex(sha1));\n+\tstrbuf_addf(&buf, \"%\"PRItime\"-%.*s\", stamp, 20, sha1_to_hex(sha1));\n \treturn strbuf_detach(&buf, NULL);\n }\n \ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex bcf77f0b8a2..3b292c99bda 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -80,7 +80,7 @@ static void show_commit(struct commit *commit, void *data)\n \t}\n \n \tif (info->show_timestamp)\n-\t\tprintf(\"%lu \", commit->date);\n+\t\tprintf(\"%\"PRItime\" \", commit->date);\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 05133309106..b4509002435 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -218,7 +218,7 @@ static void show_datestring(const char *flag, const char *datestr)\n \t/* date handling requires both flags and revs */\n \tif ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))\n \t\treturn;\n-\tbuffer = xstrfmt(\"%s%lu\", flag, approxidate(datestr));\n+\tbuffer = xstrfmt(\"%s%\"PRItime, flag, approxidate(datestr));\n \tshow(buffer);\n \tfree(buffer);\n }\ndiff --git a/date.c b/date.c\nindex 495c207c64f..5c33dfd8ee7 100644\n--- a/date.c\n+++ b/date.c\n@@ -100,41 +100,41 @@ void show_date_relative(unsigned long time, int tz,\n \tdiff = now->tv_sec - time;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu second ago\", \"%lu seconds ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" second ago\", \"%\"PRItime\" seconds ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into minutes */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 90) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu minute ago\", \"%lu minutes ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" minute ago\", \"%\"PRItime\" minutes ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Turn it into hours */\n \tdiff = (diff + 30) / 60;\n \tif (diff < 36) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu hour ago\", \"%lu hours ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" hour ago\", \"%\"PRItime\" hours ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* We deal with number of days from here on */\n \tdiff = (diff + 12) / 24;\n \tif (diff < 14) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu day ago\", \"%lu days ago\", diff), diff);\n+\t\t\t Q_(\"%\"PRItime\" day ago\", \"%\"PRItime\" days ago\", diff), diff);\n \t\treturn;\n \t}\n \t/* Say weeks for the past 10 weeks or so */\n \tif (diff < 70) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu week ago\", \"%lu weeks ago\", (diff + 3) / 7),\n+\t\t\t Q_(\"%\"PRItime\" week ago\", \"%\"PRItime\" weeks ago\", (diff + 3) / 7),\n \t\t\t (diff + 3) / 7);\n \t\treturn;\n \t}\n \t/* Say months for the past 12 months or so */\n \tif (diff < 365) {\n \t\tstrbuf_addf(timebuf,\n-\t\t\t Q_(\"%lu month ago\", \"%lu months ago\", (diff + 15) / 30),\n+\t\t\t Q_(\"%\"PRItime\" month ago\", \"%\"PRItime\" months ago\", (diff + 15) / 30),\n \t\t\t (diff + 15) / 30);\n \t\treturn;\n \t}\n@@ -145,20 +145,20 @@ void show_date_relative(unsigned long time, int tz,\n \t\tunsigned long months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&sb, Q_(\"%lu year\", \"%lu years\", years), years);\n+\t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n \t\t\tstrbuf_addf(timebuf,\n \t\t\t\t /* TRANSLATORS: \"%s\" is \"<n> years\" */\n-\t\t\t\t Q_(\"%s, %lu month ago\", \"%s, %lu months ago\", months),\n+\t\t\t\t Q_(\"%s, %\"PRItime\" month ago\", \"%s, %\"PRItime\" months ago\", months),\n \t\t\t\t sb.buf, months);\n \t\t\tstrbuf_release(&sb);\n \t\t} else\n \t\t\tstrbuf_addf(timebuf,\n-\t\t\t\t Q_(\"%lu year ago\", \"%lu years ago\", years), years);\n+\t\t\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", years), years);\n \t\treturn;\n \t}\n \t/* Otherwise, just years. Centuries is probably overkill. */\n \tstrbuf_addf(timebuf,\n-\t\t Q_(\"%lu year ago\", \"%lu years ago\", (diff + 183) / 365),\n+\t\t Q_(\"%\"PRItime\" year ago\", \"%\"PRItime\" years ago\", (diff + 183) / 365),\n \t\t (diff + 183) / 365);\n }\n \n@@ -179,7 +179,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_UNIX) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu\", time);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime, time);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -188,7 +188,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\tstrbuf_addf(&timebuf, \"%\"PRItime\" %+05d\", time, tz);\n \t\treturn timebuf.buf;\n \t}\n \n@@ -643,7 +643,7 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n \t\toffset = -offset;\n \t\tsign = '-';\n \t}\n-\tstrbuf_addf(buf, \"%lu %c%02d%02d\", date, sign, offset / 60, offset % 60);\n+\tstrbuf_addf(buf, \"%\"PRItime\" %c%02d%02d\", date, sign, offset / 60, offset % 60);\n }\n \n /*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex afb8b050248..6004cea60d4 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -395,7 +395,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n-\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n \t\tint i;\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex d78cc36dd1a..b2451a12d54 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,6 +319,7 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+#define PRItime \"lu\"\n #define parse_timestamp strtoul\n \n #ifndef PATH_SEP\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 801d26468e0..4e9e3628716 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -4135,7 +4135,7 @@ static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n \t\t\tprintf(\"prune %s\", message);\n \t} else {\n \t\tif (cb->newlog) {\n-\t\t\tfprintf(cb->newlog, \"%s %s %s %lu %+05d\\t%s\",\n+\t\t\tfprintf(cb->newlog, \"%s %s %s %\"PRItime\" %+05d\\t%s\",\n \t\t\t\toid_to_hex(ooid), oid_to_hex(noid),\n \t\t\t\temail, timestamp, tz, message);\n \t\t\toidcpy(&cb->last_kept_oid, noid);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 52d1fc34454..269040f028f 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -53,7 +53,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \n \t\tstrbuf_reset(&result);\n \t\tparse_date(*argv, &result);\n-\t\tif (sscanf(result.buf, \"%lu %d\", &t, &tz) == 2)\n+\t\tif (sscanf(result.buf, \"%\"PRItime\" %d\", &t, &tz) == 2)\n \t\t\tprintf(\"%s -> %s\\n\",\n \t\t\t       *argv, show_date(t, tz, DATE_MODE(ISO8601)));\n \t\telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex a01430c24bd..7d93627e454 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -161,7 +161,7 @@ int cmd_main(int argc, const char **argv)\n \tshow(&expect, &ret, \"boolean: %d\", boolean);\n \tshow(&expect, &ret, \"integer: %d\", integer);\n \tshow(&expect, &ret, \"magnitude: %lu\", magnitude);\n-\tshow(&expect, &ret, \"timestamp: %lu\", timestamp);\n+\tshow(&expect, &ret, \"timestamp: %\"PRItime, timestamp);\n \tshow(&expect, &ret, \"string: %s\", string ? string : \"(not set)\");\n \tshow(&expect, &ret, \"abbrev: %d\", abbrev);\n \tshow(&expect, &ret, \"verbose: %d\", verbose);\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex 2d84c45ffe9..a436bfdb053 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -141,7 +141,7 @@ static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n \t\t       const char *committer, unsigned long timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n-\tprintf(\"%s %s %s %lu %d %s\\n\",\n+\tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\n \t       oid_to_hex(old_oid), oid_to_hex(new_oid),\n \t       committer, timestamp, tz, msg);\n \treturn 0;\ndiff --git a/upload-pack.c b/upload-pack.c\nindex f17f4dd1233..4966f0b8a09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -863,7 +863,7 @@ static void receive_needs(void)\n \n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n-\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\t\targv_array_pushf(&av, \"--max-age=%\"PRItime, deepen_since);\n \t\tif (deepen_not.nr) {\n \t\t\targv_array_push(&av, \"--not\");\n \t\t\tfor (i = 0; i < deepen_not.nr; i++) {\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 97cba39cdf5..6c9f2866d8b 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -73,7 +73,7 @@ void fast_export_begin_note(uint32_t revision, const char *author,\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n \tprintf(\"commit %s\\n\", note_ref);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\", author, author, \"local\", timestamp);\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\", author, author, \"local\", timestamp);\n \tprintf(\"data %\"PRIuMAX\"\\n\", (uintmax_t)loglen);\n \tfwrite(log, loglen, 1, stdout);\n \tif (firstnote) {\n@@ -107,7 +107,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,\n \t}\n \tprintf(\"commit %s\\n\", local_ref);\n \tprintf(\"mark :%\"PRIu32\"\\n\", revision);\n-\tprintf(\"committer %s <%s@%s> %lu +0000\\n\",\n+\tprintf(\"committer %s <%s@%s> %\"PRItime\" +0000\\n\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *author ? author : \"nobody\",\n \t\t   *uuid ? uuid : \"local\", timestamp);\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317961","messageId":"5a17f0ed846b1b894ac023bc8694b6f5c428ff15.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 6/8] Introduce a new data type for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:29:31Z","receivedAt":"2017-04-26T19:29:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git's source code assumes that unsigned long is at least as precise as\ntime_t. Which is incorrect, and causes a lot of problems, in particular\nwhere unsigned long is only 32-bit (notably on Windows, even in 64-bit\nversions).\n\nSo let's just use a more appropriate data type instead. In preparation\nfor this, we introduce the new `timestamp_t` data type.\n\nBy necessity, this is a very, very large patch, as it has to replace all\ntimestamps' data type in one go.\n\nAs we will use a data type that is not necessarily identical to `time_t`,\nwe need to be very careful to use `time_t` whenever we interact with the\nsystem functions, and `timestamp_t` everywhere else.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/technical/api-parse-options.txt |  8 ++--\n archive-tar.c                                 |  7 ++-\n archive-zip.c                                 | 12 ++++-\n archive.h                                     |  2 +-\n builtin/am.c                                  |  2 +-\n builtin/blame.c                               |  8 ++--\n builtin/fsck.c                                |  4 +-\n builtin/gc.c                                  |  2 +-\n builtin/log.c                                 |  2 +-\n builtin/merge-base.c                          |  2 +-\n builtin/name-rev.c                            |  6 +--\n builtin/pack-objects.c                        |  4 +-\n builtin/prune.c                               |  4 +-\n builtin/receive-pack.c                        |  6 +--\n builtin/reflog.c                              | 24 +++++-----\n builtin/show-branch.c                         |  4 +-\n builtin/worktree.c                            |  4 +-\n bundle.c                                      |  2 +-\n cache.h                                       | 14 +++---\n commit.c                                      | 12 ++---\n commit.h                                      |  2 +-\n config.c                                      |  2 +-\n credential-cache--daemon.c                    | 12 ++---\n date.c                                        | 66 +++++++++++++--------------\n fetch-pack.c                                  |  6 +--\n git-compat-util.h                             |  2 +\n http-backend.c                                |  4 +-\n parse-options-cb.c                            |  4 +-\n pretty.c                                      |  2 +-\n reachable.c                                   |  9 ++--\n reachable.h                                   |  4 +-\n ref-filter.c                                  |  4 +-\n reflog-walk.c                                 |  8 ++--\n refs.c                                        | 14 +++---\n refs.h                                        |  8 ++--\n refs/files-backend.c                          |  4 +-\n revision.c                                    |  6 +--\n revision.h                                    |  4 +-\n sha1_name.c                                   |  6 +--\n t/helper/test-date.c                          |  8 ++--\n t/helper/test-parse-options.c                 |  2 +-\n t/helper/test-ref-store.c                     |  2 +-\n tag.c                                         |  2 +-\n tag.h                                         |  2 +-\n upload-pack.c                                 |  4 +-\n vcs-svn/fast_export.c                         |  4 +-\n vcs-svn/fast_export.h                         |  4 +-\n vcs-svn/svndump.c                             |  2 +-\n wt-status.c                                   |  2 +-\n 49 files changed, 170 insertions(+), 158 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 36768b479e1..829b5581105 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,13 +183,13 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &int_var, description)`::\n+`OPT_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n-`OPT_EXPIRY_DATE(short, long, &int_var, description)`::\n+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n-\tThe timestamp is put into `int_var`.\n+\tThe timestamp is put into `timestamp_t_var`.\n \n `OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::\n \tIntroduce an option with argument.\ndiff --git a/archive-tar.c b/archive-tar.c\nindex 380e3aedd23..319a5b1c7cd 100644\n--- a/archive-tar.c\n+++ b/archive-tar.c\n@@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n  */\n #if ULONG_MAX == 0xFFFFFFFF\n #define USTAR_MAX_SIZE ULONG_MAX\n-#define USTAR_MAX_MTIME ULONG_MAX\n #else\n-#define USTAR_MAX_SIZE 077777777777UL\n+#define USTAR_MAX_SIZE 077777777777ULL\n+#endif\n+#if TIME_MAX == 0xFFFFFFFF\n+#define USTAR_MAX_MTIME TIME_MAX\n+#else\n #define USTAR_MAX_MTIME 077777777777UL\n #endif\n \ndiff --git a/archive-zip.c b/archive-zip.c\nindex b429a8d974a..68df3d64402 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -545,9 +545,17 @@ static void write_zip_trailer(const unsigned char *sha1)\n \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n }\n \n-static void dos_time(time_t *time, int *dos_date, int *dos_time)\n+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n {\n-\tstruct tm *t = localtime(time);\n+\ttime_t time;\n+\tstruct tm *t;\n+\n+\tif (date_overflows(*timestamp))\n+\t\tdie(\"timestamp too large for this system: %\"PRItime,\n+\t\t    *timestamp);\n+\ttime = (time_t)*timestamp;\n+\tt = localtime(&time);\n+\t*timestamp = time;\n \n \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n \t            (t->tm_year + 1900 - 1980) * 512;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e2c..62d1d82c1af 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -9,7 +9,7 @@ struct archiver_args {\n \tstruct tree *tree;\n \tconst unsigned char *commit_sha1;\n \tconst struct commit *commit;\n-\ttime_t time;\n+\ttimestamp_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n \tunsigned int worktree_attributes : 1;\ndiff --git a/builtin/am.c b/builtin/am.c\nindex ffb7a6355fb..8bdbd53b618 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -881,7 +881,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n \t\t\tfprintf(out, \"From: %s\\n\", str);\n \t\telse if (skip_prefix(sb.buf, \"# Date \", &str)) {\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tlong tz, tz2;\n \t\t\tchar *end;\n \ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex e4b3c7b0ebf..f00eda16378 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1561,13 +1561,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n struct commit_info {\n \tstruct strbuf author;\n \tstruct strbuf author_mail;\n-\tunsigned long author_time;\n+\ttimestamp_t author_time;\n \tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n \tstruct strbuf committer;\n \tstruct strbuf committer_mail;\n-\tunsigned long committer_time;\n+\ttimestamp_t committer_time;\n \tstruct strbuf committer_tz;\n \n \tstruct strbuf summary;\n@@ -1578,7 +1578,7 @@ struct commit_info {\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n \tstruct strbuf *name, struct strbuf *mail,\n-\tunsigned long *time, struct strbuf *tz)\n+\ttimestamp_t *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n \tsize_t len, maillen, namelen;\n@@ -1837,7 +1837,7 @@ static void assign_blame(struct scoreboard *sb, int opt)\n \tstop_progress(&pi.progress);\n }\n \n-static const char *format_time(unsigned long time, const char *tz_str,\n+static const char *format_time(timestamp_t time, const char *tz_str,\n \t\t\t       int show_raw_time)\n {\n \tstatic struct strbuf time_buf = STRBUF_INIT;\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex c233eda21c8..32a32e55c85 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -397,7 +397,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,\n static int default_refs;\n \n static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tstruct object *obj;\n \n@@ -418,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,\n }\n \n static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tconst char *refname = cb_data;\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex 91f7696a85e..f484eda43ca 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -33,7 +33,7 @@ static int aggressive_window = 250;\n static int gc_auto_threshold = 6700;\n static int gc_auto_pack_limit = 50;\n static int detach_auto = 1;\n-static unsigned long gc_log_expire_time;\n+static timestamp_t gc_log_expire_time;\n static const char *gc_log_expire = \"1.day.ago\";\n static const char *prune_expire = \"2.weeks.ago\";\n static const char *prune_worktrees_expire = \"3.months.ago\";\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f93ef6c7100..fd3d10ec217 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -911,7 +911,7 @@ static void gen_message_id(struct rev_info *info, char *base)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstrbuf_addf(&buf, \"%s.%\"PRItime\".git.%s\", base,\n-\t\t    (unsigned long) time(NULL),\n+\t\t    (timestamp_t) time(NULL),\n \t\t    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex cfe2a796f85..8ed96391c1d 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -132,7 +132,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n }\n \n static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, unsigned long timestamp,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cbdata)\n {\n \tstruct rev_collect *revs = cbdata;\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 92a5d8a5d26..44374750170 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -10,7 +10,7 @@\n \n typedef struct rev_name {\n \tconst char *tip_name;\n-\tunsigned long taggerdate;\n+\ttimestamp_t taggerdate;\n \tint generation;\n \tint distance;\n } rev_name;\n@@ -21,7 +21,7 @@ static long cutoff = LONG_MAX;\n #define MERGE_TRAVERSAL_WEIGHT 65535\n \n static void name_rev(struct commit *commit,\n-\t\tconst char *tip_name, unsigned long taggerdate,\n+\t\tconst char *tip_name, timestamp_t taggerdate,\n \t\tint generation, int distance,\n \t\tint deref)\n {\n@@ -146,7 +146,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo\n \tstruct name_ref_data *data = cb_data;\n \tint can_abbreviate_output = data->tags_only && data->name_only;\n \tint deref = 0;\n-\tunsigned long taggerdate = ULONG_MAX;\n+\ttimestamp_t taggerdate = TIME_MAX;\n \n \tif (data->tags_only && !starts_with(path, \"refs/tags/\"))\n \t\treturn 0;\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 0fe35d1b5ae..9b4ba8a80d7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -44,7 +44,7 @@ static uint32_t nr_result, nr_written;\n static int non_empty;\n static int reuse_delta = 1, reuse_object = 1;\n static int keep_unreachable, unpack_unreachable, include_tag;\n-static unsigned long unpack_unreachable_expiration;\n+static timestamp_t unpack_unreachable_expiration;\n static int pack_loose_unreachable;\n static int local;\n static int have_non_local_packs;\n@@ -2675,7 +2675,7 @@ static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)\n static struct oid_array recent_objects;\n \n static int loosened_object_can_be_discarded(const struct object_id *oid,\n-\t\t\t\t\t    unsigned long mtime)\n+\t\t\t\t\t    timestamp_t mtime)\n {\n \tif (!unpack_unreachable_expiration)\n \t\treturn 0;\ndiff --git a/builtin/prune.c b/builtin/prune.c\nindex 42633e0c6e6..8dcfecde0f3 100644\n--- a/builtin/prune.c\n+++ b/builtin/prune.c\n@@ -13,7 +13,7 @@ static const char * const prune_usage[] = {\n };\n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n static int show_progress = -1;\n \n static int prune_tmp_file(const char *fullpath)\n@@ -111,7 +111,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)\n \t};\n \tchar *s;\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tsave_commit_buffer = 0;\n \tcheck_replace_refs = 0;\n \tref_paranoia = 1;\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex ab718f4402c..0bb36d584d7 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -78,7 +78,7 @@ static const char *NONCE_OK = \"OK\";\n static const char *NONCE_SLOP = \"SLOP\";\n static const char *nonce_status;\n static long nonce_stamp_slop;\n-static unsigned long nonce_stamp_slop_limit;\n+static timestamp_t nonce_stamp_slop_limit;\n static struct ref_transaction *transaction;\n \n static enum {\n@@ -454,7 +454,7 @@ static void hmac_sha1(unsigned char *out,\n \tgit_SHA1_Final(out, &ctx);\n }\n \n-static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)\n+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tunsigned char sha1[20];\n@@ -496,7 +496,7 @@ static char *find_header(const char *msg, size_t len, const char *key)\n static const char *check_nonce(const char *buf, size_t len)\n {\n \tchar *nonce = find_header(buf, len, \"nonce\");\n-\tunsigned long stamp, ostamp;\n+\ttimestamp_t stamp, ostamp;\n \tchar *bohmac, *expect = NULL;\n \tconst char *retval = NONCE_BAD;\n \ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex 74727757785..4228d9ff4db 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -16,14 +16,14 @@ static const char reflog_delete_usage[] =\n static const char reflog_exists_usage[] =\n \"git reflog exists <ref>\";\n \n-static unsigned long default_reflog_expire;\n-static unsigned long default_reflog_expire_unreachable;\n+static timestamp_t default_reflog_expire;\n+static timestamp_t default_reflog_expire_unreachable;\n \n struct cmd_reflog_expire_cb {\n \tstruct rev_info revs;\n \tint stalefix;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tint recno;\n };\n \n@@ -219,7 +219,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)\n static void mark_reachable(struct expire_reflog_policy_cb *cb)\n {\n \tstruct commit_list *pending;\n-\tunsigned long expire_limit = cb->mark_limit;\n+\ttimestamp_t expire_limit = cb->mark_limit;\n \tstruct commit_list *leftover = NULL;\n \n \tfor (pending = cb->mark_list; pending; pending = pending->next)\n@@ -284,7 +284,7 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit\n  * Return true iff the specified reflog entry should be expired.\n  */\n static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n-\t\t\t\t    const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t    const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t    const char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\n@@ -392,8 +392,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus\n \n static struct reflog_expire_cfg {\n \tstruct reflog_expire_cfg *next;\n-\tunsigned long expire_total;\n-\tunsigned long expire_unreachable;\n+\ttimestamp_t expire_total;\n+\ttimestamp_t expire_unreachable;\n \tchar pattern[FLEX_ARRAY];\n } *reflog_expire_cfg, **reflog_expire_cfg_tail;\n \n@@ -415,7 +415,7 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)\n \treturn ent;\n }\n \n-static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)\n+static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)\n {\n \tif (!value)\n \t\treturn config_error_nonbool(var);\n@@ -433,7 +433,7 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)\n {\n \tconst char *pattern, *key;\n \tint pattern_len;\n-\tunsigned long expire;\n+\ttimestamp_t expire;\n \tint slot;\n \tstruct reflog_expire_cfg *ent;\n \n@@ -515,7 +515,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c\n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n {\n \tstruct expire_reflog_policy_cb cb;\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \tint i, status, do_all;\n \tint explicit_expiry = 0;\n \tunsigned int flags = 0;\n@@ -616,7 +616,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\n }\n \n static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct expire_reflog_policy_cb *cb = cb_data;\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 19756595d57..8860f429b06 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -735,7 +735,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tbase = strtoul(reflog_base, &ep, 10);\n \t\t\tif (*ep) {\n \t\t\t\t/* Ah, that is a date spec... */\n-\t\t\t\tunsigned long at;\n+\t\t\t\ttimestamp_t at;\n \t\t\t\tat = approxidate(reflog_base);\n \t\t\t\tread_ref_at(ref, flags, at, -1, oid.hash, NULL,\n \t\t\t\t\t    NULL, NULL, &base);\n@@ -746,7 +746,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t\tchar *logmsg;\n \t\t\tchar *nth_desc;\n \t\t\tconst char *msg;\n-\t\t\tunsigned long timestamp;\n+\t\t\ttimestamp_t timestamp;\n \t\t\tint tz;\n \n \t\t\tif (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 9993ded41aa..74f9b18d40c 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -30,7 +30,7 @@ struct add_opts {\n \n static int show_only;\n static int verbose;\n-static unsigned long expire;\n+static timestamp_t expire;\n \n static int prune_worktree(const char *id, struct strbuf *reason)\n {\n@@ -131,7 +131,7 @@ static int prune(int ac, const char **av, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\texpire = ULONG_MAX;\n+\texpire = TIME_MAX;\n \tac = parse_options(ac, av, prefix, options, worktree_usage, 0);\n \tif (ac)\n \t\tusage_with_options(worktree_usage, options);\ndiff --git a/bundle.c b/bundle.c\nindex f43bfcf5ff3..05e014fc5ab 100644\n--- a/bundle.c\n+++ b/bundle.c\n@@ -211,7 +211,7 @@ static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)\n \tunsigned long size;\n \tenum object_type type;\n \tchar *buf = NULL, *line, *lineend;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tint result = 1;\n \n \tif (revs->max_age == -1 && revs->min_age == -1)\ndiff --git a/cache.h b/cache.h\nindex ef0fe43a9df..e2482a510f7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1478,18 +1478,18 @@ struct date_mode {\n #define DATE_MODE(t) date_mode_from_type(DATE_##t)\n struct date_mode *date_mode_from_type(enum date_mode_type type);\n \n-const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);\n-void show_date_relative(unsigned long time, int tz, const struct timeval *now,\n+const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n+void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);\n-int parse_expiry_date(const char *date, unsigned long *timestamp);\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n+int parse_expiry_date(const char *date, timestamp_t *timestamp);\n void datestamp(struct strbuf *out);\n #define approxidate(s) approxidate_careful((s), NULL)\n-unsigned long approxidate_careful(const char *, int *);\n-unsigned long approxidate_relative(const char *date, const struct timeval *now);\n+timestamp_t approxidate_careful(const char *, int *);\n+timestamp_t approxidate_relative(const char *date, const struct timeval *now);\n void parse_date_format(const char *format, struct date_mode *mode);\n-int date_overflows(unsigned long date);\n+int date_overflows(timestamp_t date);\n \n #define IDENT_STRICT\t       1\n #define IDENT_NO_DATE\t       2\ndiff --git a/commit.c b/commit.c\nindex 0d2d0fa1984..99a62b90ee2 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -66,7 +66,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \treturn commit;\n }\n \n-static unsigned long parse_commit_date(const char *buf, const char *tail)\n+static timestamp_t parse_commit_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \n@@ -473,8 +473,8 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm\n \n static int commit_list_compare_by_date(const void *a, const void *b)\n {\n-\tunsigned long a_date = ((const struct commit_list *)a)->item->date;\n-\tunsigned long b_date = ((const struct commit_list *)b)->item->date;\n+\ttimestamp_t a_date = ((const struct commit_list *)a)->item->date;\n+\ttimestamp_t b_date = ((const struct commit_list *)b)->item->date;\n \tif (a_date < b_date)\n \t\treturn 1;\n \tif (a_date > b_date)\n@@ -598,7 +598,7 @@ static void record_author_date(struct author_date_slab *author_date,\n \tconst char *ident_line;\n \tsize_t ident_len;\n \tchar *date_end;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \n \tident_line = find_commit_header(buffer, \"author\", &ident_len);\n \tif (!ident_line)\n@@ -621,8 +621,8 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,\n {\n \tconst struct commit *a = a_, *b = b_;\n \tstruct author_date_slab *author_date = cb_data;\n-\tunsigned long a_date = *(author_date_slab_at(author_date, a));\n-\tunsigned long b_date = *(author_date_slab_at(author_date, b));\n+\ttimestamp_t a_date = *(author_date_slab_at(author_date, a));\n+\ttimestamp_t b_date = *(author_date_slab_at(author_date, b));\n \n \t/* newer commits with larger date first */\n \tif (a_date < b_date)\ndiff --git a/commit.h b/commit.h\nindex 7b1986d5c8a..c9d887b5e53 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -17,7 +17,7 @@ struct commit {\n \tstruct object object;\n \tvoid *util;\n \tunsigned int index;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tstruct commit_list *parents;\n \tstruct tree *tree;\n };\ndiff --git a/config.c b/config.c\nindex 0daaed338ea..4cf644b9fbf 100644\n--- a/config.c\n+++ b/config.c\n@@ -1943,7 +1943,7 @@ int git_config_get_expiry(const char *key, const char **output)\n \tif (ret)\n \t\treturn ret;\n \tif (strcmp(*output, \"now\")) {\n-\t\tunsigned long now = approxidate(\"now\");\n+\t\ttimestamp_t now = approxidate(\"now\");\n \t\tif (approxidate(*output) >= now)\n \t\t\tgit_die_config(key, _(\"Invalid %s: '%s'\"), key, *output);\n \t}\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 46c5937526a..f3814cc47a0 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -8,7 +8,7 @@ static struct tempfile socket_file;\n \n struct credential_cache_entry {\n \tstruct credential item;\n-\tunsigned long expiration;\n+\ttimestamp_t expiration;\n };\n static struct credential_cache_entry *entries;\n static int entries_nr;\n@@ -47,12 +47,12 @@ static void remove_credential(const struct credential *c)\n \t\te->expiration = 0;\n }\n \n-static int check_expirations(void)\n+static timestamp_t check_expirations(void)\n {\n-\tstatic unsigned long wait_for_entry_until;\n+\tstatic timestamp_t wait_for_entry_until;\n \tint i = 0;\n-\tunsigned long now = time(NULL);\n-\tunsigned long next = (unsigned long)-1;\n+\ttimestamp_t now = time(NULL);\n+\ttimestamp_t next = TIME_MAX;\n \n \t/*\n \t * Initially give the client 30 seconds to actually contact us\n@@ -159,7 +159,7 @@ static void serve_one_client(FILE *in, FILE *out)\n static int serve_cache_loop(int fd)\n {\n \tstruct pollfd pfd;\n-\tunsigned long wakeup;\n+\ttimestamp_t wakeup;\n \n \twakeup = check_expirations();\n \tif (!wakeup)\ndiff --git a/date.c b/date.c\nindex 5c33dfd8ee7..92ab31aa441 100644\n--- a/date.c\n+++ b/date.c\n@@ -39,7 +39,7 @@ static const char *weekday_names[] = {\n \t\"Sundays\", \"Mondays\", \"Tuesdays\", \"Wednesdays\", \"Thursdays\", \"Fridays\", \"Saturdays\"\n };\n \n-static time_t gm_time_t(unsigned long time, int tz)\n+static time_t gm_time_t(timestamp_t time, int tz)\n {\n \tint minutes;\n \n@@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int tz)\n  * thing, which means that tz -0100 is passed in as the integer -100,\n  * even though it means \"sixty minutes off\"\n  */\n-static struct tm *time_to_tm(unsigned long time, int tz)\n+static struct tm *time_to_tm(timestamp_t time, int tz)\n {\n \ttime_t t = gm_time_t(time, tz);\n \treturn gmtime(&t);\n@@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)\n  * What value of \"tz\" was in effect back then at \"time\" in the\n  * local timezone?\n  */\n-static int local_tzoffset(unsigned long time)\n+static int local_tzoffset(timestamp_t time)\n {\n \ttime_t t, t_local;\n \tstruct tm tm;\n@@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n-void show_date_relative(unsigned long time, int tz,\n+void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n {\n-\tunsigned long diff;\n+\ttimestamp_t diff;\n \tif (now->tv_sec < time) {\n \t\tstrbuf_addstr(timebuf, _(\"in the future\"));\n \t\treturn;\n@@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,\n \t}\n \t/* Give years and months for 5 years or so */\n \tif (diff < 1825) {\n-\t\tunsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n-\t\tunsigned long years = totalmonths / 12;\n-\t\tunsigned long months = totalmonths % 12;\n+\t\ttimestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);\n+\t\ttimestamp_t years = totalmonths / 12;\n+\t\ttimestamp_t months = totalmonths % 12;\n \t\tif (months) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \t\t\tstrbuf_addf(&sb, Q_(\"%\"PRItime\" year\", \"%\"PRItime\" years\", years), years);\n@@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n-const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n+const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n@@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,\n \treturn 0;\n }\n \n-static int match_multi_number(unsigned long num, char c, const char *date,\n+static int match_multi_number(timestamp_t num, char c, const char *date,\n \t\t\t      char *end, struct tm *tm, time_t now)\n {\n \tstruct tm now_tm;\n@@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n {\n \tint n;\n \tchar *end;\n-\tunsigned long num;\n+\ttimestamp_t num;\n \n \tnum = parse_timestamp(date, &end, 10);\n \n@@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)\n \treturn end - date;\n }\n \n-static void date_string(unsigned long date, int offset, struct strbuf *buf)\n+static void date_string(timestamp_t date, int offset, struct strbuf *buf)\n {\n \tint sign = '+';\n \n@@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)\n  * Parse a string like \"0 +0000\" as ancient timestamp near epoch, but\n  * only when it appears not as part of any other string.\n  */\n-static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)\n+static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tchar *end;\n-\tunsigned long stamp;\n+\ttimestamp_t stamp;\n \tint ofs;\n \n \tif (*date < '0' || '9' < *date)\n \t\treturn -1;\n \tstamp = parse_timestamp(date, &end, 10);\n-\tif (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))\n+\tif (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))\n \t\treturn -1;\n \tdate = end + 2;\n \tofs = strtol(date, &end, 10);\n@@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,\n \n /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822\n    (i.e. English) day/month names, and it doesn't work correctly with %z. */\n-int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n+int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)\n {\n \tstruct tm tm;\n \tint tm_gmt;\n-\tunsigned long dummy_timestamp;\n+\ttimestamp_t dummy_timestamp;\n \tint dummy_offset;\n \n \tif (!timestamp)\n@@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)\n \treturn 0; /* success */\n }\n \n-int parse_expiry_date(const char *date, unsigned long *timestamp)\n+int parse_expiry_date(const char *date, timestamp_t *timestamp)\n {\n \tint errors = 0;\n \n@@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \t\t * of the past, and there is nothing from the future\n \t\t * to be kept.\n \t\t */\n-\t\t*timestamp = ULONG_MAX;\n+\t\t*timestamp = TIME_MAX;\n \telse\n \t\t*timestamp = approxidate_careful(date, &errors);\n \n@@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)\n \n int parse_date(const char *date, struct strbuf *result)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tif (parse_date_basic(date, &timestamp, &offset))\n \t\treturn -1;\n@@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)\n  * Relative time update (eg \"2 days ago\").  If we haven't set the time\n  * yet, we need to set it from current time.\n  */\n-static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)\n+static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)\n {\n \ttime_t n;\n \n@@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,\n \t\t\t\t     time_t now)\n {\n \tchar *end;\n-\tunsigned long number = parse_timestamp(date, &end, 10);\n+\ttimestamp_t number = parse_timestamp(date, &end, 10);\n \n \tswitch (*end) {\n \tcase ':':\n@@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-static unsigned long approxidate_str(const char *date,\n-\t\t\t\t     const struct timeval *tv,\n-\t\t\t\t     int *error_ret)\n+static timestamp_t approxidate_str(const char *date,\n+\t\t\t\t   const struct timeval *tv,\n+\t\t\t\t   int *error_ret)\n {\n \tint number = 0;\n \tint touched = 0;\n@@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,\n \tpending_number(&tm, &number);\n \tif (!touched)\n \t\t*error_ret = 1;\n-\treturn update_tm(&tm, &now, 0);\n+\treturn (timestamp_t)update_tm(&tm, &now, 0);\n }\n \n-unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+timestamp_t approxidate_relative(const char *date, const struct timeval *tv)\n {\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint errors = 0;\n \n@@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n \treturn approxidate_str(date, tv, &errors);\n }\n \n-unsigned long approxidate_careful(const char *date, int *error_ret)\n+timestamp_t approxidate_careful(const char *date, int *error_ret)\n {\n \tstruct timeval tv;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint offset;\n \tint dummy = 0;\n \tif (!error_ret)\n@@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \n-int date_overflows(unsigned long t)\n+int date_overflows(timestamp_t t)\n {\n \ttime_t sys;\n \n-\t/* If we overflowed our unsigned long, that's bad... */\n-\tif (t == ULONG_MAX)\n+\t/* If we overflowed our timestamp data type, that's bad... */\n+\tif ((uintmax_t)t >= TIME_MAX)\n \t\treturn 1;\n \n \t/*\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 6004cea60d4..5f15dd2c390 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -394,7 +394,7 @@ static int find_common(struct fetch_pack_args *args,\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n \tif (args->deepen_since) {\n-\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\ttimestamp_t max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %\"PRItime, max_age);\n \t}\n \tif (args->deepen_not) {\n@@ -583,7 +583,7 @@ static int mark_complete_oid(const char *refname, const struct object_id *oid,\n }\n \n static void mark_recent_complete_commits(struct fetch_pack_args *args,\n-\t\t\t\t\t unsigned long cutoff)\n+\t\t\t\t\t timestamp_t cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n \t\tprint_verbose(args, _(\"Marking %s as complete\"),\n@@ -670,7 +670,7 @@ static int everything_local(struct fetch_pack_args *args,\n {\n \tstruct ref *ref;\n \tint retval;\n-\tunsigned long cutoff = 0;\n+\ttimestamp_t cutoff = 0;\n \n \tsave_commit_buffer = 0;\n \ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex b2451a12d54..594100e7652 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,8 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n+typedef unsigned long timestamp_t;\n #define PRItime \"lu\"\n #define parse_timestamp strtoul\n+#define TIME_MAX ULONG_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\ndiff --git a/http-backend.c b/http-backend.c\nindex eef0a361f4f..d6ea6075339 100644\n--- a/http-backend.c\n+++ b/http-backend.c\n@@ -90,7 +90,7 @@ static void hdr_int(struct strbuf *hdr, const char *name, uintmax_t value)\n \tstrbuf_addf(hdr, \"%s: %\" PRIuMAX \"\\r\\n\", name, value);\n }\n \n-static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)\n+static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)\n {\n \tconst char *value = show_date(when, 0, DATE_MODE(RFC2822));\n \thdr_str(hdr, name, value);\n@@ -105,7 +105,7 @@ static void hdr_nocache(struct strbuf *hdr)\n \n static void hdr_cache_forever(struct strbuf *hdr)\n {\n-\tunsigned long now = time(NULL);\n+\ttimestamp_t now = time(NULL);\n \thdr_date(hdr, \"Date\", now);\n \thdr_date(hdr, \"Expires\", now + 31536000);\n \thdr_str(hdr, \"Cache-Control\", \"public, max-age=31536000\");\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 7419780a9b6..a6810f295cb 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -31,14 +31,14 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\t*(unsigned long *)(opt->value) = approxidate(arg);\n+\t*(timestamp_t *)(opt->value) = approxidate(arg);\n \treturn 0;\n }\n \n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n-\treturn parse_expiry_date(arg, (unsigned long *)opt->value);\n+\treturn parse_expiry_date(arg, (timestamp_t *)opt->value);\n }\n \n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\ndiff --git a/pretty.c b/pretty.c\nindex 24fb0c79062..587d48371b0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -405,7 +405,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,\n const char *show_ident_date(const struct ident_split *ident,\n \t\t\t    const struct date_mode *mode)\n {\n-\tunsigned long date = 0;\n+\ttimestamp_t date = 0;\n \tlong tz = 0;\n \n \tif (ident->date_begin && ident->date_end)\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4fc..682418f5d23 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -55,11 +55,11 @@ static void mark_commit(struct commit *c, void *data)\n \n struct recent_data {\n \tstruct rev_info *revs;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n };\n \n static void add_recent_object(const struct object_id *oid,\n-\t\t\t      unsigned long mtime,\n+\t\t\t      timestamp_t mtime,\n \t\t\t      struct recent_data *data)\n {\n \tstruct object *obj;\n@@ -139,7 +139,7 @@ static int add_recent_packed(const struct object_id *oid,\n }\n \n int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t   unsigned long timestamp)\n+\t\t\t\t\t   timestamp_t timestamp)\n {\n \tstruct recent_data data;\n \tint r;\n@@ -156,8 +156,7 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n }\n \n void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t    unsigned long mark_recent,\n-\t\t\t    struct progress *progress)\n+\t\t\t    timestamp_t mark_recent, struct progress *progress)\n {\n \tstruct connectivity_progress cp;\n \ndiff --git a/reachable.h b/reachable.h\nindex d23efc36ec5..3c00fa0526c 100644\n--- a/reachable.h\n+++ b/reachable.h\n@@ -3,8 +3,8 @@\n \n struct progress;\n extern int add_unseen_recent_objects_to_traversal(struct rev_info *revs,\n-\t\t\t\t\t\t  unsigned long timestamp);\n+\t\t\t\t\t\t  timestamp_t timestamp);\n extern void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n-\t\t\t\t   unsigned long mark_recent, struct progress *);\n+\t\t\t\t   timestamp_t mark_recent, struct progress *);\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex c7836ae07bd..1fc5e9970db 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -849,7 +849,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n {\n \tconst char *eoemail = strstr(buf, \"> \");\n \tchar *zone;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tlong tz;\n \tstruct date_mode date_mode = { DATE_NORMAL };\n \tconst char *formatp;\n@@ -869,7 +869,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam\n \tif (!eoemail)\n \t\tgoto bad;\n \ttimestamp = parse_timestamp(eoemail + 2, &zone, 10);\n-\tif (timestamp == ULONG_MAX)\n+\tif (timestamp == TIME_MAX)\n \t\tgoto bad;\n \ttz = strtol(zone, NULL, 10);\n \tif ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 99679f58255..3ca5ed8415a 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -12,7 +12,7 @@ struct complete_reflogs {\n \tstruct reflog_info {\n \t\tstruct object_id ooid, noid;\n \t\tchar *email;\n-\t\tunsigned long timestamp;\n+\t\ttimestamp_t timestamp;\n \t\tint tz;\n \t\tchar *message;\n \t} *items;\n@@ -20,7 +20,7 @@ struct complete_reflogs {\n };\n \n static int read_one_reflog(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct complete_reflogs *array = cb_data;\n@@ -69,7 +69,7 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)\n }\n \n static int get_reflog_recno_by_time(struct complete_reflogs *array,\n-\tunsigned long timestamp)\n+\ttimestamp_t timestamp)\n {\n \tint i;\n \tfor (i = array->nr - 1; i >= 0; i--)\n@@ -141,7 +141,7 @@ void init_reflog_walk(struct reflog_walk_info **info)\n int add_reflog_for_walk(struct reflog_walk_info *info,\n \t\tstruct commit *commit, const char *name)\n {\n-\tunsigned long timestamp = 0;\n+\ttimestamp_t timestamp = 0;\n \tint recno = -1;\n \tstruct string_list_item *item;\n \tstruct complete_reflogs *reflogs;\ndiff --git a/refs.c b/refs.c\nindex a3d5f42e373..f4944a658c7 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -712,7 +712,7 @@ int is_branch(const char *refname)\n \n struct read_ref_at_cb {\n \tconst char *refname;\n-\tunsigned long at_time;\n+\ttimestamp_t at_time;\n \tint cnt;\n \tint reccnt;\n \tunsigned char *sha1;\n@@ -721,15 +721,15 @@ struct read_ref_at_cb {\n \tunsigned char osha1[20];\n \tunsigned char nsha1[20];\n \tint tz;\n-\tunsigned long date;\n+\ttimestamp_t date;\n \tchar **msg;\n-\tunsigned long *cutoff_time;\n+\ttimestamp_t *cutoff_time;\n \tint *cutoff_tz;\n \tint *cutoff_cnt;\n };\n \n static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -776,7 +776,7 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,\n }\n \n static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  const char *email, timestamp_t timestamp,\n \t\t\t\t  int tz, const char *message, void *cb_data)\n {\n \tstruct read_ref_at_cb *cb = cb_data;\n@@ -796,9 +796,9 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid\n \treturn 1;\n }\n \n-int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,\n+int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n \tstruct read_ref_at_cb cb;\n \ndiff --git a/refs.h b/refs.h\nindex 49e97d7d5fd..2b80d37fd34 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -317,9 +317,9 @@ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err\n \n /** Reads log for the value of ref during at_time. **/\n int read_ref_at(const char *refname, unsigned int flags,\n-\t\tunsigned long at_time, int cnt,\n+\t\ttimestamp_t at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n-\t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n+\t\ttimestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt);\n \n /** Check if a particular reflog exists */\n int refs_reflog_exists(struct ref_store *refs, const char *refname);\n@@ -356,7 +356,7 @@ int delete_reflog(const char *refname);\n /* iterate over reflog entries */\n typedef int each_reflog_ent_fn(\n \t\tstruct object_id *old_oid, struct object_id *new_oid,\n-\t\tconst char *committer, unsigned long timestamp,\n+\t\tconst char *committer, timestamp_t timestamp,\n \t\tint tz, const char *msg, void *cb_data);\n \n int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n@@ -616,7 +616,7 @@ typedef void reflog_expiry_prepare_fn(const char *refname,\n typedef int reflog_expiry_should_prune_fn(unsigned char *osha1,\n \t\t\t\t\t  unsigned char *nsha1,\n \t\t\t\t\t  const char *email,\n-\t\t\t\t\t  unsigned long timestamp, int tz,\n+\t\t\t\t\t  timestamp_t timestamp, int tz,\n \t\t\t\t\t  const char *message, void *cb_data);\n typedef void reflog_expiry_cleanup_fn(void *cb_data);\n \ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 4e9e3628716..4d9d1144569 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3237,7 +3237,7 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c\n {\n \tstruct object_id ooid, noid;\n \tchar *email_end, *message;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tint tz;\n \tconst char *p = sb->buf;\n \n@@ -4118,7 +4118,7 @@ struct expire_reflog_cb {\n };\n \n static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t     const char *email, unsigned long timestamp, int tz,\n+\t\t\t     const char *email, timestamp_t timestamp, int tz,\n \t\t\t     const char *message, void *cb_data)\n {\n \tstruct expire_reflog_cb *cb = cb_data;\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f73..8a8c1789c7b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -884,7 +884,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n /* How many extra uninteresting commits we want to see.. */\n #define SLOP 5\n \n-static int still_interesting(struct commit_list *src, unsigned long date, int slop,\n+static int still_interesting(struct commit_list *src, timestamp_t date, int slop,\n \t\t\t     struct commit **interesting_cache)\n {\n \t/*\n@@ -1018,7 +1018,7 @@ static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n-\tunsigned long date = ~0ul;\n+\ttimestamp_t date = TIME_MAX;\n \tstruct commit_list *list = revs->commits;\n \tstruct commit_list *newlist = NULL;\n \tstruct commit_list **p = &newlist;\n@@ -1215,7 +1215,7 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n }\n \n static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *email, timestamp_t timestamp, int tz,\n \t\tconst char *message, void *cb_data)\n {\n \thandle_one_reflog_commit(ooid, cb_data);\ndiff --git a/revision.h b/revision.h\nindex 14886ec92b4..0d9e68b36e9 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -181,8 +181,8 @@ struct rev_info {\n \t/* special limits */\n \tint skip_count;\n \tint max_count;\n-\tunsigned long max_age;\n-\tunsigned long min_age;\n+\ttimestamp_t max_age;\n+\ttimestamp_t min_age;\n \tint min_parents;\n \tint max_parents;\n \tint (*include_check)(struct commit *, void *);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 8eec9f7c1bb..35c1e2a9e32 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -660,8 +660,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,\n \n \tif (reflog_len) {\n \t\tint nth, i;\n-\t\tunsigned long at_time;\n-\t\tunsigned long co_time;\n+\t\ttimestamp_t at_time;\n+\t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n@@ -1054,7 +1054,7 @@ struct grab_nth_branch_switch_cbdata {\n };\n \n static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *email, unsigned long timestamp, int tz,\n+\t\t\t\t  const char *email, timestamp_t timestamp, int tz,\n \t\t\t\t  const char *message, void *cb_data)\n {\n \tstruct grab_nth_branch_switch_cbdata *cb = cb_data;\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex 269040f028f..f414a3ac670 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -27,7 +27,7 @@ static void show_dates(const char **argv, const char *format)\n \tparse_date_format(format, &mode);\n \tfor (; *argv; argv++) {\n \t\tchar *arg;\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\t/*\n@@ -48,7 +48,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n \tstruct strbuf result = STRBUF_INIT;\n \n \tfor (; *argv; argv++) {\n-\t\tunsigned long t;\n+\t\ttimestamp_t t;\n \t\tint tz;\n \n \t\tstrbuf_reset(&result);\n@@ -65,7 +65,7 @@ static void parse_dates(const char **argv, struct timeval *now)\n static void parse_approxidate(const char **argv, struct timeval *now)\n {\n \tfor (; *argv; argv++) {\n-\t\ttime_t t;\n+\t\ttimestamp_t t;\n \t\tt = approxidate_relative(*argv, now);\n \t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(ISO8601)));\n \t}\n@@ -96,7 +96,7 @@ int cmd_main(int argc, const char **argv)\n \telse if (!strcmp(*argv, \"approxidate\"))\n \t\tparse_approxidate(argv+1, &now);\n \telse if (!strcmp(*argv, \"is64bit\"))\n-\t\treturn sizeof(unsigned long) == 8 ? 0 : 1;\n+\t\treturn sizeof(timestamp_t) == 8 ? 0 : 1;\n \telse if (!strcmp(*argv, \"time_t-is64bit\"))\n \t\treturn sizeof(time_t) == 8 ? 0 : 1;\n \telse\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 7d93627e454..75fe883aac1 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -5,7 +5,7 @@\n static int boolean = 0;\n static int integer = 0;\n static unsigned long magnitude = 0;\n-static unsigned long timestamp;\n+static timestamp_t timestamp;\n static int abbrev = 7;\n static int verbose = -1; /* unspecified */\n static int dry_run = 0, quiet = 0;\ndiff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c\nindex a436bfdb053..9077ec2c330 100644\n--- a/t/helper/test-ref-store.c\n+++ b/t/helper/test-ref-store.c\n@@ -138,7 +138,7 @@ static int cmd_for_each_reflog(struct ref_store *refs, const char **argv)\n }\n \n static int each_reflog(struct object_id *old_oid, struct object_id *new_oid,\n-\t\t       const char *committer, unsigned long timestamp,\n+\t\t       const char *committer, timestamp_t timestamp,\n \t\t       int tz, const char *msg, void *cb_data)\n {\n \tprintf(\"%s %s %s %\"PRItime\" %d %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex 9b6725e02c9..d71b67e8d83 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -97,7 +97,7 @@ struct tag *lookup_tag(const unsigned char *sha1)\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n-static unsigned long parse_tag_date(const char *buf, const char *tail)\n+static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\n \ndiff --git a/tag.h b/tag.h\nindex a5721b6731e..2abb3726fb5 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -9,7 +9,7 @@ struct tag {\n \tstruct object object;\n \tstruct object *tagged;\n \tchar *tag;\n-\tunsigned long date;\n+\ttimestamp_t date;\n };\n \n extern struct tag *lookup_tag(const unsigned char *sha1);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4966f0b8a09..97da13e6a54 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -35,7 +35,7 @@ static const char * const upload_pack_usage[] = {\n #define CLIENT_SHALLOW\t(1u << 18)\n #define HIDDEN_REF\t(1u << 19)\n \n-static unsigned long oldest_have;\n+static timestamp_t oldest_have;\n \n static int deepen_relative;\n static int multi_ack;\n@@ -735,7 +735,7 @@ static void receive_needs(void)\n \tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n-\tunsigned long deepen_since = 0;\n+\ttimestamp_t deepen_since = 0;\n \tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\ndiff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c\nindex 6c9f2866d8b..5a89db30e3f 100644\n--- a/vcs-svn/fast_export.c\n+++ b/vcs-svn/fast_export.c\n@@ -68,7 +68,7 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)\n }\n \n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref)\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref)\n {\n \tstatic int firstnote = 1;\n \tsize_t loglen = strlen(log);\n@@ -93,7 +93,7 @@ static char gitsvnline[MAX_GITSVN_LINE_LEN];\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log,\n \t\t\tconst char *uuid, const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref)\n+\t\t\ttimestamp_t timestamp, const char *local_ref)\n {\n \tstatic const struct strbuf empty = STRBUF_INIT;\n \tif (!log)\ndiff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h\nindex c8b5adb811c..b9a3b71c99f 100644\n--- a/vcs-svn/fast_export.h\n+++ b/vcs-svn/fast_export.h\n@@ -11,10 +11,10 @@ void fast_export_delete(const char *path);\n void fast_export_modify(const char *path, uint32_t mode, const char *dataref);\n void fast_export_note(const char *committish, const char *dataref);\n void fast_export_begin_note(uint32_t revision, const char *author,\n-\t\tconst char *log, unsigned long timestamp, const char *note_ref);\n+\t\tconst char *log, timestamp_t timestamp, const char *note_ref);\n void fast_export_begin_commit(uint32_t revision, const char *author,\n \t\t\tconst struct strbuf *log, const char *uuid,const char *url,\n-\t\t\tunsigned long timestamp, const char *local_ref);\n+\t\t\ttimestamp_t timestamp, const char *local_ref);\n void fast_export_end_commit(uint32_t revision);\n void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);\n void fast_export_buf_to_data(const struct strbuf *data);\ndiff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c\nindex e4b395963b9..1846685a21a 100644\n--- a/vcs-svn/svndump.c\n+++ b/vcs-svn/svndump.c\n@@ -47,7 +47,7 @@ static struct {\n \n static struct {\n \tuint32_t revision;\n-\tunsigned long timestamp;\n+\ttimestamp_t timestamp;\n \tstruct strbuf log, author, note;\n } rev_ctx;\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 03754849626..1b1d644b85f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1387,7 +1387,7 @@ struct grab_1st_switch_cbdata {\n };\n \n static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,\n-\t\t\t   const char *email, unsigned long timestamp, int tz,\n+\t\t\t   const char *email, timestamp_t timestamp, int tz,\n \t\t\t   const char *message, void *cb_data)\n {\n \tstruct grab_1st_switch_cbdata *cb = cb_data;\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317962","messageId":"3f4c005794846ecc80bb4048adda54be2ad23b7a.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 7/8] Abort if the system time cannot handle one of our timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:29:36Z","receivedAt":"2017-04-26T19:29:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"We are about to switch to a new data type for time stamps that is\ndefinitely not smaller or equal, but larger or equal to time_t.\n\nSo before using the system functions to process or format timestamps,\nlet's make extra certain that they can handle what we feed them.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n date.c | 17 +++++++++++++++--\n 1 file changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 92ab31aa441..63fa99685e2 100644\n--- a/date.c\n+++ b/date.c\n@@ -46,7 +46,17 @@ static time_t gm_time_t(timestamp_t time, int tz)\n \tminutes = tz < 0 ? -tz : tz;\n \tminutes = (minutes / 100)*60 + (minutes % 100);\n \tminutes = tz < 0 ? -minutes : minutes;\n-\treturn time + minutes * 60;\n+\n+\tif (minutes > 0) {\n+\t\tif (unsigned_add_overflows(time, minutes * 60))\n+\t\t\tdie(\"Timestamp+tz too large: %\"PRItime\" +%04d\",\n+\t\t\t    time, tz);\n+\t} else if (time < -minutes * 60)\n+\t\tdie(\"Timestamp before Unix epoch: %\"PRItime\" %04d\", time, tz);\n+\ttime += minutes * 60;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\treturn (time_t)time;\n }\n \n /*\n@@ -70,7 +80,10 @@ static int local_tzoffset(timestamp_t time)\n \tstruct tm tm;\n \tint offset, eastwest;\n \n-\tt = time;\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\tt = (time_t)time;\n \tlocaltime_r(&t, &tm);\n \tt_local = tm_to_time_t(&tm);\n \n-- \n2.12.2.windows.2.406.gd14a8f8640f\n\n\n"},{"id":"317963","messageId":"7f9b6db618742a6dae6c491ba52dbe1f9a2bf745.1493234408.git.johannes.schindelin@gmx.de","threadId":"45241","inReplyTo":"cover.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH v6 8/8] Use uintmax_t for timestamps","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-04-26T19:29:42Z","receivedAt":"2017-04-26T19:29:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Previously, we used `unsigned long` for timestamps. This was only a good\nchoice on Linux, where we know implicitly that `unsigned long` is what is\nused for `time_t`.\n\nHowever, we want to use a different data type for timestamps for two\nreasons:\n\n- there is nothing that says that `unsigned long` should be the same data\n  type as `time_t`, and indeed, on 64-bit Windows for example, it is not:\n  `unsigned long` is 32-bit but `time_t` is 64-bit.\n\n- even on 32-bit Linux, where `unsigned long` (and thereby `time_t`) is\n  32-bit, we *want* to be able to encode timestamps in Git that are\n  currently absurdly far in the future, *even if* the system library is\n  not able to format those timestamps into date strings.\n\nSo let's just switch to the maximal integer type available, which should\nbe at least 64-bit for all practical purposes these days. It certainly\ncannot be worse than `unsigned long`, so...\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-compat-util.h | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 594100e7652..f366180f4b9 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -319,10 +319,10 @@ extern char *gitdirname(char *);\n #define PRIo32 \"o\"\n #endif\n \n-typedef unsigned long timestamp_t;\n-#define PRItime \"lu\"\n-#define parse_timestamp strtoul\n-#define TIME_MAX ULONG_MAX\n+typedef uintmax_t timestamp_t;\n+#define PRItime PRIuMAX\n+#define parse_timestamp strtoumax\n+#define TIME_MAX UINTMAX_MAX\n \n #ifndef PATH_SEP\n #define PATH_SEP ':'\n-- \n2.12.2.windows.2.406.gd14a8f8640f\n"},{"id":"318003","messageId":"b6302244-7425-605e-8103-9aa845c03c3e@web.de","threadId":"45241","inReplyTo":"alpine.DEB.2.20.1704260005310.3480@virtualbox","subject":"Re: [PATCH v5 0/8] Introduce timestamp_t for timestamps","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-04-26T22:09:17Z","receivedAt":"2017-04-26T22:09:30Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Hi Dscho,\n\nAm 26.04.2017 um 00:22 schrieb Johannes Schindelin:\n> On Tue, 25 Apr 2017, René Scharfe wrote:\n>> Am 24.04.2017 um 15:57 schrieb Johannes Schindelin:\n>> Can we leave time_t alone and just do the part where you replace\n>> unsigned long with timestamp_t defined as uint64_t?  That should already\n>> help on Windows, correct?  When/if timestamp_t is later changed to a\n>> signed type then we could easily convert the time_t cases to timestamp_t\n>> as well, or the other way around.\n> \n> This patch series leaves time_t alone already, so your wish has been\n> fulfilled preemptively.\n\nSounds good!  It does contain conversions from time_t to timestamp_t in\narchive-zip.c, though.  I'll comment in reply to the relevant patch.\n\n>>> It is arguably a bug to paper over too-large author/committer dates and\n>>> to replace them with Jan 1 1970 without even telling the user that we do\n>>> that, but this is the behavior that t4212 verifies, so I reinstated that\n>>> behavior. The change in behavior was missed because of the missing\n>>> unsigned_add_overflows() test.\n>>\n>> I can't think of many ways to get future time stamps (broken clock,\n>> broken CMOS battery, bit rot, time travel), so I wouldn't expect a\n>> change towards better error reporting to affect a lot of users.  (Not\n>> necessarily as part of this series, of course.)\n> \n> If you want to suggest that we should stop verifying overflows when a\n> complex reasoning can prove that the overflow is not happening in a\n> billion years, I disagree. Not only is it unnecessarily time-consuming to\n> ask readers to perform the complex reasoning, and not only is there enough\n> room for bugs to hide in plain sight (because of the complexity), it also\n> makes the same code harder to reuse in other software where a different\n> timestamp data type was chosen (or inherited from previous Git versions).\n> \n> I'd much rather have easy-to-reason code that does not cause head\n> scratching (like the \"why do we ignore a too large timestamp?\" triggering\n> `if (date_overflows(date)) date = 0;`) than pretending to be smart and\n> clever and make everybody else feel stupid by forcing them through hoops\n> of thinking bubbles until they also reached the conclusion that this\n> actually won't happen. Unless there is a bug in the code.\n\nNo, I meant that the presence of tests does not necessarily cast an\nundesirable behavior into stone, especially if it's hard to trigger\nin real life.  And that improvements thereof can be done later.  In\nother words: It's OK to maintain the same behavior in this series,\nbut cheer up, we may be able to fix the issue eventually.\n\nRené\n"},{"id":"318005","messageId":"615c74de-0a9d-b5ff-f7f2-68feca5d1985@web.de","threadId":"45241","inReplyTo":"fea2df0e1ff5869572cf756d75fd3468d184457f.1493042239.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v5 6/8] Introduce a new data type for timestamps","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2017-04-26T22:32:04Z","receivedAt":"2017-04-26T22:32:17Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 24.04.2017 um 15:58 schrieb Johannes Schindelin:\n> diff --git a/archive-tar.c b/archive-tar.c\n> index 380e3aedd23..695339a2369 100644\n> --- a/archive-tar.c\n> +++ b/archive-tar.c\n> @@ -27,9 +27,12 @@ static int write_tar_filter_archive(const struct archiver *ar,\n>    */\n>   #if ULONG_MAX == 0xFFFFFFFF\n>   #define USTAR_MAX_SIZE ULONG_MAX\n> -#define USTAR_MAX_MTIME ULONG_MAX\n>   #else\n>   #define USTAR_MAX_SIZE 077777777777UL\n> +#endif\n> +#if TIME_MAX == 0xFFFFFFFF\n> +#define USTAR_MAX_MTIME TIME_MAX\n> +#else\n>   #define USTAR_MAX_MTIME 077777777777UL\n>   #endif\n>   \n> diff --git a/archive-zip.c b/archive-zip.c\n> index b429a8d974a..68df3d64402 100644\n> --- a/archive-zip.c\n> +++ b/archive-zip.c\n> @@ -545,9 +545,17 @@ static void write_zip_trailer(const unsigned char *sha1)\n>   \t\twrite_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);\n>   }\n>   \n> -static void dos_time(time_t *time, int *dos_date, int *dos_time)\n> +static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)\n>   {\n> -\tstruct tm *t = localtime(time);\n> +\ttime_t time;\n> +\tstruct tm *t;\n> +\n> +\tif (date_overflows(*timestamp))\n> +\t\tdie(\"timestamp too large for this system: %\"PRItime,\n> +\t\t    *timestamp);\n> +\ttime = (time_t)*timestamp;\n> +\tt = localtime(&time);\n> +\t*timestamp = time;\n>   \n>   \t*dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +\n>   \t            (t->tm_year + 1900 - 1980) * 512;\n> diff --git a/archive.h b/archive.h\n> index 415e0152e2c..62d1d82c1af 100644\n> --- a/archive.h\n> +++ b/archive.h\n> @@ -9,7 +9,7 @@ struct archiver_args {\n>   \tstruct tree *tree;\n>   \tconst unsigned char *commit_sha1;\n>   \tconst struct commit *commit;\n> -\ttime_t time;\n> +\ttimestamp_t time;\n>   \tstruct pathspec pathspec;\n>   \tunsigned int verbose : 1;\n>   \tunsigned int worktree_attributes : 1;\n\ntime_t is converted to timestamp_t here.  Hmm.\n\nTruncation can already occur in archive.c::parse_treeish_arg() when\nassigning commit->date (of type timestamp_t) to archive_time (of type\ntime_t).  The overflow check should either be moved there or the type of\nthe latter variable should be changed, right?\n\nCompilation and tests are still successful on Debian x86 and MinGW64\neven after removing the changes above.  On the former the test \"generate\ntar with future mtime\" in t5000 writes Epoch time stamps in both cases\n(and doesn't notice because tar is unable to handle times after 2038, so\nthat check is skipped), on the latter it emits the correct future dates.\n\nSo what are the benefits of these changes?\n\nUnless I'm missing something (very possible at this time of day) I'd say\ndrop these hunks and let me handle the fallout of the series in archive.\nI was planning on improving its date handling code anyway (eventually)..\n\nRené\n"},{"id":"320295","messageId":"xmqqa868t6yu.fsf_-_@gitster.mtv.corp.google.com","threadId":"45241","inReplyTo":"5a17f0ed846b1b894ac023bc8694b6f5c428ff15.1493234408.git.johannes.schindelin@gmx.de","subject":"[PATCH] name-rev: change a \"long\" variable to timestamp_t","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-05-20T05:47:37Z","receivedAt":"2017-05-20T05:47:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier dddbad72 (\"timestamp_t: a new data type for timestamps\",\n2017-04-26) updated all in-core variables, fields and function\nreturn values that are used to store \"seconds since epoch\" to a new\ntype timestamp_t.  Unfortunately one variable \"cutoff\", which is\nused to keep track of the oldest timestamp of commit we saw on the\ncommand line, was \"long\", and left behind.\n\nUpdate it to timestamp_t as well.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * Noticed while merging the topic 'mg/name-rev-debug' to 'pu'.\n\n builtin/name-rev.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/name-rev.c b/builtin/name-rev.c\nindex 4437475017..1f6fcae121 100644\n--- a/builtin/name-rev.c\n+++ b/builtin/name-rev.c\n@@ -15,7 +15,7 @@ typedef struct rev_name {\n \tint distance;\n } rev_name;\n \n-static long cutoff = LONG_MAX;\n+static timestamp_t cutoff = TIME_MAX;\n \n /* How many generations are maximally preferred over _one_ merge traversal? */\n #define MERGE_TRAVERSAL_WEIGHT 65535\n-- \n2.13.0-439-gd4feae47b3\n\n"},{"id":"320411","messageId":"alpine.DEB.2.21.1.1705221539330.3610@virtualbox","threadId":"45241","inReplyTo":"xmqqa868t6yu.fsf_-_@gitster.mtv.corp.google.com","subject":"Re: [PATCH] name-rev: change a \"long\" variable to timestamp_t","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-05-22T13:39:50Z","receivedAt":"2017-05-22T13:40:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 20 May 2017, Junio C Hamano wrote:\n\n> Earlier dddbad72 (\"timestamp_t: a new data type for timestamps\",\n> 2017-04-26) updated all in-core variables, fields and function\n> return values that are used to store \"seconds since epoch\" to a new\n> type timestamp_t.  Unfortunately one variable \"cutoff\", which is\n> used to keep track of the oldest timestamp of commit we saw on the\n> command line, was \"long\", and left behind.\n> \n> Update it to timestamp_t as well.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nObviously correct. Thanks.\n\nCiao,\nDscho\n"}]}