int git_signature_now(git_signature **sig_out, const char *name, const char *email) { time_t now; time_t offset; struct tm *utc_tm; git_signature *sig; struct tm _utc; *sig_out = NULL; /* * Get the current time as seconds since the epoch and * transform that into a tm struct containing the time at * UTC. Give that to mktime which considers it a local time * (tm_isdst = -1 asks it to take DST into account) and gives * us that time as seconds since the epoch. The difference * between its return value and 'now' is our offset to UTC. */ time(&now); utc_tm = p_gmtime_r(&now, &_utc); utc_tm->tm_isdst = -1; offset = (time_t)difftime(now, mktime(utc_tm)); offset /= 60; if (git_signature_new(&sig, name, email, now, (int)offset) < 0) return -1; *sig_out = sig; return 0; }
static size_t match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm) { time_t now; struct tm now_tm; struct tm *refuse_future; long num2, num3; num2 = strtol(end+1, &end, 10); num3 = -1; if (*end == c && isdigit(end[1])) num3 = strtol(end+1, &end, 10); /* Time? Date? */ switch (c) { case ':': if (num3 < 0) num3 = 0; if (num < 25 && num2 >= 0 && num2 < 60 && num3 >= 0 && num3 <= 60) { tm->tm_hour = num; tm->tm_min = num2; tm->tm_sec = num3; break; } return 0; case '-': case '/': case '.': now = time(NULL); refuse_future = NULL; if (p_gmtime_r(&now, &now_tm)) refuse_future = &now_tm; if (num > 70) { /* yyyy-mm-dd? */ if (is_date(num, num2, num3, refuse_future, now, tm)) break; /* yyyy-dd-mm? */ if (is_date(num, num3, num2, refuse_future, now, tm)) break; } /* Our eastern European friends say dd.mm.yy[yy] * is the norm there, so giving precedence to * mm/dd/yy[yy] form only when separator is not '.' */ if (c != '.' && is_date(num3, num, num2, refuse_future, now, tm)) break; /* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */ if (is_date(num3, num2, num, refuse_future, now, tm)) break; /* Funny European mm.dd.yy */ if (c == '.' && is_date(num3, num, num2, refuse_future, now, tm)) break; return 0; } return end - date; }
/* * We've seen a digit. Time? Year? Date? */ static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt) { size_t n; char *end; unsigned long num; num = strtoul(date, &end, 10); /* * Seconds since 1970? We trigger on that for any numbers with * more than 8 digits. This is because we don't want to rule out * numbers like 20070606 as a YYYYMMDD date. */ if (num >= 100000000 && nodate(tm)) { time_t time = num; if (p_gmtime_r(&time, tm)) { *tm_gmt = 1; return end - date; } } /* * Check for special formats: num[-.:/]num[same]num */ switch (*end) { case ':': case '.': case '/': case '-': if (isdigit(end[1])) { size_t match = match_multi_number(num, *end, date, end, tm); if (match) return match; } } /* * None of the special formats? Try to guess what * the number meant. We use the number of digits * to make a more educated guess.. */ n = 0; do { n++; } while (isdigit(date[n])); /* Four-digit year or a timezone? */ if (n == 4) { if (num <= 1400 && *offset == -1) { unsigned int minutes = num % 100; unsigned int hours = num / 100; *offset = hours*60 + minutes; } else if (num > 1900 && num < 2100) tm->tm_year = num - 1900; return n; } /* * Ignore lots of numerals. We took care of 4-digit years above. * Days or months must be one or two digits. */ if (n > 2) return n; /* * NOTE! We will give precedence to day-of-month over month or * year numbers in the 1-12 range. So 05 is always "mday 5", * unless we already have a mday.. * * IOW, 01 Apr 05 parses as "April 1st, 2005". */ if (num > 0 && num < 32 && tm->tm_mday < 0) { tm->tm_mday = num; return n; } /* Two-digit year? */ if (n == 2 && tm->tm_year < 0) { if (num < 10 && tm->tm_mday >= 0) { tm->tm_year = num + 100; return n; } if (num >= 70) { tm->tm_year = num; return n; } } if (num > 0 && num < 13 && tm->tm_mon < 0) tm->tm_mon = num-1; return n; }