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 <raa.lkml@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Alex Riesen 2009-08-30 22:26:05 -04:00 committed by Junio C Hamano
parent 36e4986f26
commit 33012fc429
2 changed files with 92 additions and 63 deletions

View file

@ -731,9 +731,14 @@ enum date_mode {
};
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
const char *show_date_relative(unsigned long time, int tz,
const struct timeval *now,
char *timebuf,
size_t timebuf_size);
int parse_date(const char *date, char *buf, int bufsize);
void datestamp(char *buf, int bufsize);
unsigned long approxidate(const char *);
unsigned long approxidate_relative(const char *date, const struct timeval *now);
enum date_mode parse_date_format(const char *format);
#define IDENT_WARN_ON_NO_NAME 1

150
date.c
View file

@ -86,6 +86,67 @@ static int local_tzoffset(unsigned long time)
return offset * eastwest;
}
const char *show_date_relative(unsigned long time, int tz,
const struct timeval *now,
char *timebuf,
size_t timebuf_size)
{
unsigned long diff;
if (now->tv_sec < time)
return "in the future";
diff = now->tv_sec - time;
if (diff < 90) {
snprintf(timebuf, timebuf_size, "%lu seconds ago", diff);
return timebuf;
}
/* Turn it into minutes */
diff = (diff + 30) / 60;
if (diff < 90) {
snprintf(timebuf, timebuf_size, "%lu minutes ago", diff);
return timebuf;
}
/* Turn it into hours */
diff = (diff + 30) / 60;
if (diff < 36) {
snprintf(timebuf, timebuf_size, "%lu hours ago", diff);
return timebuf;
}
/* We deal with number of days from here on */
diff = (diff + 12) / 24;
if (diff < 14) {
snprintf(timebuf, timebuf_size, "%lu days ago", diff);
return timebuf;
}
/* Say weeks for the past 10 weeks or so */
if (diff < 70) {
snprintf(timebuf, timebuf_size, "%lu weeks ago", (diff + 3) / 7);
return timebuf;
}
/* Say months for the past 12 months or so */
if (diff < 360) {
snprintf(timebuf, timebuf_size, "%lu months ago", (diff + 15) / 30);
return timebuf;
}
/* Give years and months for 5 years or so */
if (diff < 1825) {
unsigned long years = diff / 365;
unsigned long months = (diff % 365 + 15) / 30;
int n;
n = snprintf(timebuf, timebuf_size, "%lu year%s",
years, (years > 1 ? "s" : ""));
if (months)
snprintf(timebuf + n, timebuf_size - n,
", %lu month%s ago",
months, (months > 1 ? "s" : ""));
else
snprintf(timebuf + n, timebuf_size - n, " ago");
return timebuf;
}
/* Otherwise, just years. Centuries is probably overkill. */
snprintf(timebuf, timebuf_size, "%lu years ago", (diff + 183) / 365);
return timebuf;
}
const char *show_date(unsigned long time, int tz, enum date_mode mode)
{
struct tm *tm;
@ -97,63 +158,10 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
}
if (mode == DATE_RELATIVE) {
unsigned long diff;
struct timeval now;
gettimeofday(&now, NULL);
if (now.tv_sec < time)
return "in the future";
diff = now.tv_sec - time;
if (diff < 90) {
snprintf(timebuf, sizeof(timebuf), "%lu seconds ago", diff);
return timebuf;
}
/* Turn it into minutes */
diff = (diff + 30) / 60;
if (diff < 90) {
snprintf(timebuf, sizeof(timebuf), "%lu minutes ago", diff);
return timebuf;
}
/* Turn it into hours */
diff = (diff + 30) / 60;
if (diff < 36) {
snprintf(timebuf, sizeof(timebuf), "%lu hours ago", diff);
return timebuf;
}
/* We deal with number of days from here on */
diff = (diff + 12) / 24;
if (diff < 14) {
snprintf(timebuf, sizeof(timebuf), "%lu days ago", diff);
return timebuf;
}
/* Say weeks for the past 10 weeks or so */
if (diff < 70) {
snprintf(timebuf, sizeof(timebuf), "%lu weeks ago", (diff + 3) / 7);
return timebuf;
}
/* Say months for the past 12 months or so */
if (diff < 360) {
snprintf(timebuf, sizeof(timebuf), "%lu months ago", (diff + 15) / 30);
return timebuf;
}
/* Give years and months for 5 years or so */
if (diff < 1825) {
unsigned long years = (diff + 183) / 365;
unsigned long months = (diff % 365 + 15) / 30;
int n;
n = snprintf(timebuf, sizeof(timebuf), "%lu year%s",
years, (years > 1 ? "s" : ""));
if (months)
snprintf(timebuf + n, sizeof(timebuf) - n,
", %lu month%s ago",
months, (months > 1 ? "s" : ""));
else
snprintf(timebuf + n, sizeof(timebuf) - n,
" ago");
return timebuf;
}
/* Otherwise, just years. Centuries is probably overkill. */
snprintf(timebuf, sizeof(timebuf), "%lu years ago", (diff + 183) / 365);
return timebuf;
return show_date_relative(time, tz, &now,
timebuf, sizeof(timebuf));
}
if (mode == DATE_LOCAL)
@ -918,19 +926,13 @@ static void pending_number(struct tm *tm, int *num)
}
}
unsigned long approxidate(const char *date)
static unsigned long approxidate_str(const char *date, const struct timeval *tv)
{
int number = 0;
struct tm tm, now;
struct timeval tv;
time_t time_sec;
char buffer[50];
if (parse_date(date, buffer, sizeof(buffer)) > 0)
return strtoul(buffer, NULL, 10);
gettimeofday(&tv, NULL);
time_sec = tv.tv_sec;
time_sec = tv->tv_sec;
localtime_r(&time_sec, &tm);
now = tm;
@ -954,3 +956,25 @@ unsigned long approxidate(const char *date)
pending_number(&tm, &number);
return update_tm(&tm, &now, 0);
}
unsigned long approxidate_relative(const char *date, const struct timeval *tv)
{
char buffer[50];
if (parse_date(date, buffer, sizeof(buffer)) > 0)
return strtoul(buffer, NULL, 0);
return approxidate_str(date, tv);
}
unsigned long approxidate(const char *date)
{
struct timeval tv;
char buffer[50];
if (parse_date(date, buffer, sizeof(buffer)) > 0)
return strtoul(buffer, NULL, 0);
gettimeofday(&tv, NULL);
return approxidate_str(date, &tv);
}