{"thread":{"id":"20778","subject":"[PATCH 1/2] Add date formatting and parsing functions relative to a given time","startedAt":"2009-08-28T21:04:04Z","lastAt":"2009-08-30T07:51:25Z","messageCount":4,"participants":["Alex Riesen","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"122056","messageId":"20090828210404.GA11867@blimp.localdomain","threadId":"20778","inReplyTo":null,"subject":"[PATCH 1/2] Add date formatting and parsing functions relative to a given time","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T21:04:04Z","receivedAt":"2009-08-28T21:04:04Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"The main purpose is to allow predictable testing of the code.\n---\n\nRebased on current master.\n\n cache.h |    2 +\n date.c  |  150 ++++++++++++++++++++++++++++++++++++--------------------------\n 2 files changed, 89 insertions(+), 63 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex dd7f71e..3fb0166 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -731,9 +731,11 @@ enum date_mode {\n };\n \n const char *show_date(unsigned long time, int timezone, enum date_mode mode);\n+const char *show_date_relative(unsigned long time, int tz, const struct timeval *now);\n int parse_date(const char *date, char *buf, int bufsize);\n void datestamp(char *buf, int bufsize);\n unsigned long approxidate(const char *);\n+unsigned long approxidate_relative(const char *date, const struct timeval *now);\n enum date_mode parse_date_format(const char *format);\n \n #define IDENT_WARN_ON_NO_NAME  1\ndiff --git a/date.c b/date.c\nindex f011692..0840e77 100644\n--- a/date.c\n+++ b/date.c\n@@ -84,6 +84,67 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n+const char *show_date_relative(unsigned long time, int tz, const struct timeval *now)\n+{\n+\tstatic char timebuf[100 /* TODO: can be optimized */];\n+\tunsigned long diff;\n+\tif (now->tv_sec < time)\n+\t\treturn \"in the future\";\n+\tdiff = now->tv_sec - time;\n+\tif (diff < 90) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu seconds ago\", diff);\n+\t\treturn timebuf;\n+\t}\n+\t/* Turn it into minutes */\n+\tdiff = (diff + 30) / 60;\n+\tif (diff < 90) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu minutes ago\", diff);\n+\t\treturn timebuf;\n+\t}\n+\t/* Turn it into hours */\n+\tdiff = (diff + 30) / 60;\n+\tif (diff < 36) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu hours ago\", diff);\n+\t\treturn timebuf;\n+\t}\n+\t/* We deal with number of days from here on */\n+\tdiff = (diff + 12) / 24;\n+\tif (diff < 14) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu days ago\", diff);\n+\t\treturn timebuf;\n+\t}\n+\t/* Say weeks for the past 10 weeks or so */\n+\tif (diff < 70) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu weeks ago\", (diff + 3) / 7);\n+\t\treturn timebuf;\n+\t}\n+\t/* Say months for the past 12 months or so */\n+\tif (diff < 360) {\n+\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu months ago\", (diff + 15) / 30);\n+\t\treturn timebuf;\n+\t}\n+\t/* Give years and months for 5 years or so */\n+\tif (diff < 1825) {\n+\t\tunsigned long years = diff / 365;\n+\t\tunsigned long months = (diff % 365 + 15) / 30;\n+\t\tint n;\n+\t\tn = snprintf(timebuf, sizeof(timebuf), \"%lu year%s\",\n+\t\t\t     years, (years > 1 ? \"s\" : \"\"));\n+\t\tif (months)\n+\t\t\tsnprintf(timebuf + n, sizeof(timebuf) - n,\n+\t\t\t\t \", %lu month%s ago\",\n+\t\t\t\t months, (months > 1 ? \"s\" : \"\"));\n+\t\telse\n+\t\t\tsnprintf(timebuf + n, sizeof(timebuf) - n,\n+\t\t\t\t \" ago\");\n+\t\treturn timebuf;\n+\t}\n+\t/* Otherwise, just years. Centuries is probably overkill. */\n+\tsnprintf(timebuf, sizeof(timebuf), \"%lu years ago\", (diff + 183) / 365);\n+\treturn timebuf;\n+\n+}\n+\n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n \tstruct tm *tm;\n@@ -95,63 +156,9 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)\n \t}\n \n \tif (mode == DATE_RELATIVE) {\n-\t\tunsigned long diff;\n \t\tstruct timeval now;\n \t\tgettimeofday(&now, NULL);\n-\t\tif (now.tv_sec < time)\n-\t\t\treturn \"in the future\";\n-\t\tdiff = now.tv_sec - time;\n-\t\tif (diff < 90) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu seconds ago\", diff);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Turn it into minutes */\n-\t\tdiff = (diff + 30) / 60;\n-\t\tif (diff < 90) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu minutes ago\", diff);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Turn it into hours */\n-\t\tdiff = (diff + 30) / 60;\n-\t\tif (diff < 36) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu hours ago\", diff);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* We deal with number of days from here on */\n-\t\tdiff = (diff + 12) / 24;\n-\t\tif (diff < 14) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu days ago\", diff);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Say weeks for the past 10 weeks or so */\n-\t\tif (diff < 70) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu weeks ago\", (diff + 3) / 7);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Say months for the past 12 months or so */\n-\t\tif (diff < 360) {\n-\t\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu months ago\", (diff + 15) / 30);\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Give years and months for 5 years or so */\n-\t\tif (diff < 1825) {\n-\t\t\tunsigned long years = diff / 365;\n-\t\t\tunsigned long months = (diff % 365 + 15) / 30;\n-\t\t\tint n;\n-\t\t\tn = snprintf(timebuf, sizeof(timebuf), \"%lu year%s\",\n-\t\t\t\t\tyears, (years > 1 ? \"s\" : \"\"));\n-\t\t\tif (months)\n-\t\t\t\tsnprintf(timebuf + n, sizeof(timebuf) - n,\n-\t\t\t\t\t\", %lu month%s ago\",\n-\t\t\t\t\tmonths, (months > 1 ? \"s\" : \"\"));\n-\t\t\telse\n-\t\t\t\tsnprintf(timebuf + n, sizeof(timebuf) - n,\n-\t\t\t\t\t\" ago\");\n-\t\t\treturn timebuf;\n-\t\t}\n-\t\t/* Otherwise, just years. Centuries is probably overkill. */\n-\t\tsnprintf(timebuf, sizeof(timebuf), \"%lu years ago\", (diff + 183) / 365);\n-\t\treturn timebuf;\n+\t\treturn show_date_relative(time, tz, &now);\n \t}\n \n \tif (mode == DATE_LOCAL)\n@@ -866,19 +873,13 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)\n \treturn end;\n }\n \n-unsigned long approxidate(const char *date)\n+static unsigned long approximation(const char *date, const struct timeval *tv)\n {\n \tint number = 0;\n \tstruct tm tm, now;\n-\tstruct timeval tv;\n \ttime_t time_sec;\n-\tchar buffer[50];\n \n-\tif (parse_date(date, buffer, sizeof(buffer)) > 0)\n-\t\treturn strtoul(buffer, NULL, 10);\n-\n-\tgettimeofday(&tv, NULL);\n-\ttime_sec = tv.tv_sec;\n+\ttime_sec = tv->tv_sec;\n \tlocaltime_r(&time_sec, &tm);\n \tnow = tm;\n \tfor (;;) {\n@@ -899,3 +900,26 @@ unsigned long approxidate(const char *date)\n \t\ttm.tm_year--;\n \treturn mktime(&tm);\n }\n+\n+unsigned long approxidate_relative(const char *date, const struct timeval *tv)\n+{\n+\tchar buffer[50];\n+\n+\tif (parse_date(date, buffer, sizeof(buffer)) > 0)\n+\t\treturn strtoul(buffer, NULL, 10);\n+\n+\treturn approximation(date, tv);\n+}\n+\n+unsigned long approxidate(const char *date)\n+{\n+\tstruct timeval tv;\n+\tchar buffer[50];\n+\n+\tif (parse_date(date, buffer, sizeof(buffer)) > 0)\n+\t\treturn strtoul(buffer, NULL, 10);\n+\n+\tgettimeofday(&tv, NULL);\n+\treturn approximation(date, &tv);\n+}\n+\n-- \n1.6.4.1.263.g468a\n"},{"id":"122057","messageId":"20090828210511.GB11867@blimp.localdomain","threadId":"20778","inReplyTo":"20090828210404.GA11867@blimp.localdomain","subject":"[PATCH 2/2] Allow testing of _relative family of time formatting and parsing functions","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T21:05:11Z","receivedAt":"2009-08-28T21:05:11Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"To complement the testability of approxidate.\n---\n test-date.c |   17 +++++++++++++++++\n 1 files changed, 17 insertions(+), 0 deletions(-)\n\ndiff --git a/test-date.c b/test-date.c\nindex 62e8f23..dcc7973 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -4,6 +4,17 @@ int main(int argc, char **argv)\n {\n \tint i;\n \n+\tstruct tm tm;\n+\tstruct timeval when = {0, 0};\n+\ttm.tm_sec  = 0;\n+\ttm.tm_min  = 0;\n+\ttm.tm_hour = 12;\n+\ttm.tm_mday = 1;\n+\ttm.tm_mon  = 0  /* January */;\n+\ttm.tm_year = 90 /* 1990 */ ;\n+\ttm.tm_isdst = -1;\n+\twhen.tv_sec = mktime(&tm);\n+\n \tfor (i = 1; i < argc; i++) {\n \t\tchar result[100];\n \t\ttime_t t;\n@@ -15,6 +26,12 @@ int main(int argc, char **argv)\n \n \t\tt = approxidate(argv[i]);\n \t\tprintf(\"%s -> %s\\n\", argv[i], ctime(&t));\n+\n+\t\tt = approxidate_relative(argv[i], &when);\n+\t\tprintf(\"relative: %s -> %s\\n\", argv[i], ctime(&t));\n+\n+\t\tprintf(\"relative: %s, out of %s\\n\",\n+\t\t       show_date_relative(t, 0, &when), ctime(&t));\n \t}\n \treturn 0;\n }\n-- \n1.6.4.1.263.g468a\n"},{"id":"122100","messageId":"20090830073619.GA14217@coredump.intra.peff.net","threadId":"20778","inReplyTo":"20090828210404.GA11867@blimp.localdomain","subject":"Re: [PATCH 1/2] Add date formatting and parsing functions relative to a given time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T07:36:19Z","receivedAt":"2009-08-30T07:36:19Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 11:04:04PM +0200, Alex Riesen wrote:\n\n> +const char *show_date_relative(unsigned long time, int tz, const struct timeval *now)\n> +{\n> +\tstatic char timebuf[100 /* TODO: can be optimized */];\n\nThis was 200 in the original version. I doubt that it makes a\ndifference, but I think in a refactoring patch I think it is best to\nsimply reorganize and make no other changes.\n\n> +static unsigned long approximation(const char *date, const struct timeval *tv)\n\nI know it's static, but this is a terribly undescriptive function name.\nApproximation of what?  Can we call it approxidate_internal or\nsomething?\n\n-Peff\n"},{"id":"122101","messageId":"81b0412b0908300051g19bc2c5buecf5d925bd0d40b6@mail.gmail.com","threadId":"20778","inReplyTo":"20090830073619.GA14217@coredump.intra.peff.net","subject":"Re: [PATCH 1/2] Add date formatting and parsing functions relative to a given time","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-30T07:51:25Z","receivedAt":"2009-08-30T07:51:25Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Sun, Aug 30, 2009 at 09:36, Jeff King<peff@peff.net> wrote:\n> On Fri, Aug 28, 2009 at 11:04:04PM +0200, Alex Riesen wrote:\n>\n>> +const char *show_date_relative(unsigned long time, int tz, const struct timeval *now)\n>> +{\n>> +     static char timebuf[100 /* TODO: can be optimized */];\n>\n> This was 200 in the original version. I doubt that it makes a\n> difference, but I think in a refactoring patch I think it is best to\n> simply reorganize and make no other changes.\n\nYes, I just noticed that 200 was much too much, made the note\nto fix it sometime and forgot the note in the final submission.\n\n>> +static unsigned long approximation(const char *date, const struct timeval *tv)\n>\n> I know it's static, but this is a terribly undescriptive function name.\n> Approximation of what?  Can we call it approxidate_internal or\n> something?\n\nBeen there, tried that. Didn't like it, because it didn't feel enough\napproxidate (the original) anymore. Not even internally, because\nof missing parse_date. My other attempts were guessdate and\napproxidate_bottom_half (but only very shortly).\n\nThe \"approximation\", if you consider the functions arguments,\nseems to me the closest to what the function _is_. OTOH,\nmaybe I should have used a verb...\n"}]}