mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Extend time parsing to before 1970
It turns out that we are starting to have users that have logs that go back that far. It won't be common, but let's get it right anyway. NOTE! With us now supporting dates earlier in 1900, this also makes "utc_mktime()" always add the "1900" to the year field. That way we avoid ever using the fairly ambiguous two-digit shorthand. It didn't use to be all that ambiguous when we knew that any two-digit number less than 70 had to be 2000+. Now that we support going back to earlier in the last centiry, that certainty is eroding. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
1cf71a476b
commit
84166a4ee7
9 changed files with 69 additions and 34 deletions
|
@ -504,7 +504,7 @@ void dump_trip_list(void)
|
||||||
printf("%s trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u (%d dives - %p)\n",
|
printf("%s trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u (%d dives - %p)\n",
|
||||||
trip->autogen ? "autogen " : "",
|
trip->autogen ? "autogen " : "",
|
||||||
++i, trip->location,
|
++i, trip->location,
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||||
trip->nrdives, trip);
|
trip->nrdives, trip);
|
||||||
last_time = trip->when;
|
last_time = trip->when;
|
||||||
}
|
}
|
||||||
|
@ -531,7 +531,7 @@ dive_trip_t *find_matching_trip(timestamp_t when)
|
||||||
utc_mkdate(trip->when, &tm);
|
utc_mkdate(trip->when, &tm);
|
||||||
printf("found trip %p @ %04d-%02d-%02d %02d:%02d:%02d\n",
|
printf("found trip %p @ %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||||
trip,
|
trip,
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -126,7 +126,7 @@ static void update_date(timestamp_t *when, const char *line)
|
||||||
if (sscanf(line, "%04u-%02u-%02u", &yyyy, &mm, &dd) != 3)
|
if (sscanf(line, "%04u-%02u-%02u", &yyyy, &mm, &dd) != 3)
|
||||||
return;
|
return;
|
||||||
utc_mkdate(*when, &tm);
|
utc_mkdate(*when, &tm);
|
||||||
tm.tm_year = yyyy - 1900;
|
tm.tm_year = yyyy;
|
||||||
tm.tm_mon = mm - 1;
|
tm.tm_mon = mm - 1;
|
||||||
tm.tm_mday = dd;
|
tm.tm_mday = dd;
|
||||||
*when = utc_mktime(&tm);
|
*when = utc_mktime(&tm);
|
||||||
|
@ -1199,7 +1199,7 @@ static dive_trip_t *create_new_trip(int yyyy, int mm, int dd)
|
||||||
|
|
||||||
static bool validate_date(int yyyy, int mm, int dd)
|
static bool validate_date(int yyyy, int mm, int dd)
|
||||||
{
|
{
|
||||||
return yyyy > 1970 && yyyy < 3000 &&
|
return yyyy > 1930 && yyyy < 3000 &&
|
||||||
mm > 0 && mm < 13 &&
|
mm > 0 && mm < 13 &&
|
||||||
dd > 0 && dd < 32;
|
dd > 0 && dd < 32;
|
||||||
}
|
}
|
||||||
|
@ -1308,7 +1308,7 @@ static int dive_directory(const char *root, const git_tree_entry *entry, const c
|
||||||
tm.tm_hour = h;
|
tm.tm_hour = h;
|
||||||
tm.tm_min = m;
|
tm.tm_min = m;
|
||||||
tm.tm_sec = s;
|
tm.tm_sec = s;
|
||||||
tm.tm_year = yyyy - 1900;
|
tm.tm_year = yyyy;
|
||||||
tm.tm_mon = mm-1;
|
tm.tm_mon = mm-1;
|
||||||
tm.tm_mday = dd;
|
tm.tm_mday = dd;
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ void dump_plan(struct diveplan *diveplan)
|
||||||
utc_mkdate(diveplan->when, &tm);
|
utc_mkdate(diveplan->when, &tm);
|
||||||
|
|
||||||
printf("\nDiveplan @ %04d-%02d-%02d %02d:%02d:%02d (surfpres %dmbar):\n",
|
printf("\nDiveplan @ %04d-%02d-%02d %02d:%02d:%02d (surfpres %dmbar):\n",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||||
diveplan->surface_pressure);
|
diveplan->surface_pressure);
|
||||||
dp = diveplan->dp;
|
dp = diveplan->dp;
|
||||||
|
|
|
@ -215,7 +215,7 @@ static void show_date(struct membuffer *b, timestamp_t when)
|
||||||
utc_mkdate(when, &tm);
|
utc_mkdate(when, &tm);
|
||||||
|
|
||||||
put_format(b, "date %04u-%02u-%02u\n",
|
put_format(b, "date %04u-%02u-%02u\n",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
|
||||||
put_format(b, "time %02u:%02u:%02u\n",
|
put_format(b, "time %02u:%02u:%02u\n",
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||||
}
|
}
|
||||||
|
@ -535,7 +535,7 @@ static void create_dive_name(struct dive *dive, struct membuffer *name, struct t
|
||||||
|
|
||||||
utc_mkdate(dive->when, &tm);
|
utc_mkdate(dive->when, &tm);
|
||||||
if (tm.tm_year != dirtm->tm_year)
|
if (tm.tm_year != dirtm->tm_year)
|
||||||
put_format(name, "%04u-", tm.tm_year + 1900);
|
put_format(name, "%04u-", tm.tm_year);
|
||||||
if (tm.tm_mon != dirtm->tm_mon)
|
if (tm.tm_mon != dirtm->tm_mon)
|
||||||
put_format(name, "%02u-", tm.tm_mon+1);
|
put_format(name, "%02u-", tm.tm_mon+1);
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ static int save_trip_description(git_repository *repo, struct dir *dir, dive_tri
|
||||||
struct membuffer desc = { 0 };
|
struct membuffer desc = { 0 };
|
||||||
|
|
||||||
put_format(&desc, "date %04u-%02u-%02u\n",
|
put_format(&desc, "date %04u-%02u-%02u\n",
|
||||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
|
||||||
put_format(&desc, "time %02u:%02u:%02u\n",
|
put_format(&desc, "time %02u:%02u:%02u\n",
|
||||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
|
|
||||||
|
@ -949,7 +949,7 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o
|
||||||
|
|
||||||
/* Create the date-based hierarchy */
|
/* Create the date-based hierarchy */
|
||||||
utc_mkdate(trip ? trip->when : dive->when, &tm);
|
utc_mkdate(trip ? trip->when : dive->when, &tm);
|
||||||
tree = mktree(repo, root, "%04d", tm.tm_year + 1900);
|
tree = mktree(repo, root, "%04d", tm.tm_year);
|
||||||
tree = mktree(repo, tree, "%02d", tm.tm_mon + 1);
|
tree = mktree(repo, tree, "%02d", tm.tm_mon + 1);
|
||||||
|
|
||||||
if (trip) {
|
if (trip) {
|
||||||
|
|
|
@ -201,7 +201,7 @@ void put_HTML_date(struct membuffer *b, struct dive *dive, const char *pre, cons
|
||||||
{
|
{
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
utc_mkdate(dive->when, &tm);
|
utc_mkdate(dive->when, &tm);
|
||||||
put_format(b, "%s%04u-%02u-%02u%s", pre, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, post);
|
put_format(b, "%s%04u-%02u-%02u%s", pre, tm.tm_year, tm.tm_mon + 1, tm.tm_mday, post);
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_HTML_quoted(struct membuffer *b, const char *text)
|
void put_HTML_quoted(struct membuffer *b, const char *text)
|
||||||
|
|
|
@ -323,7 +323,7 @@ static void show_date(struct membuffer *b, timestamp_t when)
|
||||||
utc_mkdate(when, &tm);
|
utc_mkdate(when, &tm);
|
||||||
|
|
||||||
put_format(b, " date='%04u-%02u-%02u'",
|
put_format(b, " date='%04u-%02u-%02u'",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
|
||||||
put_format(b, " time='%02u:%02u:%02u'",
|
put_format(b, " time='%02u:%02u:%02u'",
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,10 +160,10 @@ void process_all_dives(struct dive *dive, struct dive **prev_dive)
|
||||||
/* yearly statistics */
|
/* yearly statistics */
|
||||||
utc_mkdate(dp->when, &tm);
|
utc_mkdate(dp->when, &tm);
|
||||||
if (current_year == 0)
|
if (current_year == 0)
|
||||||
current_year = tm.tm_year + 1900;
|
current_year = tm.tm_year;
|
||||||
|
|
||||||
if (current_year != tm.tm_year + 1900) {
|
if (current_year != tm.tm_year) {
|
||||||
current_year = tm.tm_year + 1900;
|
current_year = tm.tm_year;
|
||||||
process_dive(dp, &(stats_yearly[++year_iter]));
|
process_dive(dp, &(stats_yearly[++year_iter]));
|
||||||
stats_yearly[year_iter].is_year = true;
|
stats_yearly[year_iter].is_year = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
72
core/time.c
72
core/time.c
|
@ -1,6 +1,24 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "dive.h"
|
#include "dive.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The date handling internally works in seconds since
|
||||||
|
* Jan 1, 1900. That avoids negative numbers which avoids
|
||||||
|
* some silly problems.
|
||||||
|
*
|
||||||
|
* But we then use the same base epoch base (Jan 1, 1970)
|
||||||
|
* that POSIX uses, so that we can use the normal date
|
||||||
|
* handling functions for getting current time etc.
|
||||||
|
*
|
||||||
|
* There's 25567 dats from Jan 1, 1900 to Jan 1, 1970.
|
||||||
|
*
|
||||||
|
* NOTE! The SEC_PER_DAY is not so much because the
|
||||||
|
* number is complicated, as to make sure we always
|
||||||
|
* expand the type to "timestamp_t" in the arithmetic.
|
||||||
|
*/
|
||||||
|
#define SEC_PER_DAY ((timestamp_t) 24*60*60)
|
||||||
|
#define EPOCH_OFFSET (25567 * SEC_PER_DAY)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert 64-bit timestamp to 'struct tm' in UTC.
|
* Convert 64-bit timestamp to 'struct tm' in UTC.
|
||||||
*
|
*
|
||||||
|
@ -24,7 +42,14 @@ void utc_mkdate(timestamp_t timestamp, struct tm *tm)
|
||||||
|
|
||||||
memset(tm, 0, sizeof(*tm));
|
memset(tm, 0, sizeof(*tm));
|
||||||
|
|
||||||
/* seconds since 1970 -> minutes since 1970 */
|
// Midnight at Jan 1, 1970 means "no date"
|
||||||
|
if (!timestamp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Convert to seconds since 1900 */
|
||||||
|
timestamp += EPOCH_OFFSET;
|
||||||
|
|
||||||
|
/* minutes since 1900 */
|
||||||
tm->tm_sec = timestamp % 60;
|
tm->tm_sec = timestamp % 60;
|
||||||
val = timestamp /= 60;
|
val = timestamp /= 60;
|
||||||
|
|
||||||
|
@ -34,19 +59,21 @@ void utc_mkdate(timestamp_t timestamp, struct tm *tm)
|
||||||
tm->tm_hour = val % 24;
|
tm->tm_hour = val % 24;
|
||||||
val /= 24;
|
val /= 24;
|
||||||
|
|
||||||
/* Jan 1, 1970 was a Thursday (tm_wday=4) */
|
/* Jan 1, 1900 was a Monday (tm_wday=1) */
|
||||||
tm->tm_wday = (val + 4) % 7;
|
tm->tm_wday = (val + 1) % 7;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we're in "days since Jan 1, 1970". To make things easier,
|
* Now we're in "days since Jan 1, 1900". To make things easier,
|
||||||
* let's make it "days since Jan 1, 1968", since that's a leap-year
|
* let's make it "days since Jan 1, 1904", since that's a leap-year.
|
||||||
|
* 1900 itself was not. The following logic will get 1900-1903
|
||||||
|
* wrong. If you were diving back then, you're kind of screwed.
|
||||||
*/
|
*/
|
||||||
val += 365 + 366;
|
val -= 365*4;
|
||||||
|
|
||||||
/* This only works up until 2099 (2100 isn't a leap-year) */
|
/* This only works up until 2099 (2100 isn't a leap-year) */
|
||||||
leapyears = val / (365 * 4 + 1);
|
leapyears = val / (365 * 4 + 1);
|
||||||
val %= (365 * 4 + 1);
|
val %= (365 * 4 + 1);
|
||||||
tm->tm_year = 68 + leapyears * 4;
|
tm->tm_year = 1904 + leapyears * 4;
|
||||||
|
|
||||||
/* Handle the leap-year itself */
|
/* Handle the leap-year itself */
|
||||||
mp = mdays_leap;
|
mp = mdays_leap;
|
||||||
|
@ -75,24 +102,33 @@ timestamp_t utc_mktime(struct tm *tm)
|
||||||
int year = tm->tm_year;
|
int year = tm->tm_year;
|
||||||
int month = tm->tm_mon;
|
int month = tm->tm_mon;
|
||||||
int day = tm->tm_mday;
|
int day = tm->tm_mday;
|
||||||
|
int days_since_1900;
|
||||||
|
timestamp_t when;
|
||||||
|
|
||||||
/* First normalize relative to 1900 */
|
/* First normalize relative to 1900 */
|
||||||
if (year < 70)
|
if (year < 50)
|
||||||
year += 100;
|
year += 100;
|
||||||
else if (year > 1900)
|
else if (year > 1900)
|
||||||
year -= 1900;
|
year -= 1900;
|
||||||
|
|
||||||
/* Normalized to Jan 1, 1970: unix time */
|
if (year < 0 || year > 129) /* algo only works for 1900-2099 */
|
||||||
year -= 70;
|
return 0;
|
||||||
|
|
||||||
if (year < 0 || year > 129) /* algo only works for 1970-2099 */
|
|
||||||
return -1;
|
|
||||||
if (month < 0 || month > 11) /* array bounds */
|
if (month < 0 || month > 11) /* array bounds */
|
||||||
return -1;
|
return 0;
|
||||||
if (month < 2 || (year + 2) % 4)
|
if (month < 2 || (year && year % 4))
|
||||||
day--;
|
day--;
|
||||||
if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_sec < 0)
|
if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_sec < 0)
|
||||||
return -1;
|
return 0;
|
||||||
return (year * 365 + (year + 1) / 4 + mdays[month] + day) * 24 * 60 * 60UL +
|
|
||||||
tm->tm_hour * 60 * 60 + tm->tm_min * 60 + tm->tm_sec;
|
/* This works until 2099 */
|
||||||
|
days_since_1900 = year * 365 + (year - 1) / 4;
|
||||||
|
|
||||||
|
/* Note the 'day' fixup for non-leapyears above */
|
||||||
|
days_since_1900 += mdays[month] + day;
|
||||||
|
|
||||||
|
/* Now add it all up, making sure to do this part in "timestamp_t" */
|
||||||
|
when = days_since_1900 * SEC_PER_DAY;
|
||||||
|
when += tm->tm_hour * 60 * 60 + tm->tm_min * 60 + tm->tm_sec;
|
||||||
|
|
||||||
|
return when - EPOCH_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,6 @@ static void uemis_ts(char *buffer, void *_when)
|
||||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||||
tm.tm_mon -= 1;
|
tm.tm_mon -= 1;
|
||||||
tm.tm_year -= 1900;
|
|
||||||
*when = utc_mktime(&tm);
|
*when = utc_mktime(&tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue