Skip to content

Commit 33012fc

Browse files
raalkmlgitster
authored andcommitted
Add date formatting and parsing functions relative to a given time
The main purpose is to allow predictable testing of the code. Signed-off-by: Alex Riesen <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 36e4986 commit 33012fc

File tree

2 files changed

+92
-63
lines changed

2 files changed

+92
-63
lines changed

cache.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,9 +731,14 @@ enum date_mode {
731731
};
732732

733733
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
734+
const char *show_date_relative(unsigned long time, int tz,
735+
const struct timeval *now,
736+
char *timebuf,
737+
size_t timebuf_size);
734738
int parse_date(const char *date, char *buf, int bufsize);
735739
void datestamp(char *buf, int bufsize);
736740
unsigned long approxidate(const char *);
741+
unsigned long approxidate_relative(const char *date, const struct timeval *now);
737742
enum date_mode parse_date_format(const char *format);
738743

739744
#define IDENT_WARN_ON_NO_NAME 1

date.c

Lines changed: 87 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,67 @@ static int local_tzoffset(unsigned long time)
8686
return offset * eastwest;
8787
}
8888

89+
const char *show_date_relative(unsigned long time, int tz,
90+
const struct timeval *now,
91+
char *timebuf,
92+
size_t timebuf_size)
93+
{
94+
unsigned long diff;
95+
if (now->tv_sec < time)
96+
return "in the future";
97+
diff = now->tv_sec - time;
98+
if (diff < 90) {
99+
snprintf(timebuf, timebuf_size, "%lu seconds ago", diff);
100+
return timebuf;
101+
}
102+
/* Turn it into minutes */
103+
diff = (diff + 30) / 60;
104+
if (diff < 90) {
105+
snprintf(timebuf, timebuf_size, "%lu minutes ago", diff);
106+
return timebuf;
107+
}
108+
/* Turn it into hours */
109+
diff = (diff + 30) / 60;
110+
if (diff < 36) {
111+
snprintf(timebuf, timebuf_size, "%lu hours ago", diff);
112+
return timebuf;
113+
}
114+
/* We deal with number of days from here on */
115+
diff = (diff + 12) / 24;
116+
if (diff < 14) {
117+
snprintf(timebuf, timebuf_size, "%lu days ago", diff);
118+
return timebuf;
119+
}
120+
/* Say weeks for the past 10 weeks or so */
121+
if (diff < 70) {
122+
snprintf(timebuf, timebuf_size, "%lu weeks ago", (diff + 3) / 7);
123+
return timebuf;
124+
}
125+
/* Say months for the past 12 months or so */
126+
if (diff < 360) {
127+
snprintf(timebuf, timebuf_size, "%lu months ago", (diff + 15) / 30);
128+
return timebuf;
129+
}
130+
/* Give years and months for 5 years or so */
131+
if (diff < 1825) {
132+
unsigned long years = diff / 365;
133+
unsigned long months = (diff % 365 + 15) / 30;
134+
int n;
135+
n = snprintf(timebuf, timebuf_size, "%lu year%s",
136+
years, (years > 1 ? "s" : ""));
137+
if (months)
138+
snprintf(timebuf + n, timebuf_size - n,
139+
", %lu month%s ago",
140+
months, (months > 1 ? "s" : ""));
141+
else
142+
snprintf(timebuf + n, timebuf_size - n, " ago");
143+
return timebuf;
144+
}
145+
/* Otherwise, just years. Centuries is probably overkill. */
146+
snprintf(timebuf, timebuf_size, "%lu years ago", (diff + 183) / 365);
147+
return timebuf;
148+
}
149+
89150
const char *show_date(unsigned long time, int tz, enum date_mode mode)
90151
{
91152
struct tm *tm;
@@ -97,63 +158,10 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
97158
}
98159

