timestamp_t: a new data type for timestamps
Git's source code assumes that unsigned long is at least as precise as time_t. Which is incorrect, and causes a lot of problems, in particular where unsigned long is only 32-bit (notably on Windows, even in 64-bit versions). So let's just use a more appropriate data type instead. In preparation for this, we introduce the new `timestamp_t` data type. By necessity, this is a very, very large patch, as it has to replace all timestamps' data type in one go. As we will use a data type that is not necessarily identical to `time_t`, we need to be very careful to use `time_t` whenever we interact with the system functions, and `timestamp_t` everywhere else. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
cb71f8bdb5
commit
dddbad728c
66
date.c
66
date.c
@ -39,7 +39,7 @@ static const char *weekday_names[] = {
|
||||
"Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays"
|
||||
};
|
||||
|
||||
static time_t gm_time_t(unsigned long time, int tz)
|
||||
static time_t gm_time_t(timestamp_t time, int tz)
|
||||
{
|
||||
int minutes;
|
||||
|
||||
@ -54,7 +54,7 @@ static time_t gm_time_t(unsigned long time, int 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)
|
||||
static struct tm *time_to_tm(timestamp_t time, int tz)
|
||||
{
|
||||
time_t t = gm_time_t(time, tz);
|
||||
return gmtime(&t);
|
||||
@ -64,7 +64,7 @@ static struct tm *time_to_tm(unsigned long time, int tz)
|
||||
* What value of "tz" was in effect back then at "time" in the
|
||||
* local timezone?
|
||||
*/
|
||||
static int local_tzoffset(unsigned long time)
|
||||
static int local_tzoffset(timestamp_t time)
|
||||
{
|
||||
time_t t, t_local;
|
||||
struct tm tm;
|
||||
@ -88,11 +88,11 @@ static int local_tzoffset(unsigned long time)
|
||||
return offset * eastwest;
|
||||
}
|
||||
|
||||
void show_date_relative(unsigned long time, int tz,
|
||||
void show_date_relative(timestamp_t time, int tz,
|
||||
const struct timeval *now,
|
||||
struct strbuf *timebuf)
|
||||
{
|
||||
unsigned long diff;
|
||||
timestamp_t diff;
|
||||
if (now->tv_sec < time) {
|
||||
strbuf_addstr(timebuf, _("in the future"));
|
||||
return;
|
||||
@ -140,9 +140,9 @@ void show_date_relative(unsigned long time, int tz,
|
||||
}
|
||||
/* 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;
|
||||
timestamp_t totalmonths = (diff * 12 * 2 + 365) / (365 * 2);
|
||||
timestamp_t years = totalmonths / 12;
|
||||
timestamp_t months = totalmonths % 12;
|
||||
if (months) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
strbuf_addf(&sb, Q_("%"PRItime" year", "%"PRItime" years", years), years);
|
||||
@ -172,7 +172,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
|
||||
return &mode;
|
||||
}
|
||||
|
||||
const char *show_date(unsigned long time, int tz, const struct date_mode *mode)
|
||||
const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
|
||||
{
|
||||
struct tm *tm;
|
||||
static struct strbuf timebuf = STRBUF_INIT;
|
||||
@ -425,7 +425,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_multi_number(unsigned long num, char c, const char *date,
|
||||
static int match_multi_number(timestamp_t num, char c, const char *date,
|
||||
char *end, struct tm *tm, time_t now)
|
||||
{
|
||||
struct tm now_tm;
|
||||
@ -508,7 +508,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
|
||||
{
|
||||
int n;
|
||||
char *end;
|
||||
unsigned long num;
|
||||
timestamp_t num;
|
||||
|
||||
num = parse_timestamp(date, &end, 10);
|
||||
|
||||
@ -635,7 +635,7 @@ static int match_tz(const char *date, int *offp)
|
||||
return end - date;
|
||||
}
|
||||
|
||||
static void date_string(unsigned long date, int offset, struct strbuf *buf)
|
||||
static void date_string(timestamp_t date, int offset, struct strbuf *buf)
|
||||
{
|
||||
int sign = '+';
|
||||
|
||||
@ -650,16 +650,16 @@ static void date_string(unsigned long date, int offset, struct strbuf *buf)
|
||||
* Parse a string like "0 +0000" as ancient timestamp near epoch, but
|
||||
* only when it appears not as part of any other string.
|
||||
*/
|
||||
static int match_object_header_date(const char *date, unsigned long *timestamp, int *offset)
|
||||
static int match_object_header_date(const char *date, timestamp_t *timestamp, int *offset)
|
||||
{
|
||||
char *end;
|
||||
unsigned long stamp;
|
||||
timestamp_t stamp;
|
||||
int ofs;
|
||||
|
||||
if (*date < '0' || '9' < *date)
|
||||
return -1;
|
||||
stamp = parse_timestamp(date, &end, 10);
|
||||
if (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-'))
|
||||
if (*end != ' ' || stamp == TIME_MAX || (end[1] != '+' && end[1] != '-'))
|
||||
return -1;
|
||||
date = end + 2;
|
||||
ofs = strtol(date, &end, 10);
|
||||
@ -675,11 +675,11 @@ static int match_object_header_date(const char *date, unsigned long *timestamp,
|
||||
|
||||
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
|
||||
(i.e. English) day/month names, and it doesn't work correctly with %z. */
|
||||
int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
|
||||
int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
|
||||
{
|
||||
struct tm tm;
|
||||
int tm_gmt;
|
||||
unsigned long dummy_timestamp;
|
||||
timestamp_t dummy_timestamp;
|
||||
int dummy_offset;
|
||||
|
||||
if (!timestamp)
|
||||
@ -747,7 +747,7 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
int parse_expiry_date(const char *date, unsigned long *timestamp)
|
||||
int parse_expiry_date(const char *date, timestamp_t *timestamp)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
@ -762,7 +762,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)
|
||||
* of the past, and there is nothing from the future
|
||||
* to be kept.
|
||||
*/
|
||||
*timestamp = ULONG_MAX;
|
||||
*timestamp = TIME_MAX;
|
||||
else
|
||||
*timestamp = approxidate_careful(date, &errors);
|
||||
|
||||
@ -771,7 +771,7 @@ int parse_expiry_date(const char *date, unsigned long *timestamp)
|
||||
|
||||
int parse_date(const char *date, struct strbuf *result)
|
||||
{
|
||||
unsigned long timestamp;
|
||||
timestamp_t timestamp;
|
||||
int offset;
|
||||
if (parse_date_basic(date, ×tamp, &offset))
|
||||
return -1;
|
||||
@ -845,7 +845,7 @@ void datestamp(struct strbuf *out)
|
||||
* Relative time update (eg "2 days ago"). If we haven't set the time
|
||||
* yet, we need to set it from current time.
|
||||
*/
|
||||
static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)
|
||||
static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)
|
||||
{
|
||||
time_t n;
|
||||
|
||||
@ -1066,7 +1066,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
|
||||
time_t now)
|
||||
{
|
||||
char *end;
|
||||
unsigned long number = parse_timestamp(date, &end, 10);
|
||||
timestamp_t number = parse_timestamp(date, &end, 10);
|
||||
|
||||
switch (*end) {
|
||||
case ':':
|
||||
@ -1114,9 +1114,9 @@ static void pending_number(struct tm *tm, int *num)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long approxidate_str(const char *date,
|
||||
const struct timeval *tv,
|
||||
int *error_ret)
|
||||
static timestamp_t approxidate_str(const char *date,
|
||||
const struct timeval *tv,
|
||||
int *error_ret)
|
||||
{
|
||||
int number = 0;
|
||||
int touched = 0;
|
||||
@ -1148,12 +1148,12 @@ static unsigned long approxidate_str(const char *date,
|
||||
pending_number(&tm, &number);
|
||||
if (!touched)
|
||||
*error_ret = 1;
|
||||
return update_tm(&tm, &now, 0);
|
||||
return (timestamp_t)update_tm(&tm, &now, 0);
|
||||
}
|
||||
|
||||
unsigned long approxidate_relative(const char *date, const struct timeval *tv)
|
||||
timestamp_t approxidate_relative(const char *date, const struct timeval *tv)
|
||||
{
|
||||
unsigned long timestamp;
|
||||
timestamp_t timestamp;
|
||||
int offset;
|
||||
int errors = 0;
|
||||
|
||||
@ -1162,10 +1162,10 @@ unsigned long approxidate_relative(const char *date, const struct timeval *tv)
|
||||
return approxidate_str(date, tv, &errors);
|
||||
}
|
||||
|
||||
unsigned long approxidate_careful(const char *date, int *error_ret)
|
||||
timestamp_t approxidate_careful(const char *date, int *error_ret)
|
||||
{
|
||||
struct timeval tv;
|
||||
unsigned long timestamp;
|
||||
timestamp_t timestamp;
|
||||
int offset;
|
||||
int dummy = 0;
|
||||
if (!error_ret)
|
||||
@ -1180,12 +1180,12 @@ unsigned long approxidate_careful(const char *date, int *error_ret)
|
||||
return approxidate_str(date, &tv, error_ret);
|
||||
}
|
||||
|
||||
int date_overflows(unsigned long t)
|
||||
int date_overflows(timestamp_t t)
|
||||
{
|
||||
time_t sys;
|
||||
|
||||
/* If we overflowed our unsigned long, that's bad... */
|
||||
if (t == ULONG_MAX)
|
||||
/* If we overflowed our timestamp data type, that's bad... */
|
||||
if ((uintmax_t)t >= TIME_MAX)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user