git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/2] date: refactor the relative date logic from presentation

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 16, 2012, 23:02 UTC
Message-ID
<1345158123-22189-2-git-send-email-gitster@pobox.com>
In-Reply-To
<1345158123-22189-1-git-send-email-gitster@pobox.com>

Separate the logic to decide which presentation (e.g. "N months") to use based on the length of the time from the present and actual presentation (i.e. "strbuf_addf()"). This is not strictly needed but will make the next step easier to read.

The format strings lost N_() markings along the way; help from the i18n folks to come up with the best and sane way to mark them up is very much appreciated.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 date.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 127 insertions(+), 43 deletions(-)
diff --git a/date.c b/date.c
index 57331ed..b6ff04e 100644
--- a/date.c
+++ b/date.c
@@ -86,78 +86,162 @@ static int local_tzoffset(unsigned long time)
 	return offset * eastwest;
 }
 
-void show_date_relative(unsigned long time, int tz,
-			       const struct timeval *now,
-			       struct strbuf *timebuf)
+enum relative_style {
+	rd_seconds = 0, rd_minutes, rd_hours, rd_days, rd_weeks, rd_months, rd_years
+};
+
+struct relative_date {
+	int seconds;
+	int minutes;
+	int hours;
+	int days;
+	int weeks;
+	int months;
+	int years;
+};
+
+static enum relative_style format_relative_date(unsigned long diff,
+						struct relative_date *rd)
 {
-	unsigned long diff;
-	if (now->tv_sec < time) {
-		strbuf_addstr(timebuf, _("in the future"));
-		return;
-	}
-	diff = now->tv_sec - time;
+	memset(rd, 0, sizeof(*rd));
 	if (diff < 90) {
-		strbuf_addf(timebuf,
-			 Q_("%lu second ago", "%lu seconds ago", diff), diff);
-		return;
+		rd->seconds = diff;
+		return rd_seconds;
 	}
 	/* Turn it into minutes */
 	diff = (diff + 30) / 60;
 	if (diff < 90) {
-		strbuf_addf(timebuf,
-			 Q_("%lu minute ago", "%lu minutes ago", diff), diff);
-		return;
+		rd->minutes = diff;
+		return rd_minutes;
 	}
 	/* Turn it into hours */
 	diff = (diff + 30) / 60;
 	if (diff < 36) {
-		strbuf_addf(timebuf,
-			 Q_("%lu hour ago", "%lu hours ago", diff), diff);
-		return;
+		rd->hours = diff;
+		return rd_hours;
 	}
 	/* We deal with number of days from here on */
 	diff = (diff + 12) / 24;
 	if (diff < 14) {
-		strbuf_addf(timebuf,
-			 Q_("%lu day ago", "%lu days ago", diff), diff);
-		return;
+		rd->days = diff;
+		return rd_days;
 	}
 	/* Say weeks for the past 10 weeks or so */
 	if (diff < 70) {
-		strbuf_addf(timebuf,
-			 Q_("%lu week ago", "%lu weeks ago", (diff + 3) / 7),
-			 (diff + 3) / 7);
-		return;
+		rd->weeks = (diff + 3) / 7;
+		return rd_weeks;
 	}
 	/* Say months for the past 12 months or so */
 	if (diff < 365) {
-		strbuf_addf(timebuf,
-			 Q_("%lu month ago", "%lu months ago", (diff + 15) / 30),
-			 (diff + 15) / 30);
-		return;
+		rd->months = (diff + 15) / 30;
+		return rd_months;
 	}
 	/* Give years and months for 5 years or so */
 	if (diff < 1825) {
 		unsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);
-		unsigned long years = totalmonths / 12;
-		unsigned long months = totalmonths % 12;
-		if (months) {
+		rd->years = totalmonths / 12;
+		rd->months = totalmonths % 12;
+		return rd_years;
+	}
+	/* Otherwise, just years. Centuries is probably overkill. */
+	rd->years = (diff + 183) / 365;
+	return rd_years;
+}
+
+void show_date_relative(unsigned long time, int tz,
+			       const struct timeval *now,
+			       struct strbuf *timebuf)
+{
+	unsigned long diff;
+	struct relative_date rd;
+	int pf = 0; /* past or future */
+
+	struct {
+		struct { const char *s, *p; } msg_seconds;
+		struct { const char *s, *p; } msg_minutes;
+		struct { const char *s, *p; } msg_hours;
+		struct { const char *s, *p; } msg_days;
+		struct { const char *s, *p; } msg_weeks;
+		struct { const char *s, *p; } msg_months;
+		struct { const char *s, *p; } msg_years_only;
+		struct { const char *s, *p; } msg_years_months;
+		struct { const char *s, *p; } msg_years;
+	} msg[1] = {
+		{
+			{ "%lu second ago", "%lu seconds ago" },
+			{ "%lu minute ago", "%lu minutes ago" },
+			{ "%lu hour ago", "%lu hours ago" },
+			{ "%lu day ago", "%lu days ago" },
+			{ "%lu week ago", "%lu weeks ago" },
+			{ "%lu month ago", "%lu months ago" },
+			{ "%lu year", "%lu years" },
+			{
+				/* TRANSLATORS: "%s" is "<n> years" */
+				"%s, %lu month ago",
+				/* TRANSLATORS: "%s" is "<n> years" */
+				"%s, %lu months ago"
+			},
+			{ "%lu year ago", "%lu years ago" },
+		}
+	};
+
+	if (now->tv_sec < time) {
+		strbuf_addstr(timebuf, _("in the future"));
+		return;
+	}
+	diff = now->tv_sec - time;
+
+	switch (format_relative_date(diff, &rd)) {
+	case rd_seconds:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_seconds.s, msg[pf].msg_seconds.p,
+			       rd.seconds), rd.seconds);
+		break;
+	case rd_minutes:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_minutes.s, msg[pf].msg_minutes.p,
+			       rd.minutes), rd.minutes);
+		break;
+	case rd_hours:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_hours.s, msg[pf].msg_hours.p,
+			       rd.hours), rd.hours);
+		break;
+	case rd_days:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_days.s, msg[pf].msg_days.p,
+			       rd.days), rd.days);
+		break;
+	case rd_weeks:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_weeks.s, msg[pf].msg_weeks.p,
+			       rd.weeks), rd.weeks);
+		break;
+	case rd_months:
+		strbuf_addf(timebuf,
+			    Q_(msg[pf].msg_months.s, msg[pf].msg_months.p,
+			       rd.months), rd.months);
+		break;
+
+	case rd_years:
+		if (rd.months) {
 			struct strbuf sb = STRBUF_INIT;
-			strbuf_addf(&sb, Q_("%lu year", "%lu years", years), years);
-			/* TRANSLATORS: "%s" is "<n> years" */
+			strbuf_addf(&sb, Q_(msg[pf].msg_years_only.s,
+					    msg[pf].msg_years_only.p,
+					    rd.years), rd.years);
 			strbuf_addf(timebuf,
-				 Q_("%s, %lu month ago", "%s, %lu months ago", months),
-				 sb.buf, months);
+				    Q_(msg[pf].msg_years_months.s,
+				       msg[pf].msg_years_months.p,
+				       rd.months),
+				    sb.buf, rd.months);
 			strbuf_release(&sb);