99160
if (mode == DATE_RELATIVE) {
100-
unsigned long diff;
101161
struct timeval now;
102162
gettimeofday(&now, NULL);
103-
if (now.tv_sec < time)
104-
return "in the future";
105-
diff = now.tv_sec - time;
106-
if (diff < 90) {
107-
snprintf(timebuf, sizeof(timebuf), "%lu seconds ago", diff);
108-
return timebuf;
109-
}
110-
/* Turn it into minutes */
111-
diff = (diff + 30) / 60;
112-
if (diff < 90) {
113-
snprintf(timebuf, sizeof(timebuf), "%lu minutes ago", diff);
114-
return timebuf;
115-
}
116-
/* Turn it into hours */
117-
diff = (diff + 30) / 60;
118-
if (diff < 36) {
119-
snprintf(timebuf, sizeof(timebuf), "%lu hours ago", diff);
120-
return timebuf;
121-
}
122-
/* We deal with number of days from here on */
123-
diff = (diff + 12) / 24;
124-
if (diff < 14) {
125-
snprintf(timebuf, sizeof(timebuf), "%lu days ago", diff);
126-
return timebuf;
127-
}
128-
/* Say weeks for the past 10 weeks or so */
129-
if (diff < 70) {
130-
snprintf(timebuf, sizeof(timebuf), "%lu weeks ago", (diff + 3) / 7);
131-
return timebuf;
132-
}
133-
/* Say months for the past 12 months or so */
134-
if (diff < 360) {
135-
snprintf(timebuf, sizeof(timebuf), "%lu months ago", (diff + 15) / 30);
136-
return timebuf;
137-
}
138-
/* Give years and months for 5 years or so */
139-
if (diff < 1825) {
140-
unsigned long years = (diff + 183) / 365;
141-
unsigned long months = (diff % 365 + 15) / 30;
142-
int n;
143-
n = snprintf(timebuf, sizeof(timebuf), "%lu year%s",
144-
years, (years > 1 ? "s" : ""));
145-
if (months)
146-
snprintf(timebuf + n, sizeof(timebuf) - n,
147-
", %lu month%s ago",
148-
months, (months > 1 ? "s" : ""));
149-
else
150-
snprintf(timebuf + n, sizeof(timebuf) - n,
151-
" ago");
152-
return timebuf;
153-
}
154-
/* Otherwise, just years. Centuries is probably overkill. */
155-
snprintf(timebuf, sizeof(timebuf), "%lu years ago", (diff + 183) / 365);
156-
return timebuf;
163+
return show_date_relative(time, tz, &now,
164+
timebuf, sizeof(timebuf));
157165
}
158166

159167
if (mode == DATE_LOCAL)
@@ -918,19 +926,13 @@ static void pending_number(struct tm *tm, int *num)
918926
}
919927
}
920928

921-
unsigned long approxidate(const char *date)
929+
static unsigned long approxidate_str(const char *date, const struct timeval *tv)
922930
{
923931
int number = 0;
924932
struct tm tm, now;
925-
struct timeval tv;
926933
time_t time_sec;
927-
char buffer[50];
928934

929-
if (parse_date(date, buffer, sizeof(buffer)) > 0)
930-
return strtoul(buffer, NULL, 10);
931-
932-
gettimeofday(&tv, NULL);
933-
time_sec = tv.tv_sec;
935+
time_sec = tv->tv_sec;
934936
localtime_r(&time_sec, &tm);
935937
now = tm;
936938

@@ -954,3 +956,25 @@ unsigned long approxidate(const char *date)
954956
pending_number(&tm, &number);
955957
return update_tm(&tm, &now, 0);
956958
}
959+
960+
unsigned long approxidate_relative(const char *date, const struct timeval *tv)
961+
{
962+
char buffer[50];
963+
964+
if (parse_date(date, buffer, sizeof(buffer)) > 0)
965+
return strtoul(buffer, NULL, 0);
966+
967+
return approxidate_str(date, tv);
968+
}
969+
970+
unsigned long approxidate(const char *date)
971+
{
972+
struct timeval tv;
973+
char buffer[50];
974+
975+
if (parse_date(date, buffer, sizeof(buffer)) > 0)
976+
return strtoul(buffer, NULL, 0);
977+
978+
gettimeofday(&tv, NULL);
979+
return approxidate_str(date, &tv);
980+
}

0 commit comments

Comments
 (0)