1155 lines
26 KiB
C
1155 lines
26 KiB
C
/*
|
|
* GIT - The information manager from hell
|
|
*
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
*/
|
|
|
|
#include "cache.h"
|
|
|
|
/*
|
|
* This is like mktime, but without normalization of tm_wday and tm_yday.
|
|
*/
|
|
static time_t tm_to_time_t(const struct tm *tm)
|
|
{
|
|
static const int mdays[] = {
|
|
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
|
};
|
|
int year = tm->tm_year - 70;
|
|
int month = tm->tm_mon;
|
|
int day = tm->tm_mday;
|
|
|
|
if (year < 0 || year > 129) /* algo only works for 1970-2099 */
|
|
return -1;
|
|
if (month < 0 || month > 11) /* array bounds */
|
|
return -1;
|
|
if (month < 2 || (year + 2) % 4)
|
|
day--;
|
|
if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_sec < 0)
|
|
return -1;
|
|
return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24*60*60UL +
|
|
tm->tm_hour * 60*60 + tm->tm_min * 60 + tm->tm_sec;
|
|
}
|
|
|
|
static const char *month_names[] = {
|
|
"January", "February", "March", "April", "May", "June",
|
|
"July", "August", "September", "October", "November", "December"
|
|
};
|
|
|
|
static const char *weekday_names[] = {
|
|
"Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays"
|
|
};
|
|
|
|
static time_t gm_time_t(unsigned long time, int tz)
|
|
{
|
|
int minutes;
|
|
|
|
minutes = tz < 0 ? -tz : tz;
|
|
minutes = (minutes / 100)*60 + (minutes % 100);
|
|
minutes = tz < 0 ? -minutes : minutes;
|
|
return time + minutes * 60;
|
|
}
|
|
|
|
/*
|
|
* The "tz" thing is passed in as this strange "decimal parse of tz"
|
|
* thing, which means that tz -0100 is passed in as the integer -100,
|
|
* even though it means "sixty minutes off"
|
|
*/
|
|
static struct tm *time_to_tm(unsigned long time, int tz)
|
|
{
|
|
time_t t = gm_time_t(time, tz);
|
|
return gmtime(&t);
|
|
}
|
|
|
|
/*
|
|
* What value of "tz" was in effect back then at "time" in the
|
|
* local timezone?
|
|
*/
|
|
static int local_tzoffset(unsigned long time)
|
|
{
|
|
time_t t, t_local;
|
|
struct tm tm;
|
|
int offset, eastwest;
|
|
|
|
t = time;
|
|
localtime_r(&t, &tm);
|
|
t_local = tm_to_time_t(&tm);
|
|
|
|
if (t_local < t) {
|
|
eastwest = -1;
|
|
offset = t - t_local;
|
|
} else {
|
|
eastwest = 1;
|
|
offset = t_local - t;
|
|
}
|
|
offset /= 60; /* in minutes */
|
|
offset = (offset % 60) + ((offset / 60) * 100);
|
|
return offset * eastwest;
|
|
}
|
|
|
|
void show_date_relative(unsigned long time, int tz,
|
|
const struct timeval *now,
|
|
struct strbuf *timebuf)
|
|
{
|
|
unsigned long diff;
|
|
if (now->tv_sec < time) {
|
|
strbuf_addstr(timebuf, _("in the future"));
|
|
return;
|
|
}
|
|
diff = now->tv_sec - time;
|
|
if (diff < 90) {
|
|
strbuf_addf(timebuf,
|
|
Q_("%lu second ago", "%lu seconds ago", diff), diff);
|
|
return;
|
|
}
|
|
/* Turn it into minutes */
|
|
diff = (diff + 30) / 60;
|
|
if (diff < 90) {
|
|
strbuf_addf(timebuf,
|
|
Q_("%lu minute ago", "%lu minutes ago", diff), diff);
|
|
return;
|
|
}
|
|
/* Turn it into hours */
|
|
diff = (diff + 30) / 60;
|
|
if (diff < 36) {
|
|
strbuf_addf(timebuf,
|
|