{"thread":{"id":"20765","subject":"[PATCH] Round-down years in \"years+months\" relative date view","startedAt":"2009-08-27T23:39:38Z","lastAt":"2009-09-01T03:03:28Z","messageCount":47,"participants":["David Reiss","Jeff King","Alex Riesen","Nicolas Pitre","A Large Angry SCM","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"121947","messageId":"4A97193A.8090502@facebook.com","threadId":"20765","inReplyTo":null,"subject":"[PATCH] Round-down years in \"years+months\" relative date view","fromName":"David Reiss","fromEmail":"dreiss@facebook.com","sentAt":"2009-08-27T23:39:38Z","receivedAt":"2009-08-27T23:39:38Z","isPatch":true,"sender":{"key":"dreiss@facebook.com","avatar":null},"body":"Previously, a commit from 1 year and 7 months ago would display as\n\"2 years, 7 months ago\".\n\nSigned-off-by: David Reiss <dreiss@facebook.com>\n---\n\nHere's my test script.  Let me know if you'd rather have it as part\nof the test suite.\n\n\n#!/bin/sh\nset -e\nREPO=\"git-relative-dates-test\"\nrm -rf \"$REPO\"\nmkdir \"$REPO\"\ncd \"$REPO\"\ngit init\nNOW=`date +%s`\nenv GIT_AUTHOR_DATE=`expr $NOW - \\( 365 + 220 \\) \\* 24 \\* 60 \\* 60` git commit --allow-empty -m old-commit\ngit log --date=relative\n\n\n date.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 1de1845..e848d96 100644\n--- a/date.c\n+++ b/date.c\n@@ -137,7 +137,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)\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 + 183) / 365;\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-- \n1.6.0.4\n"},{"id":"121975","messageId":"20090828060538.GA22416@coredump.intra.peff.net","threadId":"20765","inReplyTo":"4A97193A.8090502@facebook.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T06:05:38Z","receivedAt":"2009-08-28T06:05:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 27, 2009 at 04:39:38PM -0700, David Reiss wrote:\n\n> Previously, a commit from 1 year and 7 months ago would display as\n> \"2 years, 7 months ago\".\n\nWow, embarrassing.\n\nAcked-by: Jeff King <peff@peff.net>\n\n> Here's my test script.  Let me know if you'd rather have it as part\n> of the test suite.\n\nI couldn't find any tests related to relative date processing, so it\nwould be really nice to have some. But I'm not sure of the best way to\ndo it without dealing with race conditions. Annoyingly, show_date calls\ngettimeofday at a pretty low level, so there isn't a way of\ninstrumenting it short of LD_PRELOAD trickery (which is probably not\nvery portable).\n\nBut maybe a patch like this is worth doing, which would allow us to test\nin a repeatable fashion:\n\n---\ndiff --git a/date.c b/date.c\nindex e848d96..db2f831 100644\n--- a/date.c\n+++ b/date.c\n@@ -86,6 +86,33 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n+static int current_time(struct timeval *now)\n+{\n+\tstatic struct timeval fake_time;\n+\tstatic int use_fake_time = -1;\n+\n+\tif (use_fake_time == -1) {\n+\t\tconst char *x = getenv(\"GIT_FAKE_TIME\");\n+\t\tif (x) {\n+\t\t\tchar buf[50];\n+\t\t\tif (parse_date(x, buf, sizeof(buf)) <= 0)\n+\t\t\t\tdie(\"unable to parse GIT_FAKE_TIME\");\n+\t\t\tfake_time.tv_sec = strtoul(buf, NULL, 10);\n+\t\t\tfake_time.tv_usec = 0;\n+\t\t\tuse_fake_time = 1;\n+\t\t}\n+\t\telse\n+\t\t\tuse_fake_time = 0;\n+\t}\n+\n+\tif (use_fake_time == 1) {\n+\t\tmemcpy(now, &fake_time, sizeof(*now));\n+\t\treturn 0;\n+\t}\n+\n+\treturn gettimeofday(now, NULL);\n+}\n+\n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n \tstruct tm *tm;\n@@ -99,7 +126,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)\n \tif (mode == DATE_RELATIVE) {\n \t\tunsigned long diff;\n \t\tstruct timeval now;\n-\t\tgettimeofday(&now, NULL);\n+\t\tcurrent_time(&now);\n \t\tif (now.tv_sec < time)\n \t\t\treturn \"in the future\";\n \t\tdiff = now.tv_sec - time;\n@@ -929,7 +956,7 @@ unsigned long approxidate(const char *date)\n \tif (parse_date(date, buffer, sizeof(buffer)) > 0)\n \t\treturn strtoul(buffer, NULL, 10);\n \n-\tgettimeofday(&tv, NULL);\n+\tcurrent_time(&tv);\n \ttime_sec = tv.tv_sec;\n \tlocaltime_r(&time_sec, &tm);\n \tnow = tm;\n"},{"id":"121979","messageId":"81b0412b0908280058i364bfb83nb04354d982abc053@mail.gmail.com","threadId":"20765","inReplyTo":"20090828060538.GA22416@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T07:58:27Z","receivedAt":"2009-08-28T07:58:27Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 08:05, Jeff King<peff@peff.net> wrote:\n> On Thu, Aug 27, 2009 at 04:39:38PM -0700, David Reiss wrote:\n>\n>> Previously, a commit from 1 year and 7 months ago would display as\n>> \"2 years, 7 months ago\".\n>\n> Wow, embarrassing.\n>\n> Acked-by: Jeff King <peff@peff.net>\n>\n>> Here's my test script.  Let me know if you'd rather have it as part\n>> of the test suite.\n>\n> I couldn't find any tests related to relative date processing, so it\n> would be really nice to have some. But I'm not sure of the best way to\n> do it without dealing with race conditions. Annoyingly, show_date calls\n> gettimeofday at a pretty low level, so there isn't a way of\n> instrumenting it short of LD_PRELOAD trickery (which is probably not\n> very portable).\n\nMaybe better prepare the _test_ so that it uses current time and time\narithmetics then put yet another cludge in operational code? Especially\nwhen we already have a greate number of GIT_ environment variables,\ndocumented nowhere, with effects not immediately obvious:\n\n  $ git grep -n '\"GIT_'| perl -ne '/\"(GIT_\\w+)/ && print \"$1\\n\"' |\nsort |uniq | wc -l\n  49\n\n  $ git grep -n '\"GIT_'|grep ^Documentation\n  $\n\nGIT_FLUSH? GIT_SEND_EMAIL_NOTTY?! GIT_CHERRY_PICK_HELP?!!\n"},{"id":"122005","messageId":"20090828150212.GA6013@coredump.intra.peff.net","threadId":"20765","inReplyTo":"81b0412b0908280058i364bfb83nb04354d982abc053@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T15:02:12Z","receivedAt":"2009-08-28T15:02:12Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 09:58:27AM +0200, Alex Riesen wrote:\n\n> > I couldn't find any tests related to relative date processing, so it\n> > would be really nice to have some. But I'm not sure of the best way to\n> > do it without dealing with race conditions. Annoyingly, show_date calls\n> > gettimeofday at a pretty low level, so there isn't a way of\n> > instrumenting it short of LD_PRELOAD trickery (which is probably not\n> > very portable).\n> \n> Maybe better prepare the _test_ so that it uses current time and time\n> arithmetics then put yet another cludge in operational code? Especially\n> when we already have a greate number of GIT_ environment variables,\n> documented nowhere, with effects not immediately obvious:\n\nBut that's the point: you can't do that without a race condition. Your\ntest gets a sense of the current time, then runs git, which checks the\ncurrent time again. How many seconds elapsed between the two checks?\n\nI guess it is good enough for testing large time spans, but I was hoping\nfor a comprehensive time test.\n\n-Peff\n"},{"id":"122019","messageId":"81b0412b0908281000l41c862f9ye52da7251014c4f7@mail.gmail.com","threadId":"20765","inReplyTo":"20090828150212.GA6013@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T17:00:59Z","receivedAt":"2009-08-28T17:00:59Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 17:02, Jeff King<peff@peff.net> wrote:\n> But that's the point: you can't do that without a race condition. Your\n> test gets a sense of the current time, then runs git, which checks the\n> current time again. How many seconds elapsed between the two checks?\n\nHow _many_ do you need?\n"},{"id":"122020","messageId":"20090828171552.GA6821@coredump.intra.peff.net","threadId":"20765","inReplyTo":"81b0412b0908281000l41c862f9ye52da7251014c4f7@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T17:15:52Z","receivedAt":"2009-08-28T17:15:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 07:00:59PM +0200, Alex Riesen wrote:\n\n> On Fri, Aug 28, 2009 at 17:02, Jeff King<peff@peff.net> wrote:\n> > But that's the point: you can't do that without a race condition. Your\n> > test gets a sense of the current time, then runs git, which checks the\n> > current time again. How many seconds elapsed between the two checks?\n> \n> How _many_ do you need?\n\nI don't understand what you're trying to say. My point is that if you\nare checking results to a one-second precision, you need to know whether\nzero seconds elapsed, or one second, or two seconds, or whatever to get\na consistent result.\n\n-Peff\n"},{"id":"122021","messageId":"alpine.LFD.2.00.0908281307510.6044@xanadu.home","threadId":"20765","inReplyTo":"20090828150212.GA6013@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2009-08-28T17:28:34Z","receivedAt":"2009-08-28T17:28:34Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Fri, 28 Aug 2009, Jeff King wrote:\n\n> On Fri, Aug 28, 2009 at 09:58:27AM +0200, Alex Riesen wrote:\n> \n> > > I couldn't find any tests related to relative date processing, so it\n> > > would be really nice to have some. But I'm not sure of the best way to\n> > > do it without dealing with race conditions. Annoyingly, show_date calls\n> > > gettimeofday at a pretty low level, so there isn't a way of\n> > > instrumenting it short of LD_PRELOAD trickery (which is probably not\n> > > very portable).\n> > \n> > Maybe better prepare the _test_ so that it uses current time and time\n> > arithmetics then put yet another cludge in operational code? Especially\n> > when we already have a greate number of GIT_ environment variables,\n> > documented nowhere, with effects not immediately obvious:\n> \n> But that's the point: you can't do that without a race condition. Your\n> test gets a sense of the current time, then runs git, which checks the\n> current time again. How many seconds elapsed between the two checks?\n> \n> I guess it is good enough for testing large time spans, but I was hoping\n> for a comprehensive time test.\n\nI agree with your concern.  This is why I created the --index-version \nswitch to pack-objects.\n\nHowever I was hoping for a current time trickery solution that could \nlive in test-date.c instead of interfering with the main code in such a \nway.\n\nDid a quick test to override the library version:\n\ndiff --git a/test-date.c b/test-date.c\nindex 62e8f23..0bcd0c9 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -1,5 +1,10 @@\n #include \"cache.h\"\n \n+int gettimeofday(struct timeval *tv, struct timezone *tz)\n+{\n+\treturn 0;\n+}\n+\n int main(int argc, char **argv)\n {\n \tint i;\n\nResult:\n\n$ ./test-date now\nnow -> bad -> Wed Dec 31 19:00:00 1969\nnow -> Tue Jan 22 10:48:24 10199\n\nSo this seems to work.  ;-)\n\n\nNicolas\n"},{"id":"122025","messageId":"20090828180158.GA6940@coredump.intra.peff.net","threadId":"20765","inReplyTo":"alpine.LFD.2.00.0908281307510.6044@xanadu.home","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T18:01:58Z","receivedAt":"2009-08-28T18:01:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 01:28:34PM -0400, Nicolas Pitre wrote:\n\n> However I was hoping for a current time trickery solution that could \n> live in test-date.c instead of interfering with the main code in such a \n> way.\n> \n> Did a quick test to override the library version:\n\nThanks, that is a much better solution. And I don't know offhand of any\nportability problems in overriding the library at link time.\n\n-Peff\n"},{"id":"122027","messageId":"81b0412b0908281121s1d37a0cdj1cdd0595014124e7@mail.gmail.com","threadId":"20765","inReplyTo":"20090828171552.GA6821@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T18:21:46Z","receivedAt":"2009-08-28T18:21:46Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 19:15, Jeff King<peff@peff.net> wrote:\n> On Fri, Aug 28, 2009 at 07:00:59PM +0200, Alex Riesen wrote:\n>\n>> On Fri, Aug 28, 2009 at 17:02, Jeff King<peff@peff.net> wrote:\n>> > But that's the point: you can't do that without a race condition. Your\n>> > test gets a sense of the current time, then runs git, which checks the\n>> > current time again. How many seconds elapsed between the two checks?\n>>\n>> How _many_ do you need?\n>\n> I don't understand what you're trying to say. My point is that if you\n> are checking results to a one-second precision, you need to know whether\n> zero seconds elapsed, or one second, or two seconds, or whatever to get\n> a consistent result.\n\nTaking this particular case as an example, can't we just set the time\nof the _commit_ back in time? We can.\nAnd we don't need to know the difference precisely, it can be\nsomething like /[0-9]+ ago/, can't it?\nOk, it is possible, that something goes terribly wrong and the test suite\nfreezes for an extended period of time, so the pattern above does\nnot apply anymore. In this case, wont you prefer the test suite to\nbreak? Ok, maybe not, if the freeze was an Ctrl-Z pressed at\nunlucky moment. Which involves an operator online and looking,\nand action and reaction will be both visible.\n\nSo, yes, it is not absolutely safe, but this approach has no side effects\non the working code. And very low probability of something go wrong.\n"},{"id":"122028","messageId":"81b0412b0908281127h2c444770g411ceaf052952899@mail.gmail.com","threadId":"20765","inReplyTo":"20090828180158.GA6940@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T18:27:06Z","receivedAt":"2009-08-28T18:27:06Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 20:01, Jeff King<peff@peff.net> wrote:\n> On Fri, Aug 28, 2009 at 01:28:34PM -0400, Nicolas Pitre wrote:\n>\n>> However I was hoping for a current time trickery solution that could\n>> live in test-date.c instead of interfering with the main code in such a\n>> way.\n>>\n>> Did a quick test to override the library version:\n>\n> Thanks, that is a much better solution. And I don't know offhand of any\n> portability problems in overriding the library at link time.\n>\n\nMicrosoft's compiler and libraries? MacOSX?\n"},{"id":"122029","messageId":"20090828183958.GA11488@coredump.intra.peff.net","threadId":"20765","inReplyTo":"81b0412b0908281127h2c444770g411ceaf052952899@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T18:39:58Z","receivedAt":"2009-08-28T18:39:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 08:27:06PM +0200, Alex Riesen wrote:\n\n> > Thanks, that is a much better solution. And I don't know offhand of any\n> > portability problems in overriding the library at link time.\n> \n> Microsoft's compiler and libraries? MacOSX?\n\nAre you saying you know those to be platforms with problems, or are you\nasking whether those platforms will have problems?\n\n-Peff\n"},{"id":"122030","messageId":"81b0412b0908281142v7e1b73ddvb727abe915dace86@mail.gmail.com","threadId":"20765","inReplyTo":"20090828183958.GA11488@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T18:42:21Z","receivedAt":"2009-08-28T18:42:21Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 20:39, Jeff King<peff@peff.net> wrote:\n> On Fri, Aug 28, 2009 at 08:27:06PM +0200, Alex Riesen wrote:\n>\n>> > Thanks, that is a much better solution. And I don't know offhand of any\n>> > portability problems in overriding the library at link time.\n>>\n>> Microsoft's compiler and libraries? MacOSX?\n>\n> Are you saying you know those to be platforms with problems, or are you\n> asking whether those platforms will have problems?\n\nBoth: MS never had weak/vague linkage, but I don't know about MacOSX.\nI suspect them to have the same deficiency, but I'd be glad to be wrong.\n"},{"id":"122031","messageId":"81b0412b0908281149i2182f95ob51fee82e29e8fdf@mail.gmail.com","threadId":"20765","inReplyTo":"81b0412b0908281142v7e1b73ddvb727abe915dace86@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T18:49:48Z","receivedAt":"2009-08-28T18:49:48Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 20:42, Alex Riesen<raa.lkml@gmail.com> wrote:\n> On Fri, Aug 28, 2009 at 20:39, Jeff King<peff@peff.net> wrote:\n>> On Fri, Aug 28, 2009 at 08:27:06PM +0200, Alex Riesen wrote:\n>>\n>>> > Thanks, that is a much better solution. And I don't know offhand of any\n>>> > portability problems in overriding the library at link time.\n>>>\n\nHm, how about supplying show_date and approxidate with current time?\nLike this:\n\n/* exported */\nconst char *show_date_rel(unsigned long time, int tz, struct timeval *now)\n{\n... the DATE_RELATIVE path of show_date\n}\n\nconst char *show_date(unsigned long time, int tz, enum date_mode mode)\n{\n  struct timeval now;\n  if (mode == DATE_RELATIVE) {\n    gettimeofday(&now, NULL);\n    return show_date_rel(time, tz, &now);\n  }\n  ... other paths of old show_date\n}\n\nStill affects the performance, but much less, and no side effects.\nAnd you can test show_date_rel path in test-date.c\n"},{"id":"122035","messageId":"alpine.LFD.2.00.0908281458370.6044@xanadu.home","threadId":"20765","inReplyTo":"81b0412b0908281142v7e1b73ddvb727abe915dace86@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2009-08-28T19:00:50Z","receivedAt":"2009-08-28T19:00:50Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Fri, 28 Aug 2009, Alex Riesen wrote:\n\n> On Fri, Aug 28, 2009 at 20:39, Jeff King<peff@peff.net> wrote:\n> > On Fri, Aug 28, 2009 at 08:27:06PM +0200, Alex Riesen wrote:\n> >\n> >> > Thanks, that is a much better solution. And I don't know offhand of any\n> >> > portability problems in overriding the library at link time.\n> >>\n> >> Microsoft's compiler and libraries? MacOSX?\n> >\n> > Are you saying you know those to be platforms with problems, or are you\n> > asking whether those platforms will have problems?\n> \n> Both: MS never had weak/vague linkage, but I don't know about MacOSX.\n\nThis is not about weak or vague linkage.  This is plain basic linker \nfeature where no library object needs to be linked if there is no symbol \nto resolve.\n\n> I suspect them to have the same deficiency, but I'd be glad to be wrong.\n\nAre you able to test it?\n\n\nNicolas\n"},{"id":"122036","messageId":"20090828190319.GA9233@blimp.localdomain","threadId":"20765","inReplyTo":"alpine.LFD.2.00.0908281307510.6044@xanadu.home","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T19:03:19Z","receivedAt":"2009-08-28T19:03:19Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":">From b51bc56816490c71cd37f52be73a06cef6b9bf14 Mon Sep 17 00:00:00 2001\nFrom: Alex Riesen <raa.lkml@gmail.com>\nDate: Fri, 28 Aug 2009 20:59:59 +0200\nSubject: [PATCH] Add date formatting functions with current time explicitely formatted\n\nIt should allow safe testing of this part of the code.\n---\nNicolas Pitre, Fri, Aug 28, 2009 19:28:34 +0200:\n> On Fri, 28 Aug 2009, Jeff King wrote:\n> > On Fri, Aug 28, 2009 at 09:58:27AM +0200, Alex Riesen wrote:\n> > \n> > > > I couldn't find any tests related to relative date processing, so it\n> > > > would be really nice to have some. But I'm not sure of the best way to\n> > > > do it without dealing with race conditions. Annoyingly, show_date calls\n> > > > gettimeofday at a pretty low level, so there isn't a way of\n> > > > instrumenting it short of LD_PRELOAD trickery (which is probably not\n> > > > very portable).\n> > > \n> > > Maybe better prepare the _test_ so that it uses current time and time\n> > > arithmetics then put yet another cludge in operational code? Especially\n> > > when we already have a greate number of GIT_ environment variables,\n> > > documented nowhere, with effects not immediately obvious:\n> > \n> > But that's the point: you can't do that without a race condition. Your\n> > test gets a sense of the current time, then runs git, which checks the\n> > current time again. How many seconds elapsed between the two checks?\n> > \n> > I guess it is good enough for testing large time spans, but I was hoping\n> > for a comprehensive time test.\n> \n> I agree with your concern.  This is why I created the --index-version \n> switch to pack-objects.\n> \n\nThis is what I mean with \"supplying current time\":\n\n cache.h |    2 +\n date.c  |  130 ++++++++++++++++++++++++++++++++++----------------------------\n 2 files changed, 73 insertions(+), 59 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 409a17d..08b4b49 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 + 183) / 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 + 183) / 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,17 @@ 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+unsigned long approxidate_relative(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 +904,10 @@ unsigned long approxidate(const char *date)\n \t\ttm.tm_year--;\n \treturn mktime(&tm);\n }\n+\n+unsigned long approxidate(const char *date)\n+{\n+\tstruct timeval tv;\n+\tgettimeofday(&tv, NULL);\n+\treturn approxidate_relative(date, &tv);\n+}\n-- \n1.6.4.1.261.gf9874\n"},{"id":"122039","messageId":"81b0412b0908281208h20aa6e81od3d6567fdffa0dec@mail.gmail.com","threadId":"20765","inReplyTo":"alpine.LFD.2.00.0908281458370.6044@xanadu.home","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T19:08:39Z","receivedAt":"2009-08-28T19:08:39Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 21:00, Nicolas Pitre<nico@cam.org> wrote:\n>> >> Microsoft's compiler and libraries? MacOSX?\n>> >\n>> > Are you saying you know those to be platforms with problems, or are you\n>> > asking whether those platforms will have problems?\n>>\n>> Both: MS never had weak/vague linkage, but I don't know about MacOSX.\n>\n> This is not about weak or vague linkage.  This is plain basic linker\n> feature where no library object needs to be linked if there is no symbol\n> to resolve.\n\nMaybe I missed something, but wasn't the idea to overwrite gettimeofday\nwith a public gettimeofday, defined in one of the object files?\nAnd shouldn't a linker complain regarding duplicated symbols, unless\nthe other (library) symbol is defined as a weak symbol, allowing\noverriding it with another symbol of stronger linkage?\n\n>> I suspect them to have the same deficiency, but I'd be glad to be wrong.\n>\n> Are you able to test it?\n>\n\nOnly the MS, but it is not interesting.\n"},{"id":"122040","messageId":"20090828191521.GA12292@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090828190319.GA9233@blimp.localdomain","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-28T19:15:21Z","receivedAt":"2009-08-28T19:15:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 28, 2009 at 09:03:19PM +0200, Alex Riesen wrote:\n\n> +unsigned long approxidate(const char *date)\n> +{\n> +\tstruct timeval tv;\n> +\tgettimeofday(&tv, NULL);\n> +\treturn approxidate_relative(date, &tv);\n> +}\n\nThis now always calls gettimeofday, whereas the original approxidate\nonly did if parse_date failed.\n\nI think you could also make this patch much smaller by just wrapping the\nwhole function and using a '0' sentinel for \"you need to fill in the\ntime.\" Like:\n\n---\ndiff --git a/date.c b/date.c\nindex 409a17d..b084d19 100644\n--- a/date.c\n+++ b/date.c\n@@ -86,6 +86,14 @@ static int local_tzoffset(unsigned long time)\n \n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n+\tstruct timeval now;\n+\tnow.tv_sec = 0;\n+\tshow_date_at_time(time, tz, mode, &now);\n+}\n+\n+const char *show_date_at_time(unsigned long time, int tz, enum date_mode mode,\n+\t\tstruct timeval now)\n+{\n \tstruct tm *tm;\n \tstatic char timebuf[200];\n \n@@ -96,8 +104,8 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)\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)\n+\t\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\nOn the other hand, refactoring the relative date code into its own\nfunction is probably a good thing in the long run.\n\n-Peff\n"},{"id":"122043","messageId":"81b0412b0908281220o1c378d5dn6ed52c8d55a9cdec@mail.gmail.com","threadId":"20765","inReplyTo":"20090828191521.GA12292@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T19:20:50Z","receivedAt":"2009-08-28T19:20:50Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Fri, Aug 28, 2009 at 21:15, Jeff King<peff@peff.net> wrote:\n> On Fri, Aug 28, 2009 at 09:03:19PM +0200, Alex Riesen wrote:\n>\n>> +unsigned long approxidate(const char *date)\n>> +{\n>> +     struct timeval tv;\n>> +     gettimeofday(&tv, NULL);\n>> +     return approxidate_relative(date, &tv);\n>> +}\n>\n> This now always calls gettimeofday, whereas the original approxidate\n> only did if parse_date failed.\n\nOh, bugger...\n\n> On the other hand, refactoring the relative date code into its own\n> function is probably a good thing in the long run.\n\nExactly.\n"},{"id":"122046","messageId":"alpine.LFD.2.00.0908281516440.6044@xanadu.home","threadId":"20765","inReplyTo":"81b0412b0908281208h20aa6e81od3d6567fdffa0dec@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2009-08-28T19:27:53Z","receivedAt":"2009-08-28T19:27:53Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Fri, 28 Aug 2009, Alex Riesen wrote:\n\n> On Fri, Aug 28, 2009 at 21:00, Nicolas Pitre<nico@cam.org> wrote:\n> >> >> Microsoft's compiler and libraries? MacOSX?\n> >> >\n> >> > Are you saying you know those to be platforms with problems, or are you\n> >> > asking whether those platforms will have problems?\n> >>\n> >> Both: MS never had weak/vague linkage, but I don't know about MacOSX.\n> >\n> > This is not about weak or vague linkage.  This is plain basic linker\n> > feature where no library object needs to be linked if there is no symbol\n> > to resolve.\n> \n> Maybe I missed something, but wasn't the idea to overwrite gettimeofday\n> with a public gettimeofday, defined in one of the object files?\n\nYes, in test-date.o.\n\n> And shouldn't a linker complain regarding duplicated symbols, unless\n> the other (library) symbol is defined as a weak symbol, allowing\n> overriding it with another symbol of stronger linkage?\n\nNormally a linker would search for new objects to link only when there \nare still symbols to resolve.  If the library is well architected (mind \nyou I don't know if that is the case on Windows or OS X) you should find \nmany small object files in a library, so to have only related functions \ntogether in a single object for only the needed code to be linked in the \nfinal binary. Hence the printf symbol should be in a separate object \nfile than gettimeofday, etc.\n\nOnly if the library's object file containing gettimeofday also contains \nanother symbol pulled by the linker will you see a duplicated symbol \nerror.  But this is still a possibility.  So your proposal is probably \ncleaner.\n\n\nNicolas\n"},{"id":"122047","messageId":"20090828193302.GB9233@blimp.localdomain","threadId":"20765","inReplyTo":"81b0412b0908281220o1c378d5dn6ed52c8d55a9cdec@mail.gmail.com","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T19:33:02Z","receivedAt":"2009-08-28T19:33:02Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"From fe67532bdf095dc9ebc0c7dd67be384e807a197c Mon Sep 17 00:00:00 2001\nFrom: Alex Riesen <raa.lkml@gmail.com>\nDate: Fri, 28 Aug 2009 20:59:59 +0200\nSubject: [PATCH] Add date formatting functions with current time explicitely formatted\n\nIt should allow safe testing of this part of the code.\n---\nAlex Riesen, Fri, Aug 28, 2009 21:20:50 +0200:\n> On Fri, Aug 28, 2009 at 21:15, Jeff King<peff@peff.net> wrote:\n> > On Fri, Aug 28, 2009 at 09:03:19PM +0200, Alex Riesen wrote:\n> >\n> >> +unsigned long approxidate(const char *date)\n> >> +{\n> >> +     struct timeval tv;\n> >> +     gettimeofday(&tv, NULL);\n> >> +     return approxidate_relative(date, &tv);\n> >> +}\n> >\n> > This now always calls gettimeofday, whereas the original approxidate\n> > only did if parse_date failed.\n> \n> Oh, bugger...\n> \n\nRather like this, I mean :)\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 409a17d..171e68f 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 + 183) / 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 + 183) / 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.261.gf9874\n"},{"id":"122049","messageId":"20090828194913.GC9233@blimp.localdomain","threadId":"20765","inReplyTo":"alpine.LFD.2.00.0908281516440.6044@xanadu.home","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T19:49:13Z","receivedAt":"2009-08-28T19:49:13Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Nicolas Pitre, Fri, Aug 28, 2009 21:27:53 +0200:\n> On Fri, 28 Aug 2009, Alex Riesen wrote:\n> > And shouldn't a linker complain regarding duplicated symbols, unless\n> > the other (library) symbol is defined as a weak symbol, allowing\n> > overriding it with another symbol of stronger linkage?\n> \n> Normally a linker would search for new objects to link only when there \n> are still symbols to resolve.  If the library is well architected (mind \n> you I don't know if that is the case on Windows or OS X) you should find \n> many small object files in a library, so to have only related functions \n> together in a single object for only the needed code to be linked in the \n> final binary. Hence the printf symbol should be in a separate object \n> file than gettimeofday, etc.\n> \n> Only if the library's object file containing gettimeofday also contains \n> another symbol pulled by the linker will you see a duplicated symbol \n> error.  But this is still a possibility.  So your proposal is probably \n> cleaner.\n\nIs it so for dynamic linking as well? Like in libc.so?\n"},{"id":"122051","messageId":"alpine.LFD.2.00.0908281554020.6044@xanadu.home","threadId":"20765","inReplyTo":"20090828194913.GC9233@blimp.localdomain","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2009-08-28T20:01:38Z","receivedAt":"2009-08-28T20:01:38Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Fri, 28 Aug 2009, Alex Riesen wrote:\n\n> Nicolas Pitre, Fri, Aug 28, 2009 21:27:53 +0200:\n> > On Fri, 28 Aug 2009, Alex Riesen wrote:\n> > > And shouldn't a linker complain regarding duplicated symbols, unless\n> > > the other (library) symbol is defined as a weak symbol, allowing\n> > > overriding it with another symbol of stronger linkage?\n> > \n> > Normally a linker would search for new objects to link only when there \n> > are still symbols to resolve.  If the library is well architected (mind \n> > you I don't know if that is the case on Windows or OS X) you should find \n> > many small object files in a library, so to have only related functions \n> > together in a single object for only the needed code to be linked in the \n> > final binary. Hence the printf symbol should be in a separate object \n> > file than gettimeofday, etc.\n> > \n> > Only if the library's object file containing gettimeofday also contains \n> > another symbol pulled by the linker will you see a duplicated symbol \n> > error.  But this is still a possibility.  So your proposal is probably \n> > cleaner.\n> \n> Is it so for dynamic linking as well? Like in libc.so?\n\nYes.  The linker still links against stubs in that case.\n\n\nNicolas\n"},{"id":"122054","messageId":"20090828205232.GD9233@blimp.localdomain","threadId":"20765","inReplyTo":"20090828193302.GB9233@blimp.localdomain","subject":"[PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T20:52:32Z","receivedAt":"2009-08-28T20:52:32Z","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---\nAlex Riesen, Fri, Aug 28, 2009 21:33:02 +0200:\n> \n> It should allow safe testing of this part of the code.\n\nAnd this should really allow testing of it:\n\n    $ ./test-date '10.days.ago'\n    10.days.ago -> bad -> Thu Jan  1 01:00:00 1970\n    10.days.ago -> Tue Aug 18 22:50:20 2009\n\n    relative: 10.days.ago -> Fri Dec 22 12:00:00 1989\n\n    relative: 10 days ago, out of Fri Dec 22 12:00:00 1989\n\n    $\n\nAccording to Wikipedia, absolutely nothing of note happened\nat the day 10 January, 1990.\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":"122055","messageId":"20090828205404.GE9233@blimp.localdomain","threadId":"20765","inReplyTo":"20090828205232.GD9233@blimp.localdomain","subject":"Re: [PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-28T20:54:04Z","receivedAt":"2009-08-28T20:54:04Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Alex Riesen, Fri, Aug 28, 2009 22:52:32 +0200:\n> According to Wikipedia, absolutely nothing of note happened\n> at the day 10 January, 1990.\n\n1 Jan. 1990, not 10.\n"},{"id":"122061","messageId":"4A9853B8.2090709@gmail.com","threadId":"20765","inReplyTo":"20090828171552.GA6821@coredump.intra.peff.net","subject":"Re: [PATCH] Round-down years in \"years+months\" relative date view","fromName":"A Large Angry SCM","fromEmail":"gitzilla@gmail.com","sentAt":"2009-08-28T22:01:28Z","receivedAt":"2009-08-28T22:01:28Z","isPatch":true,"sender":{"key":"gitzilla@gmail.com","avatar":"https://gravatar.com/avatar/354625c442439908ff3dd99757dee330e29e9df7847472384faf7a00add247fb?d=mp&s=160"},"body":"Jeff King wrote:\n> On Fri, Aug 28, 2009 at 07:00:59PM +0200, Alex Riesen wrote:\n> \n>> On Fri, Aug 28, 2009 at 17:02, Jeff King<peff@peff.net> wrote:\n>>> But that's the point: you can't do that without a race condition. Your\n>>> test gets a sense of the current time, then runs git, which checks the\n>>> current time again. How many seconds elapsed between the two checks?\n>> How _many_ do you need?\n> \n> I don't understand what you're trying to say. My point is that if you\n> are checking results to a one-second precision, you need to know whether\n> zero seconds elapsed, or one second, or two seconds, or whatever to get\n> a consistent result.\n\nTo no-one in particular, Gitzilla mumbles \"To do this right(tm) would \nprobably require LD_PRELOAD magic with a environment variable invocation.\n"},{"id":"122089","messageId":"7vk50mz41e.fsf@alter.siamese.dyndns.org","threadId":"20765","inReplyTo":"20090828205232.GD9233@blimp.localdomain","subject":"Re: [PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-29T21:46:53Z","receivedAt":"2009-08-29T21:46:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> To complement the testability of approxidate.\n> ---\n> Alex Riesen, Fri, Aug 28, 2009 21:33:02 +0200:\n>> \n>> It should allow safe testing of this part of the code.\n>\n> And this should really allow testing of it:\n>\n>     $ ./test-date '10.days.ago'\n>     10.days.ago -> bad -> Thu Jan  1 01:00:00 1970\n>     10.days.ago -> Tue Aug 18 22:50:20 2009\n>\n>     relative: 10.days.ago -> Fri Dec 22 12:00:00 1989\n>\n>     relative: 10 days ago, out of Fri Dec 22 12:00:00 1989\n>\n>     $\n\nWhat are these blank lines for?  Is this intended as a serious submission\nfor inclusion?  I am having a hrad time to guess, especially you did not\nsign this off, nor Cc'ed me.\n"},{"id":"122099","messageId":"81b0412b0908300025r4eeee84fyf0bfc3b2e940ff37@mail.gmail.com","threadId":"20765","inReplyTo":"7vk50mz41e.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-30T07:25:11Z","receivedAt":"2009-08-30T07:25:11Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Sat, Aug 29, 2009 at 23:46, Junio C Hamano<gitster@pobox.com> wrote:\n> Alex Riesen <raa.lkml@gmail.com> writes:\n>> To complement the testability of approxidate.\n>> ---\n>> Alex Riesen, Fri, Aug 28, 2009 21:33:02 +0200:\n>>>\n>>> It should allow safe testing of this part of the code.\n>>\n>> And this should really allow testing of it:\n>>\n>>     $ ./test-date '10.days.ago'\n>>     10.days.ago -> bad -> Thu Jan  1 01:00:00 1970\n>>     10.days.ago -> Tue Aug 18 22:50:20 2009\n>>\n>>     relative: 10.days.ago -> Fri Dec 22 12:00:00 1989\n>>\n>>     relative: 10 days ago, out of Fri Dec 22 12:00:00 1989\n>>\n>>     $\n>\n> What are these blank lines for?\n\nctime(3) artifact (it adds a \\n in the output buffer), which I missed.\n\n> Is this intended as a serious submission for inclusion?\n\nNot yet. AFAICS, test-date is never used in our test suite.\n\n> I am having a hrad time to guess, especially you did not\n> sign this off, nor Cc'ed me.\n\nRight, that's because I'm not sure myself. Frankly, I'm not\nconvinced we have to test every single thing. In my experience,\nthe bigger a test suite, the less are people inclined to use it\n(including setting up automatic test runs).\n\nJeff, Nicolas? Is this test enough? Are there any other code\npaths you want to include in the test?\n\nAnd sorry for having you missed in Cc:, that wasn't intended.\n"},{"id":"122102","messageId":"20090830075140.GB14217@coredump.intra.peff.net","threadId":"20765","inReplyTo":"81b0412b0908300025r4eeee84fyf0bfc3b2e940ff37@mail.gmail.com","subject":"Re: [PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T07:51:40Z","receivedAt":"2009-08-30T07:51:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 09:25:11AM +0200, Alex Riesen wrote:\n\n> > Is this intended as a serious submission for inclusion?\n> \n> Not yet. AFAICS, test-date is never used in our test suite.\n\nNo, it isn't, but I think the point of this is to change that.\nSo it is useless without an extra patch to the test suite. I'll try to\nput something together.\n\n> Right, that's because I'm not sure myself. Frankly, I'm not\n> convinced we have to test every single thing. In my experience,\n> the bigger a test suite, the less are people inclined to use it\n> (including setting up automatic test runs).\n> \n> Jeff, Nicolas? Is this test enough? Are there any other code\n> paths you want to include in the test?\n\nI think this is a useful addition to the test suite. The bug David fixed\nwas obvious, but it sat for a year because of poor test coverage. Linus\nfixed several approxidate bugs recently. The approxidate code is\nnotoriously temperamental, so it is a good thing to be checking for\nregressions.\n\nAnd I don't think our test suite is nearly big enough to start worrying\nabout getting people not to use it. Without CVS and SVN tests, I can run\nit on 3-year-old hardware in less than a minute. Either you bother to\nrun it or not, but I doubt that adding one new test script is going to\nbreak the bank.\n\n-Peff\n"},{"id":"122103","messageId":"81b0412b0908300110l5dd07b9ejdd0e2af7df517542@mail.gmail.com","threadId":"20765","inReplyTo":"20090830075140.GB14217@coredump.intra.peff.net","subject":"Re: [PATCH] Allow testing of _relative family of time formatting and parsing functions","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-30T08:10:44Z","receivedAt":"2009-08-30T08:10:44Z","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:51, Jeff King<peff@peff.net> wrote:\n> On Sun, Aug 30, 2009 at 09:25:11AM +0200, Alex Riesen wrote:\n>\n>> > Is this intended as a serious submission for inclusion?\n>>\n>> Not yet. AFAICS, test-date is never used in our test suite.\n>\n> No, it isn't, but I think the point of this is to change that.\n> So it is useless without an extra patch to the test suite. I'll try to\n> put something together.\n\nThanks :)\n"},{"id":"122106","messageId":"20090830091346.GA14928@blimp.localdomain","threadId":"20765","inReplyTo":"81b0412b0908300025r4eeee84fyf0bfc3b2e940ff37@mail.gmail.com","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-30T09:13:46Z","receivedAt":"2009-08-30T09:13:46Z","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\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nHave show_date_relative supplied the output buffer. As it is a new\ninterface, it can as well be a little bit more generic than its sole\ncaller. test-date.c is updated and shall follow in a moment.\n\nAnd, after a while thinking, I am convinced that Jeff has a point\nand used a more \"internal\" name for approxidate's recent \"bottom half\".\n\n cache.h |    5 ++\n date.c  |  152 +++++++++++++++++++++++++++++++++++++--------------------------\n 2 files changed, 94 insertions(+), 63 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex dd7f71e..1586f33 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -731,9 +731,14 @@ 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,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size);\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..0b0f7a7 100644\n--- a/date.c\n+++ b/date.c\n@@ -84,6 +84,68 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n+const char *show_date_relative(unsigned long time, int tz,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size)\n+{\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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%lu year%s\",\n+\t\t\t     years, (years > 1 ? \"s\" : \"\"));\n+\t\tif (months)\n+\t\t\tsnprintf(timebuf + n, timebuf_size - 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, timebuf_size - 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, timebuf_size, \"%lu years ago\", (diff + 183) / 365);\n+\treturn timebuf;\n+}\n+\n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n \tstruct tm *tm;\n@@ -95,63 +157,10 @@ 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\t\t\t\t  timebuf, sizeof(timebuf));\n \t}\n \n \tif (mode == DATE_LOCAL)\n@@ -866,19 +875,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 approxidate_str(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 +902,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 approxidate_str(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 approxidate_str(date, &tv);\n+}\n+\n-- \n1.6.4.1.294.g16262\n"},{"id":"122105","messageId":"20090830091541.GB14928@blimp.localdomain","threadId":"20765","inReplyTo":"20090830091346.GA14928@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-30T09:15:41Z","receivedAt":"2009-08-30T09:15:41Z","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\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\n---\n\nAlex Riesen, Sun, Aug 30, 2009 11:13:46 +0200:\n> test-date.c is updated and shall follow in a moment.\n\nhere it goes.\n\n test-date.c |   20 ++++++++++++++++++++\n 1 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/test-date.c b/test-date.c\nindex 62e8f23..4cb146d 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -4,6 +4,19 @@ int main(int argc, char **argv)\n {\n \tint i;\n \n+\t/* see date.c, function show_date_relative */\n+\tchar timebuf[(sizeof(long) * 5 / 2 + sizeof(\" minutes ago,\")) * 2];\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 +28,13 @@ 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\", argv[i], ctime(&t));\n+\n+\t\tprintf(\"relative: %s, out of %s\",\n+\t\t       show_date_relative(t, 0, &when, timebuf,sizeof(timebuf)),\n+\t\t       ctime(&t));\n \t}\n \treturn 0;\n }\n-- \n1.6.4.1.294.g16262\n"},{"id":"122107","messageId":"20090830091557.GA28531@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830091346.GA14928@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-30T09:15:57Z","receivedAt":"2009-08-30T09:15:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 11:13:46AM +0200, Alex Riesen wrote:\n\n> Have show_date_relative supplied the output buffer. As it is a new\n> interface, it can as well be a little bit more generic than its sole\n> caller. test-date.c is updated and shall follow in a moment.\n\nFYI, I am munging test-date to match the test script I am writing, so\ndon't bother with that patch.\n\n-Peff\n"},{"id":"122108","messageId":"20090830093642.GA30922@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830091557.GA28531@coredump.intra.peff.net","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-30T09:36:42Z","receivedAt":"2009-08-30T09:36:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 05:15:57AM -0400, Jeff King wrote:\n\n> FYI, I am munging test-date to match the test script I am writing, so\n> don't bother with that patch.\n\nHere is what my patch is looking like. Please give any comments, and\nthen I will resubmit in a form that will be simpler for Junio, which\nshould be a series with:\n\n  - your patch to refactor date.c\n  - this patch (this version uses the original interface to\n    show_relative; I will tweak to match the new patch you just sent)\n  - another patch to go on top of lt/approxidate to test recent fixes\n    from Linus\n\n---\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nnew file mode 100755\nindex 0000000..4beb44b\n--- /dev/null\n+++ b/t/t0006-date.sh\n@@ -0,0 +1,71 @@\n+#!/bin/sh\n+\n+test_description='test date parsing and printing'\n+. ./test-lib.sh\n+\n+# arbitrary reference time: 2009-08-30 19:20:00\n+TEST_DATE_NOW=1251660000; export TEST_DATE_NOW\n+\n+check_show() {\n+\tt=$(($TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_success \"relative date ($2)\" \"\n+\ttest-date show $t >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_show 5 '5 seconds ago'\n+check_show 300 '5 minutes ago'\n+check_show 18000 '5 hours ago'\n+check_show 432000 '5 days ago'\n+check_show 1728000 '3 weeks ago'\n+check_show 13000000 '5 months ago'\n+check_show 37500000 '1 year, 2 months ago'\n+check_show 55188000 '1 year, 9 months ago'\n+check_show 630000000 '20 years ago'\n+\n+check_parse() {\n+\techo \"$1 -> $2\" >expect\n+\ttest_expect_success \"parse date ($1)\" \"\n+\ttest-date parse '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_parse 2008 bad\n+check_parse 2008-02 bad\n+check_parse 2008-02-14 '2008-02-14 00:00:00 +0000'\n+check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'\n+\n+check_approxidate() {\n+\techo \"$1 -> $2 +0000\" >expect\n+\ttest_expect_success \"parse approxidate ($1)\" \"\n+\ttest-date approxidate '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_approxidate now '2009-08-30 19:20:00'\n+check_approxidate '5 seconds ago' '2009-08-30 19:19:55'\n+check_approxidate 5.seconds.ago '2009-08-30 19:19:55'\n+check_approxidate 10.minutes.ago '2009-08-30 19:10:00'\n+check_approxidate yesterday '2009-08-29 19:20:00'\n+check_approxidate 3.days.ago '2009-08-27 19:20:00'\n+check_approxidate 3.weeks.ago '2009-08-09 19:20:00'\n+check_approxidate 3.months.ago '2009-05-30 19:20:00'\n+check_approxidate 2.years.3.months.ago '2007-05-30 19:20:00'\n+\n+check_approxidate '6am yesterday' '2009-08-29 06:00:00'\n+check_approxidate '6pm yesterday' '2009-08-29 18:00:00'\n+check_approxidate '3:00' '2009-08-30 03:00:00'\n+check_approxidate '15:00' '2009-08-30 15:00:00'\n+check_approxidate 'noon today' '2009-08-30 12:00:00'\n+check_approxidate 'noon yesterday' '2009-08-29 12:00:00'\n+\n+check_approxidate 'last tuesday' '2009-08-25 19:20:00'\n+check_approxidate 'July 5th' '2009-07-05 19:20:00'\n+check_approxidate '06/05/2009' '2009-06-05 00:00:00'\n+check_approxidate '06.05.2009' '2009-05-06 00:00:00'\n+\n+test_done\ndiff --git a/test-date.c b/test-date.c\nindex 62e8f23..8d263a3 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -1,20 +1,63 @@\n #include \"cache.h\"\n \n-int main(int argc, char **argv)\n+static const char *usage_msg = \"\\n\"\n+\"  test-date show [time_t]...\\n\"\n+\"  test-date parse [date]...\\n\"\n+\"  test-date approxidate [date]...\\n\";\n+\n+static void show_dates(char **argv, struct timeval *now)\n {\n-\tint i;\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date_relative(t, 0, now));\n+\t}\n+}\n \n-\tfor (i = 1; i < argc; i++) {\n+static void parse_dates(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n \t\tchar result[100];\n \t\ttime_t t;\n \n-\t\tmemcpy(result, \"bad\", 4);\n-\t\tparse_date(argv[i], result, sizeof(result));\n+\t\tparse_date(*argv, result, sizeof(result));\n \t\tt = strtoul(result, NULL, 0);\n-\t\tprintf(\"%s -> %s -> %s\", argv[i], result, ctime(&t));\n+\t\tprintf(\"%s -> %s\\n\", *argv,\n+\t\t\tt ? show_date(t, 0, DATE_ISO8601) : \"bad\");\n+\t}\n+}\n+\n+static void parse_approxidate(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t;\n+\t\tt = approxidate_relative(*argv, now);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_ISO8601));\n+\t}\n+}\n \n-\t\tt = approxidate(argv[i]);\n-\t\tprintf(\"%s -> %s\\n\", argv[i], ctime(&t));\n+int main(int argc, char **argv)\n+{\n+\tstruct timeval now;\n+\tconst char *x;\n+\n+\tx = getenv(\"TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow.tv_sec = atoi(x);\n+\t\tnow.tv_usec = 0;\n \t}\n+\telse\n+\t\tgettimeofday(&now, NULL);\n+\n+\targv++;\n+\tif (!*argv)\n+\t\tusage(usage_msg);\n+\tif (!strcmp(*argv, \"show\"))\n+\t\tshow_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"parse\"))\n+\t\tparse_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"approxidate\"))\n+\t\tparse_approxidate(argv+1, &now);\n+\telse\n+\t\tusage(usage_msg);\n \treturn 0;\n }\n"},{"id":"122110","messageId":"81b0412b0908300256l13d308d9oc30172a20a9f6108@mail.gmail.com","threadId":"20765","inReplyTo":"20090830093642.GA30922@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-30T09:56:37Z","receivedAt":"2009-08-30T09:56:37Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Sun, Aug 30, 2009 at 11:36, Jeff King<peff@peff.net> wrote:\n> On Sun, Aug 30, 2009 at 05:15:57AM -0400, Jeff King wrote:\n>\n>> FYI, I am munging test-date to match the test script I am writing, so\n>> don't bother with that patch.\n>\n> Here is what my patch is looking like. Please give any comments, and\n> then I will resubmit in a form that will be simpler for Junio, which\n> should be a series with:\n>\n>  - your patch to refactor date.c\n>  - this patch (this version uses the original interface to\n>    show_relative; I will tweak to match the new patch you just sent)\n\nYes, I think this is the only comment I can make.\n\n> +# arbitrary reference time: 2009-08-30 19:20:00\n\nThe world changed since 1980 :) There is already three things\nhappened at the day (http://en.wikipedia.org/wiki/August_2009),\nand it is not evening yet (well, here in Europe)\n\n> +check_show 5 '5 seconds ago'\n> +check_show 300 '5 minutes ago'\n> +check_show 18000 '5 hours ago'\n> +check_show 432000 '5 days ago'\n> +check_show 1728000 '3 weeks ago'\n> +check_show 13000000 '5 months ago'\n> +check_show 37500000 '1 year, 2 months ago'\n> +check_show 55188000 '1 year, 9 months ago'\n> +check_show 630000000 '20 years ago'\n\ncheck_show 630000000 '20.years.ago'?\n(Arbitrary, non-whitespace delimiters, which was an\nadvertised feature, to make shell's life easier)\n"},{"id":"122111","messageId":"20090830100826.GA31543@coredump.intra.peff.net","threadId":"20765","inReplyTo":"81b0412b0908300256l13d308d9oc30172a20a9f6108@mail.gmail.com","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-30T10:08:26Z","receivedAt":"2009-08-30T10:08:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 11:56:37AM +0200, Alex Riesen wrote:\n\n> > +check_show 5 '5 seconds ago'\n> > +check_show 300 '5 minutes ago'\n> > +check_show 18000 '5 hours ago'\n> > +check_show 432000 '5 days ago'\n> > +check_show 1728000 '3 weeks ago'\n> > +check_show 13000000 '5 months ago'\n> > +check_show 37500000 '1 year, 2 months ago'\n> > +check_show 55188000 '1 year, 9 months ago'\n> > +check_show 630000000 '20 years ago'\n> \n> check_show 630000000 '20.years.ago'?\n> (Arbitrary, non-whitespace delimiters, which was an\n> advertised feature, to make shell's life easier)\n\nThis part is about checking what show_date produces (the first number is\nan offset from now in seconds, and the second is what we expect), so it\nalways has spaces.\n\nSee the check_approxidate section further down for an example of parsing\nwhat you are talking about.\n\n-Peff\n"},{"id":"122114","messageId":"81b0412b0908300417x1b909242hcd13a00587d6d33c@mail.gmail.com","threadId":"20765","inReplyTo":"20090830100826.GA31543@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-30T11:17:28Z","receivedAt":"2009-08-30T11:17:28Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Sun, Aug 30, 2009 at 12:08, Jeff King<peff@peff.net> wrote:\n> On Sun, Aug 30, 2009 at 11:56:37AM +0200, Alex Riesen wrote:\n>>\n>> check_show 630000000 '20.years.ago'?\n>> (Arbitrary, non-whitespace delimiters, which was an\n>> advertised feature, to make shell's life easier)\n>\n> This part is about checking what show_date produces (the first number is\n> an offset from now in seconds, and the second is what we expect), so it\n> always has spaces.\n>\n> See the check_approxidate section further down for an example of parsing\n> what you are talking about.\n\nAh, I see\n"},{"id":"122139","messageId":"20090830214309.GA16119@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830093642.GA30922@coredump.intra.peff.net","subject":"[PATCH 1/3] Add date formatting and parsing functions relative to a given time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T21:43:09Z","receivedAt":"2009-08-30T21:43:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"From: Alex Riesen <raa.lkml@gmail.com>\n\nThe main purpose is to allow predictable testing of the code.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\nSigned-off-by: Jeff King <peff@peff.net>\n---\n cache.h |    5 ++\n date.c  |  152 +++++++++++++++++++++++++++++++++++++--------------------------\n 2 files changed, 94 insertions(+), 63 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 808daba..5fad24c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -731,9 +731,14 @@ 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,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size);\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..0b0f7a7 100644\n--- a/date.c\n+++ b/date.c\n@@ -84,6 +84,68 @@ static int local_tzoffset(unsigned long time)\n \treturn offset * eastwest;\n }\n \n+const char *show_date_relative(unsigned long time, int tz,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size)\n+{\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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%lu year%s\",\n+\t\t\t     years, (years > 1 ? \"s\" : \"\"));\n+\t\tif (months)\n+\t\t\tsnprintf(timebuf + n, timebuf_size - 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, timebuf_size - 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, timebuf_size, \"%lu years ago\", (diff + 183) / 365);\n+\treturn timebuf;\n+}\n+\n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n \tstruct tm *tm;\n@@ -95,63 +157,10 @@ 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\t\t\t\t  timebuf, sizeof(timebuf));\n \t}\n \n \tif (mode == DATE_LOCAL)\n@@ -866,19 +875,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 approxidate_str(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 +902,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 approxidate_str(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 approxidate_str(date, &tv);\n+}\n+\n-- \n1.6.4.2.375.g73938\n"},{"id":"122140","messageId":"20090830214604.GB16119@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830093642.GA30922@coredump.intra.peff.net","subject":"[PATCH 2/3] refactor test-date interface","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T21:46:04Z","receivedAt":"2009-08-30T21:46:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The test-date program goes back to the early days of git,\nwhere it was presumably used to do manual sanity checks on\nchanges to the date code. However, it is not actually used\nby the test suite to do any sort of automatic of systematic\ntests.\n\nThis patch refactors the interface to the program to try to\nmake it more suitable for use by the test suite. There\nshould be no fallouts to changing the interface since it is\nnot actually installed and is not internally called by any\nother programs.\n\nThe changes are:\n\n  - add a \"mode\" parameter so the caller can specify which\n    operation to test\n\n  - add a mode to test relative date output from show_date\n\n  - allow faking a fixed time via the TEST_DATE_NOW\n    environment variable, which allows consistent automated\n    testing\n\n  - drop the use of ctime for showing dates in favor of our\n    internal iso8601 printing routines. The ctime output is\n    somewhat redundant (because of the day-of-week) which\n    makes writing test cases more annoying.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI mulled over replacing ctime for a bit, as we are testing git's date\ncode with other parts of git's date code. But it really is more\nconvenient for writing test cases to use iso8601, since you don't have\nto calculate the day-of-week (and I also think it is a bit more\nreadable). And our iso8601 code is dead simple, so I am not too worried\nabout a bug in it hiding a bug elsewhere.\n\n test-date.c |   86 +++++++++++++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 66 insertions(+), 20 deletions(-)\n rewrite test-date.c (63%)\n\ndiff --git a/test-date.c b/test-date.c\ndissimilarity index 63%\nindex 62e8f23..5b0a220 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -1,20 +1,66 @@\n-#include \"cache.h\"\n-\n-int main(int argc, char **argv)\n-{\n-\tint i;\n-\n-\tfor (i = 1; i < argc; i++) {\n-\t\tchar result[100];\n-\t\ttime_t t;\n-\n-\t\tmemcpy(result, \"bad\", 4);\n-\t\tparse_date(argv[i], result, sizeof(result));\n-\t\tt = strtoul(result, NULL, 0);\n-\t\tprintf(\"%s -> %s -> %s\", argv[i], result, ctime(&t));\n-\n-\t\tt = approxidate(argv[i]);\n-\t\tprintf(\"%s -> %s\\n\", argv[i], ctime(&t));\n-\t}\n-\treturn 0;\n-}\n+#include \"cache.h\"\n+\n+static const char *usage_msg = \"\\n\"\n+\"  test-date show [time_t]...\\n\"\n+\"  test-date parse [date]...\\n\"\n+\"  test-date approxidate [date]...\\n\";\n+\n+static void show_dates(char **argv, struct timeval *now)\n+{\n+\tchar buf[128];\n+\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tshow_date_relative(t, 0, now, buf, sizeof(buf));\n+\t\tprintf(\"%s -> %s\\n\", *argv, buf);\n+\t}\n+}\n+\n+static void parse_dates(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n+\t\tchar result[100];\n+\t\ttime_t t;\n+\n+\t\tparse_date(*argv, result, sizeof(result));\n+\t\tt = strtoul(result, NULL, 0);\n+\t\tprintf(\"%s -> %s\\n\", *argv,\n+\t\t\tt ? show_date(t, 0, DATE_ISO8601) : \"bad\");\n+\t}\n+}\n+\n+static void parse_approxidate(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t;\n+\t\tt = approxidate_relative(*argv, now);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_ISO8601));\n+\t}\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tstruct timeval now;\n+\tconst char *x;\n+\n+\tx = getenv(\"TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow.tv_sec = atoi(x);\n+\t\tnow.tv_usec = 0;\n+\t}\n+\telse\n+\t\tgettimeofday(&now, NULL);\n+\n+\targv++;\n+\tif (!*argv)\n+\t\tusage(usage_msg);\n+\tif (!strcmp(*argv, \"show\"))\n+\t\tshow_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"parse\"))\n+\t\tparse_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"approxidate\"))\n+\t\tparse_approxidate(argv+1, &now);\n+\telse\n+\t\tusage(usage_msg);\n+\treturn 0;\n+}\n-- \n1.6.4.2.375.g73938\n"},{"id":"122141","messageId":"20090830214741.GC16119@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830093642.GA30922@coredump.intra.peff.net","subject":"[PATCH 3/3] tests: add date printing and parsing tests","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T21:47:41Z","receivedAt":"2009-08-30T21:47:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Until now, there was no coverage of relative date printing\nor approxidate parsing routines (mainly because we had no\nway of faking the \"now\" time for relative date calculations,\nwhich made consistent testing impossible).\n\nThis new script tries to exercise the basic features of\nshow_date and approxidate. The only specific problem case\ntested is showing relative year/month dates in the latter\nhalf of a year, as fixed by 607a9e8.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nLike I said, this is really just to exercise the basic code paths.\nBut now that the infrastructure is there, we can add any corner cases\nor verify new features or bug fixes as they come up. Patches welcome. :)\n\n t/t0006-date.sh |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 71 insertions(+), 0 deletions(-)\n create mode 100755 t/t0006-date.sh\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nnew file mode 100755\nindex 0000000..4beb44b\n--- /dev/null\n+++ b/t/t0006-date.sh\n@@ -0,0 +1,71 @@\n+#!/bin/sh\n+\n+test_description='test date parsing and printing'\n+. ./test-lib.sh\n+\n+# arbitrary reference time: 2009-08-30 19:20:00\n+TEST_DATE_NOW=1251660000; export TEST_DATE_NOW\n+\n+check_show() {\n+\tt=$(($TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_success \"relative date ($2)\" \"\n+\ttest-date show $t >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_show 5 '5 seconds ago'\n+check_show 300 '5 minutes ago'\n+check_show 18000 '5 hours ago'\n+check_show 432000 '5 days ago'\n+check_show 1728000 '3 weeks ago'\n+check_show 13000000 '5 months ago'\n+check_show 37500000 '1 year, 2 months ago'\n+check_show 55188000 '1 year, 9 months ago'\n+check_show 630000000 '20 years ago'\n+\n+check_parse() {\n+\techo \"$1 -> $2\" >expect\n+\ttest_expect_success \"parse date ($1)\" \"\n+\ttest-date parse '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_parse 2008 bad\n+check_parse 2008-02 bad\n+check_parse 2008-02-14 '2008-02-14 00:00:00 +0000'\n+check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'\n+\n+check_approxidate() {\n+\techo \"$1 -> $2 +0000\" >expect\n+\ttest_expect_success \"parse approxidate ($1)\" \"\n+\ttest-date approxidate '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_approxidate now '2009-08-30 19:20:00'\n+check_approxidate '5 seconds ago' '2009-08-30 19:19:55'\n+check_approxidate 5.seconds.ago '2009-08-30 19:19:55'\n+check_approxidate 10.minutes.ago '2009-08-30 19:10:00'\n+check_approxidate yesterday '2009-08-29 19:20:00'\n+check_approxidate 3.days.ago '2009-08-27 19:20:00'\n+check_approxidate 3.weeks.ago '2009-08-09 19:20:00'\n+check_approxidate 3.months.ago '2009-05-30 19:20:00'\n+check_approxidate 2.years.3.months.ago '2007-05-30 19:20:00'\n+\n+check_approxidate '6am yesterday' '2009-08-29 06:00:00'\n+check_approxidate '6pm yesterday' '2009-08-29 18:00:00'\n+check_approxidate '3:00' '2009-08-30 03:00:00'\n+check_approxidate '15:00' '2009-08-30 15:00:00'\n+check_approxidate 'noon today' '2009-08-30 12:00:00'\n+check_approxidate 'noon yesterday' '2009-08-29 12:00:00'\n+\n+check_approxidate 'last tuesday' '2009-08-25 19:20:00'\n+check_approxidate 'July 5th' '2009-07-05 19:20:00'\n+check_approxidate '06/05/2009' '2009-06-05 00:00:00'\n+check_approxidate '06.05.2009' '2009-05-06 00:00:00'\n+\n+test_done\n-- \n1.6.4.2.375.g73938\n"},{"id":"122142","messageId":"20090830215127.GA16303@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830214309.GA16119@coredump.intra.peff.net","subject":"Re: [PATCH 1/3] Add date formatting and parsing functions relative to a given time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-30T21:51:27Z","receivedAt":"2009-08-30T21:51:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 05:43:09PM -0400, Jeff King wrote:\n\n> From: Alex Riesen <raa.lkml@gmail.com>\n> \n> The main purpose is to allow predictable testing of the code.\n> \n> Signed-off-by: Alex Riesen <raa.lkml@gmail.com>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n\nBleh. I just started working on a 4/3 that would test Linus' recent\napproxidate changes, but then I realized that this massive date.c\nrefactoring conflicts with his changes.\n\nI think the most sane thing is to rebase the whole series on top of\nlt/approxidate. Let me see what I can do.\n\n-Peff\n"},{"id":"122155","messageId":"20090831022228.GA4833@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090830215127.GA16303@coredump.intra.peff.net","subject":"Re: [PATCH 1/3] Add date formatting and parsing functions relative to a given time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-31T02:22:28Z","receivedAt":"2009-08-31T02:22:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 05:51:27PM -0400, Jeff King wrote:\n\n> I think the most sane thing is to rebase the whole series on top of\n> lt/approxidate. Let me see what I can do.\n\nAnd here it is. It was a little more complex than a simple rebase\nbecause lt/approxidate actually introduced new bugs. :) Hopefully this\nwill be the last re-roll required.\n\nThe new series applies on top of lt/approxidate, and contains:\n\n  [1/4]: Add date formatting and parsing functions relative to a given time\n  [2/4]: refactor test-date interface\n  [3/4]: tests: add date printing and parsing tests\n  [4/4]: fix approxidate parsing of relative months and years\n\n-Peff\n"},{"id":"122156","messageId":"20090831022605.GA5507@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090831022228.GA4833@coredump.intra.peff.net","subject":"[PATCH v2 1/4] Add date formatting and parsing functions relative to a given time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-31T02:26:05Z","receivedAt":"2009-08-31T02:26:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"From: Alex Riesen <raa.lkml@gmail.com>\n\nThe main purpose is to allow predictable testing of the code.\n\nSigned-off-by: Alex Riesen <raa.lkml@gmail.com>\nSigned-off-by: Jeff King <peff@peff.net>\n---\nSame as previous 1/3, but rebased onto lt/approxidate topic. The merge\nended up as quite a mess because of textual differences, so I had to\nfix up a fair bit by hand; Alex, please confirm that I didn't screw\nanything up too badly right before putting your name at the top. ;)\n\n cache.h |    5 ++\n date.c  |  150 ++++++++++++++++++++++++++++++++++++--------------------------\n 2 files changed, 92 insertions(+), 63 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 808daba..5fad24c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -731,9 +731,14 @@ 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,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size);\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 e848d96..8e57e5e 100644\n--- a/date.c\n+++ b/date.c\n@@ -86,6 +86,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,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       char *timebuf,\n+\t\t\t       size_t timebuf_size)\n+{\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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%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, timebuf_size, \"%lu year%s\",\n+\t\t\t\tyears, (years > 1 ? \"s\" : \"\"));\n+\t\tif (months)\n+\t\t\tsnprintf(timebuf + n, timebuf_size - n,\n+\t\t\t\t\t\", %lu month%s ago\",\n+\t\t\t\t\tmonths, (months > 1 ? \"s\" : \"\"));\n+\t\telse\n+\t\t\tsnprintf(timebuf + n, timebuf_size - n, \" ago\");\n+\t\treturn timebuf;\n+\t}\n+\t/* Otherwise, just years. Centuries is probably overkill. */\n+\tsnprintf(timebuf, timebuf_size, \"%lu years ago\", (diff + 183) / 365);\n+\treturn timebuf;\n+}\n+\n const char *show_date(unsigned long time, int tz, enum date_mode mode)\n {\n \tstruct tm *tm;\n@@ -97,63 +158,10 @@ 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\t\t\t\t  timebuf, sizeof(timebuf));\n \t}\n \n \tif (mode == DATE_LOCAL)\n@@ -918,19 +926,13 @@ static void pending_number(struct tm *tm, int *num)\n \t}\n }\n \n-unsigned long approxidate(const char *date)\n+static unsigned long approxidate_str(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 \n@@ -954,3 +956,25 @@ unsigned long approxidate(const char *date)\n \tpending_number(&tm, &number);\n \treturn update_tm(&tm, &now, 0);\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, 0);\n+\n+\treturn approxidate_str(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, 0);\n+\n+\tgettimeofday(&tv, NULL);\n+\treturn approxidate_str(date, &tv);\n+}\n-- \n1.6.4.2.373.g5881fd\n"},{"id":"122157","messageId":"20090831022646.GB5507@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090831022228.GA4833@coredump.intra.peff.net","subject":"[PATCH v2 2/4] refactor test-date interface","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-31T02:26:46Z","receivedAt":"2009-08-31T02:26:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The test-date program goes back to the early days of git,\nwhere it was presumably used to do manual sanity checks on\nchanges to the date code. However, it is not actually used\nby the test suite to do any sort of automatic of systematic\ntests.\n\nThis patch refactors the interface to the program to try to\nmake it more suitable for use by the test suite. There\nshould be no fallouts to changing the interface since it is\nnot actually installed and is not internally called by any\nother programs.\n\nThe changes are:\n\n  - add a \"mode\" parameter so the caller can specify which\n    operation to test\n\n  - add a mode to test relative date output from show_date\n\n  - allow faking a fixed time via the TEST_DATE_NOW\n    environment variable, which allows consistent automated\n    testing\n\n  - drop the use of ctime for showing dates in favor of our\n    internal iso8601 printing routines. The ctime output is\n    somewhat redundant (because of the day-of-week) which\n    makes writing test cases more annoying.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nSame as earlier 2/3.\n\n test-date.c |   86 +++++++++++++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 66 insertions(+), 20 deletions(-)\n rewrite test-date.c (63%)\n\ndiff --git a/test-date.c b/test-date.c\ndissimilarity index 63%\nindex 62e8f23..5b0a220 100644\n--- a/test-date.c\n+++ b/test-date.c\n@@ -1,20 +1,66 @@\n-#include \"cache.h\"\n-\n-int main(int argc, char **argv)\n-{\n-\tint i;\n-\n-\tfor (i = 1; i < argc; i++) {\n-\t\tchar result[100];\n-\t\ttime_t t;\n-\n-\t\tmemcpy(result, \"bad\", 4);\n-\t\tparse_date(argv[i], result, sizeof(result));\n-\t\tt = strtoul(result, NULL, 0);\n-\t\tprintf(\"%s -> %s -> %s\", argv[i], result, ctime(&t));\n-\n-\t\tt = approxidate(argv[i]);\n-\t\tprintf(\"%s -> %s\\n\", argv[i], ctime(&t));\n-\t}\n-\treturn 0;\n-}\n+#include \"cache.h\"\n+\n+static const char *usage_msg = \"\\n\"\n+\"  test-date show [time_t]...\\n\"\n+\"  test-date parse [date]...\\n\"\n+\"  test-date approxidate [date]...\\n\";\n+\n+static void show_dates(char **argv, struct timeval *now)\n+{\n+\tchar buf[128];\n+\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tshow_date_relative(t, 0, now, buf, sizeof(buf));\n+\t\tprintf(\"%s -> %s\\n\", *argv, buf);\n+\t}\n+}\n+\n+static void parse_dates(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n+\t\tchar result[100];\n+\t\ttime_t t;\n+\n+\t\tparse_date(*argv, result, sizeof(result));\n+\t\tt = strtoul(result, NULL, 0);\n+\t\tprintf(\"%s -> %s\\n\", *argv,\n+\t\t\tt ? show_date(t, 0, DATE_ISO8601) : \"bad\");\n+\t}\n+}\n+\n+static void parse_approxidate(char **argv, struct timeval *now)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t;\n+\t\tt = approxidate_relative(*argv, now);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_ISO8601));\n+\t}\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tstruct timeval now;\n+\tconst char *x;\n+\n+\tx = getenv(\"TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow.tv_sec = atoi(x);\n+\t\tnow.tv_usec = 0;\n+\t}\n+\telse\n+\t\tgettimeofday(&now, NULL);\n+\n+\targv++;\n+\tif (!*argv)\n+\t\tusage(usage_msg);\n+\tif (!strcmp(*argv, \"show\"))\n+\t\tshow_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"parse\"))\n+\t\tparse_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"approxidate\"))\n+\t\tparse_approxidate(argv+1, &now);\n+\telse\n+\t\tusage(usage_msg);\n+\treturn 0;\n+}\n-- \n1.6.4.2.373.g5881fd\n"},{"id":"122158","messageId":"20090831023015.GC5507@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090831022228.GA4833@coredump.intra.peff.net","subject":"[PATCH v2 3/4] tests: add date printing and parsing tests","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-31T02:30:16Z","receivedAt":"2009-08-31T02:30:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Until now, there was no coverage of relative date printing\nor approxidate parsing routines (mainly because we had no\nway of faking the \"now\" time for relative date calculations,\nwhich made consistent testing impossible).\n\nThis new script tries to exercise the basic features of\nshow_date and approxidate. Most of the tests are just \"this\nobvious thing works\" to prevent future regressions, with a\nfew exceptions:\n\n  - We confirm the fix in 607a9e8 that relative year/month\n    dates in the latter half of a year round correctly.\n\n  - We confirm that the improvements in b5373e9 and 1bddb25\n    work.\n\n  - A few tests are marked to expect failure, which are\n    regressions recently introduced by the two commits\n    above.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nSimilar to earlier 3/3, but improvements and regressions from\nlt/approxidate included.\n\nLinus, when you posted the approxidate fixes earlier, you mentioned you\nmight have some other corner cases. I think you were just referring to\nthe stuff you improved in the followup patch, but if you know of more\nbroken-ness, we should probably include it here.\n\n t/t0006-date.sh |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 75 insertions(+), 0 deletions(-)\n create mode 100755 t/t0006-date.sh\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nnew file mode 100755\nindex 0000000..02cd565\n--- /dev/null\n+++ b/t/t0006-date.sh\n@@ -0,0 +1,75 @@\n+#!/bin/sh\n+\n+test_description='test date parsing and printing'\n+. ./test-lib.sh\n+\n+# arbitrary reference time: 2009-08-30 19:20:00\n+TEST_DATE_NOW=1251660000; export TEST_DATE_NOW\n+\n+check_show() {\n+\tt=$(($TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_${3:-success} \"relative date ($2)\" \"\n+\ttest-date show $t >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_show 5 '5 seconds ago'\n+check_show 300 '5 minutes ago'\n+check_show 18000 '5 hours ago'\n+check_show 432000 '5 days ago'\n+check_show 1728000 '3 weeks ago'\n+check_show 13000000 '5 months ago'\n+check_show 37500000 '1 year, 2 months ago'\n+check_show 55188000 '1 year, 9 months ago'\n+check_show 630000000 '20 years ago'\n+\n+check_parse() {\n+\techo \"$1 -> $2\" >expect\n+\ttest_expect_${3:-success} \"parse date ($1)\" \"\n+\ttest-date parse '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_parse 2008 bad\n+check_parse 2008-02 bad\n+check_parse 2008-02-14 bad\n+check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'\n+\n+check_approxidate() {\n+\techo \"$1 -> $2 +0000\" >expect\n+\ttest_expect_${3:-success} \"parse approxidate ($1)\" \"\n+\ttest-date approxidate '$1' >actual &&\n+\ttest_cmp expect actual\n+\t\"\n+}\n+\n+check_approxidate now '2009-08-30 19:20:00'\n+check_approxidate '5 seconds ago' '2009-08-30 19:19:55'\n+check_approxidate 5.seconds.ago '2009-08-30 19:19:55'\n+check_approxidate 10.minutes.ago '2009-08-30 19:10:00'\n+check_approxidate yesterday '2009-08-29 19:20:00'\n+check_approxidate 3.days.ago '2009-08-27 19:20:00'\n+check_approxidate 3.weeks.ago '2009-08-09 19:20:00'\n+check_approxidate 3.months.ago '2009-05-30 19:20:00' failure\n+check_approxidate 2.years.3.months.ago '2007-05-30 19:20:00' failure\n+\n+check_approxidate '6am yesterday' '2009-08-29 06:00:00'\n+check_approxidate '6pm yesterday' '2009-08-29 18:00:00'\n+check_approxidate '3:00' '2009-08-30 03:00:00'\n+check_approxidate '15:00' '2009-08-30 15:00:00'\n+check_approxidate 'noon today' '2009-08-30 12:00:00'\n+check_approxidate 'noon yesterday' '2009-08-29 12:00:00'\n+\n+check_approxidate 'last tuesday' '2009-08-25 19:20:00'\n+check_approxidate 'July 5th' '2009-07-05 19:20:00'\n+check_approxidate '06/05/2009' '2009-06-05 19:20:00'\n+check_approxidate '06.05.2009' '2009-05-06 19:20:00'\n+\n+check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00'\n+check_approxidate '5AM Jun 6' '2009-06-06 05:00:00'\n+check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n+\n+test_done\n-- \n1.6.4.2.373.g5881fd\n"},{"id":"122159","messageId":"20090831023142.GD5507@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090831022228.GA4833@coredump.intra.peff.net","subject":"[PATCH v2 4/4] fix approxidate parsing of relative months and years","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-31T02:31:42Z","receivedAt":"2009-08-31T02:31:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"These were broken by b5373e9. The problem is that the code\nmarks the month and year with \"-1\" for \"we don't know it\nyet\", but the month and year code paths were not adjusted to\nfill in the current time before doing their calculations\n(whereas other units follow a different code path and are\nfine).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis one is new from the last series, as it fixes bugs only found in\nlt/approxidate.\n\n date.c          |    5 ++++-\n t/t0006-date.sh |    4 ++--\n 2 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 8e57e5e..e9ee4aa 100644\n--- a/date.c\n+++ b/date.c\n@@ -857,7 +857,9 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm\n \t}\n \n \tif (match_string(date, \"months\") >= 5) {\n-\t\tint n = tm->tm_mon - *num;\n+\t\tint n;\n+\t\tupdate_tm(tm, now, 0); /* fill in date fields if needed */\n+\t\tn = tm->tm_mon - *num;\n \t\t*num = 0;\n \t\twhile (n < 0) {\n \t\t\tn += 12;\n@@ -868,6 +870,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm\n \t}\n \n \tif (match_string(date, \"years\") >= 4) {\n+\t\tupdate_tm(tm, now, 0); /* fill in date fields if needed */\n \t\ttm->tm_year -= *num;\n \t\t*num = 0;\n \t\treturn end;\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 02cd565..a4d8fa8 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -53,8 +53,8 @@ check_approxidate 10.minutes.ago '2009-08-30 19:10:00'\n check_approxidate yesterday '2009-08-29 19:20:00'\n check_approxidate 3.days.ago '2009-08-27 19:20:00'\n check_approxidate 3.weeks.ago '2009-08-09 19:20:00'\n-check_approxidate 3.months.ago '2009-05-30 19:20:00' failure\n-check_approxidate 2.years.3.months.ago '2007-05-30 19:20:00' failure\n+check_approxidate 3.months.ago '2009-05-30 19:20:00'\n+check_approxidate 2.years.3.months.ago '2007-05-30 19:20:00'\n \n check_approxidate '6am yesterday' '2009-08-29 06:00:00'\n check_approxidate '6pm yesterday' '2009-08-29 18:00:00'\n-- \n1.6.4.2.373.g5881fd\n"},{"id":"122166","messageId":"81b0412b0908302308s3d02bb89o786a4b452d67c43@mail.gmail.com","threadId":"20765","inReplyTo":"20090831022605.GA5507@coredump.intra.peff.net","subject":"Re: [PATCH v2 1/4] Add date formatting and parsing functions relative to a given time","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2009-08-31T06:08:37Z","receivedAt":"2009-08-31T06:08:37Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"On Mon, Aug 31, 2009 at 04:26, Jeff King<peff@peff.net> wrote:\n> From: Alex Riesen <raa.lkml@gmail.com>\n>\n> The main purpose is to allow predictable testing of the code.\n>\n> Signed-off-by: Alex Riesen <raa.lkml@gmail.com>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> Same as previous 1/3, but rebased onto lt/approxidate topic. The merge\n> ended up as quite a mess because of textual differences, so I had to\n> fix up a fair bit by hand; Alex, please confirm that I didn't screw\n> anything up too badly right before putting your name at the top. ;)\n\nLooks good.\n"},{"id":"122221","messageId":"20090901030328.GA24938@coredump.intra.peff.net","threadId":"20765","inReplyTo":"20090831023015.GC5507@coredump.intra.peff.net","subject":"Re: [PATCH v2 3/4] tests: add date printing and parsing tests","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-09-01T03:03:28Z","receivedAt":"2009-09-01T03:03:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Aug 30, 2009 at 10:30:15PM -0400, Jeff King wrote:\n\n>   - We confirm that the improvements in b5373e9 and 1bddb25\n>     work.\n\nUgh. I just realized (when explaining how awesome git resurrect was in\nanother mail) that I managed to bungle these commit hashes (and the one\nmentioned in the following patch).\n\nWhat happened is that I was building on the topic branch and lazily did\na \"rebase -i origin\" to fix up my patches. I left the first two patches\nuntouched, of course, but they still ended up with new committer\ninformation.\n\nAs my patches are merged to 'next' already, I think it is too late to\nfixup the commit message. But for posterity, the correct referenced\ncommits are 9029055 and 36e4986.\n\nCaveat rebaser.\n\n-Peff\n"}]}