-		} else
+		} else {
 			strbuf_addf(timebuf,
-				 Q_("%lu year ago", "%lu years ago", years), years);
-		return;
+				    Q_(msg[pf].msg_years.s, msg[pf].msg_years.p,
+				       rd.years), rd.years);
+		}
+		break;
 	}
-	/* Otherwise, just years. Centuries is probably overkill. */
-	strbuf_addf(timebuf,
-		 Q_("%lu year ago", "%lu years ago", (diff + 183) / 365),
-		 (diff + 183) / 365);
 }
 
 const char *show_date(unsigned long time, int tz, enum date_mode mode)
-- 
1.7.12.rc3.69.gaf0166d
Previous: Junio C HamanoNext: Junio C Hamano
Message 4 of 8 in “Can show relative date of the commit with future timestamp”
  1. Can show relative date of the commit with future timestampTom Xue, Jul 5, 2012
  2. Junio C HamanoJul 5, 2012
  3. 0/2 relative future dateJunio C Hamano, Aug 16, 2012
  4. 1/2 date: refactor the relative date logic from presentationJunio C Hamano, Aug 16, 2012
  5. 2/2 date: show relative dates in the futureJunio C Hamano, Aug 16, 2012
  6. Jundong XueJul 6, 2012
  7. Junio C HamanoAug 20, 2012
  8. Jundong XueAug 21, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.