mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-12-01 21:19:16 -06:00
Implement internal replacements for localtime, mktime, etc.
The builtin time functions suffer from the "2038 bug" caused by overflowing a 32-bit representation of seconds from 1 Jan 1970. Provide functions based on GDateTime which use a 64-bit representation (like our Timespec), replace all of the instances in gnc-date.c, and make other adjustments needed to ensure that the tests pass on a 32-bit system. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22604 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
f309e0c697
commit
2725d5a654
@ -128,6 +128,7 @@ gnc_g_time_zone_adjust_for_dst (GTimeZone* tz, GDateTime *date)
|
||||
guint day = g_date_time_get_day_of_month (date);
|
||||
gint bias, hours, minutes;
|
||||
gchar *tzstr;
|
||||
g_return_val_if_fail (date != NULL, NULL);
|
||||
if (dst > 0 && tzinfo.StandardDate.wMonth > 0
|
||||
&& ((month > tzinfo.DaylightDate.wMonth
|
||||
&& month < tzinfo.StandardDate.wMonth)
|
||||
@ -149,13 +150,15 @@ gnc_g_time_zone_adjust_for_dst (GTimeZone* tz, GDateTime *date)
|
||||
|
||||
static GDateTime*
|
||||
gnc_g_date_time_new_local (gint year, gint month, gint day, gint hour, gint minute, gdouble seconds)
|
||||
{
|
||||
{
|
||||
#ifndef G_OS_WIN32
|
||||
return g_date_time_new_local (year, month, day, hour, minute, seconds);
|
||||
#else
|
||||
GTimeZone *tz = gnc_g_time_zone_new_local();
|
||||
GDateTime *gdt = g_date_time_new (tz, year, month, day,
|
||||
hour, minute, seconds);
|
||||
if (!gdt)
|
||||
return gdt;
|
||||
tz = gnc_g_time_zone_adjust_for_dst (tz, gdt);
|
||||
g_date_time_unref (gdt);
|
||||
gdt = g_date_time_new (tz, year, month, day, hour, minute, seconds);
|
||||
@ -167,7 +170,9 @@ gnc_g_date_time_new_local (gint year, gint month, gint day, gint hour, gint minu
|
||||
static GDateTime*
|
||||
gnc_g_date_time_adjust_for_dst (GDateTime *gdt, GTimeZone *tz)
|
||||
{
|
||||
GDateTime *ngdt = g_date_time_to_timezone (gdt, tz);
|
||||
GDateTime *ngdt;
|
||||
g_return_val_if_fail (gdt != NULL, NULL);
|
||||
ngdt = g_date_time_to_timezone (gdt, tz);
|
||||
g_date_time_unref (gdt);
|
||||
tz = gnc_g_time_zone_adjust_for_dst (tz, ngdt);
|
||||
gdt = g_date_time_to_timezone (ngdt, tz);
|
||||
@ -184,6 +189,8 @@ gnc_g_date_time_new_from_unix_local (gint64 time)
|
||||
#else
|
||||
GTimeZone *tz = gnc_g_time_zone_new_local ();
|
||||
GDateTime *gdt = g_date_time_new_from_unix_utc (time);
|
||||
if (!gdt)
|
||||
return gdt;
|
||||
return gnc_g_date_time_adjust_for_dst (gdt, tz);
|
||||
#endif
|
||||
}
|
||||
@ -196,6 +203,8 @@ gnc_g_date_time_new_from_timeval_local (const GTimeVal* tv)
|
||||
#else
|
||||
GTimeZone *tz = gnc_g_time_zone_new_local ();
|
||||
GDateTime *gdt = g_date_time_new_from_timeval_utc (tv);
|
||||
if (!gdt)
|
||||
return gdt;
|
||||
return gnc_g_date_time_adjust_for_dst (gdt, tz);
|
||||
#endif
|
||||
}
|
||||
@ -208,6 +217,8 @@ gnc_g_date_time_new_now_local (void)
|
||||
#else
|
||||
GTimeZone *tz = gnc_g_time_zone_new_local ();
|
||||
GDateTime *gdt = g_date_time_new_now_local ();
|
||||
if (!gdt)
|
||||
return gdt;
|
||||
return gnc_g_date_time_adjust_for_dst (gdt, tz);
|
||||
#endif
|
||||
}
|
||||
@ -245,7 +256,197 @@ _gnc_date_time_init (_GncDateTime *gncdt)
|
||||
gncdt->to_local = gnc_g_date_time_to_local;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/****************** Posix Replacement Functions ***************************/
|
||||
void
|
||||
gnc_tm_free (struct tm* time)
|
||||
{
|
||||
g_slice_free1 (sizeof (struct tm), time);
|
||||
}
|
||||
|
||||
#define MAX_TZ_SIZE
|
||||
static void
|
||||
gnc_g_date_time_fill_struct_tm (GDateTime *gdt, struct tm* time)
|
||||
{
|
||||
g_date_time_get_ymd (gdt, &(time->tm_year), &(time->tm_mon), &(time->tm_mday));
|
||||
time->tm_sec = g_date_time_get_second (gdt);
|
||||
time->tm_min = g_date_time_get_minute (gdt);
|
||||
time->tm_hour = g_date_time_get_hour (gdt);
|
||||
time->tm_wday = g_date_time_get_day_of_week (gdt);
|
||||
time->tm_yday = g_date_time_get_day_of_year (gdt);
|
||||
time->tm_isdst = g_date_time_is_daylight_savings (gdt);
|
||||
time->tm_year -= 1900;
|
||||
--time->tm_mon;
|
||||
}
|
||||
|
||||
struct tm*
|
||||
gnc_localtime (const gint64 *secs)
|
||||
{
|
||||
struct tm *time = g_slice_alloc0 (sizeof (struct tm));
|
||||
if (gnc_localtime_r (secs, time) == NULL)
|
||||
{
|
||||
gnc_tm_free (time);
|
||||
return NULL;
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
struct tm*
|
||||
gnc_localtime_r (const gint64 *secs, struct tm* time)
|
||||
{
|
||||
guint index = 0;
|
||||
GDateTime *gdt = gnc_g_date_time_new_from_unix_local (*secs);
|
||||
g_return_val_if_fail (gdt != NULL, NULL);
|
||||
|
||||
gnc_g_date_time_fill_struct_tm (gdt, time);
|
||||
timezone = - g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
|
||||
if (g_date_time_is_daylight_savings (gdt))
|
||||
{
|
||||
index = 1;
|
||||
daylight = 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_STRUCT_TM_GMTOFF
|
||||
time->tm_gmtoff = - timezone;
|
||||
#endif
|
||||
|
||||
g_date_time_unref (gdt);
|
||||
return time;
|
||||
}
|
||||
|
||||
struct tm*
|
||||
gnc_gmtime (const gint64 *secs)
|
||||
{
|
||||
struct tm *time;
|
||||
GDateTime *gdt = g_date_time_new_from_unix_utc (*secs);
|
||||
g_return_val_if_fail (gdt != NULL, NULL);
|
||||
time = g_slice_alloc0 (sizeof (struct tm));
|
||||
gnc_g_date_time_fill_struct_tm (gdt, time);
|
||||
g_date_time_unref (gdt);
|
||||
return time;
|
||||
}
|
||||
|
||||
static void
|
||||
normalize_time_component (gint *inner, gint *outer, guint divisor, gint base)
|
||||
{
|
||||
while (*inner < base)
|
||||
{
|
||||
--(*outer);
|
||||
*inner += divisor;
|
||||
}
|
||||
while (*inner > divisor)
|
||||
{
|
||||
++(*outer);
|
||||
*inner -= divisor;
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
normalize_month (gint month)
|
||||
{
|
||||
month = (month % 12 + 12) % 12;
|
||||
return month == 0 ? 12 : month;
|
||||
}
|
||||
|
||||
static void
|
||||
normalize_struct_tm (struct tm* time)
|
||||
{
|
||||
gint year = time->tm_year + 1900;
|
||||
gint last_day;
|
||||
gint64 secs;
|
||||
|
||||
++time->tm_mon;
|
||||
|
||||
normalize_time_component (&(time->tm_sec), &(time->tm_min), 60, 0);
|
||||
normalize_time_component (&(time->tm_min), &(time->tm_hour), 60, 0);
|
||||
normalize_time_component (&(time->tm_hour), &(time->tm_mday), 24, 0);
|
||||
normalize_time_component (&(time->tm_mon), &year, 12, 1);
|
||||
while (time->tm_mday < 1)
|
||||
{
|
||||
last_day = gnc_date_get_last_mday (normalize_month (--time->tm_mon), year);
|
||||
time->tm_mday += last_day;
|
||||
normalize_time_component (&(time->tm_mon), &year, 12, 1);
|
||||
}
|
||||
last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year);
|
||||
while (time->tm_mday > last_day)
|
||||
{
|
||||
++time->tm_mon;
|
||||
time->tm_mday -= last_day;
|
||||
normalize_time_component (&(time->tm_mon), &year, 12, 1);
|
||||
last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year);
|
||||
}
|
||||
time->tm_year = year - 1900;
|
||||
}
|
||||
|
||||
gint64
|
||||
gnc_mktime (struct tm* time)
|
||||
{
|
||||
GDateTime *gdt;
|
||||
gint64 secs;
|
||||
normalize_struct_tm (time);
|
||||
gdt = gnc_g_date_time_new_local (time->tm_year + 1900, time->tm_mon,
|
||||
time->tm_mday, time->tm_hour,
|
||||
time->tm_min, (gdouble)(time->tm_sec));
|
||||
time->tm_mon = time->tm_mon > 0 ? time->tm_mon - 1 : 11;
|
||||
time->tm_wday = g_date_time_get_day_of_week (gdt);
|
||||
time->tm_yday = g_date_time_get_day_of_year (gdt);
|
||||
time->tm_isdst = g_date_time_is_daylight_savings (gdt);
|
||||
|
||||
#ifdef HAVE_STRUCT_TM_GMTOFF
|
||||
time->tm_gmtoff = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
|
||||
#endif
|
||||
|
||||
secs = g_date_time_to_unix (gdt);
|
||||
g_date_time_unref (gdt);
|
||||
return secs;
|
||||
}
|
||||
|
||||
gint64
|
||||
gnc_timegm (struct tm* time)
|
||||
{
|
||||
GDateTime *gdt;
|
||||
gint64 secs;
|
||||
normalize_struct_tm (time);
|
||||
gdt = g_date_time_new_utc (time->tm_year + 1900, time->tm_mon,
|
||||
time->tm_mday, time->tm_hour, time->tm_min,
|
||||
(gdouble)(time->tm_sec));
|
||||
time->tm_mon = time->tm_mon > 0 ? time->tm_mon - 1 : 11;
|
||||
time->tm_wday = g_date_time_get_day_of_week (gdt);
|
||||
time->tm_yday = g_date_time_get_day_of_year (gdt);
|
||||
time->tm_isdst = g_date_time_is_daylight_savings (gdt);
|
||||
|
||||
secs = g_date_time_to_unix (gdt);
|
||||
g_date_time_unref (gdt);
|
||||
return secs;
|
||||
}
|
||||
|
||||
gchar*
|
||||
gnc_ctime (const gint64 *secs)
|
||||
{
|
||||
GDateTime *gdt = gnc_g_date_time_new_from_unix_local (*secs);
|
||||
gchar *string = g_date_time_format (gdt, "%a %b %H:%M:%S %Y");
|
||||
g_date_time_unref (gdt);
|
||||
return string;
|
||||
}
|
||||
|
||||
gint64
|
||||
gnc_time (gint64 *tbuf)
|
||||
{
|
||||
GDateTime *gdt = gnc_g_date_time_new_now_local ();
|
||||
gint64 secs = g_date_time_to_unix (gdt);
|
||||
g_date_time_unref (gdt);
|
||||
if (tbuf != NULL)
|
||||
*tbuf = secs;
|
||||
return secs;
|
||||
}
|
||||
|
||||
gdouble
|
||||
gnc_difftime (const gint64 secs1, const gint64 secs2)
|
||||
{
|
||||
return (double)secs2 - (double)secs1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
const char*
|
||||
gnc_date_dateformat_to_string(QofDateFormat format)
|
||||
@ -436,14 +637,15 @@ timespecCanonicalDayTime(Timespec t)
|
||||
{
|
||||
struct tm tm;
|
||||
Timespec retval;
|
||||
time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
|
||||
localtime_r(&t_secs, &tm);
|
||||
gint64 t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
|
||||
gnc_localtime_r(&t_secs, &tm);
|
||||
gnc_tm_set_day_middle(&tm);
|
||||
retval.tv_sec = mktime(&tm);
|
||||
retval.tv_sec = gnc_mktime(&tm);
|
||||
retval.tv_nsec = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* NB: month is 1-12, year is 0001 - 9999. */
|
||||
int gnc_date_get_last_mday (int month, int year)
|
||||
{
|
||||
static int last_day_of_month[2][12] =
|
||||
@ -636,7 +838,7 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
case QOF_DATE_FORMAT_LOCALE:
|
||||
{
|
||||
struct tm tm_str;
|
||||
time_t t;
|
||||
gint64 t;
|
||||
|
||||
tm_str.tm_mday = day;
|
||||
tm_str.tm_mon = month - 1; /* tm_mon = 0 through 11 */
|
||||
@ -644,8 +846,8 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
says, it's not a Y2K thing */
|
||||
|
||||
gnc_tm_set_day_start (&tm_str);
|
||||
t = mktime (&tm_str);
|
||||
localtime_r (&t, &tm_str);
|
||||
t = gnc_mktime (&tm_str);
|
||||
gnc_localtime_r (&t, &tm_str);
|
||||
flen = qof_strftime (buff, len, GNC_D_FMT, &tm_str);
|
||||
if (flen != 0)
|
||||
break;
|
||||
@ -665,18 +867,20 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
}
|
||||
|
||||
size_t
|
||||
qof_print_date_buff (char * buff, size_t len, time_t t)
|
||||
qof_print_date_buff (char * buff, size_t len, gint64 t)
|
||||
{
|
||||
struct tm theTime;
|
||||
|
||||
gint64 bt = t;
|
||||
size_t actual;
|
||||
if (!buff) return 0 ;
|
||||
if (!localtime_r(&t, &theTime))
|
||||
if (!gnc_localtime_r(&bt, &theTime))
|
||||
return 0;
|
||||
|
||||
return qof_print_date_dmy_buff (buff, len,
|
||||
actual = qof_print_date_dmy_buff (buff, len,
|
||||
theTime.tm_mday,
|
||||
theTime.tm_mon + 1,
|
||||
theTime.tm_year + 1900);
|
||||
return actual;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -689,7 +893,7 @@ qof_print_gdate( char *buf, size_t len, const GDate *gd )
|
||||
}
|
||||
|
||||
char *
|
||||
qof_print_date (time_t t)
|
||||
qof_print_date (gint64 t)
|
||||
{
|
||||
char buff[MAX_DATE_LENGTH];
|
||||
memset (buff, 0, sizeof (buff));
|
||||
@ -701,10 +905,10 @@ const char *
|
||||
gnc_print_date (Timespec ts)
|
||||
{
|
||||
static char buff[MAX_DATE_LENGTH];
|
||||
time_t t;
|
||||
gint64 t;
|
||||
|
||||
memset (buff, 0, sizeof (buff));
|
||||
t = ts.tv_sec + (time_t)(ts.tv_nsec / 1000000000.0);
|
||||
t = ts.tv_sec + (gint64)(ts.tv_nsec / 1000000000.0);
|
||||
|
||||
qof_print_date_buff (buff, MAX_DATE_LENGTH, t);
|
||||
|
||||
@ -758,7 +962,7 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
|
||||
int iday, imonth, iyear;
|
||||
int now_day, now_month, now_year;
|
||||
struct tm *now, utc;
|
||||
time_t secs;
|
||||
gint64 secs;
|
||||
|
||||
if (!buff) return(FALSE);
|
||||
|
||||
@ -801,11 +1005,12 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
|
||||
}
|
||||
|
||||
/* today's date */
|
||||
time (&secs);
|
||||
now = localtime (&secs);
|
||||
gnc_time (&secs);
|
||||
now = gnc_localtime (&secs);
|
||||
now_day = now->tm_mday;
|
||||
now_month = now->tm_mon + 1;
|
||||
now_year = now->tm_year + 1900;
|
||||
gnc_tm_free (now);
|
||||
|
||||
/* set defaults: if day or month appear to be blank, use today's date */
|
||||
iday = now_day;
|
||||
@ -1014,11 +1219,11 @@ char dateSeparator (void)
|
||||
/* Make a guess */
|
||||
gchar string[256];
|
||||
struct tm tm;
|
||||
time_t secs;
|
||||
gint64 secs;
|
||||
gchar *s;
|
||||
|
||||
secs = time(NULL);
|
||||
localtime_r(&secs, &tm);
|
||||
secs = gnc_time (NULL);
|
||||
gnc_localtime_r(&secs, &tm);
|
||||
qof_strftime(string, sizeof(string), GNC_D_FMT, &tm);
|
||||
|
||||
for (s = string; s != '\0'; s++)
|
||||
@ -1200,6 +1405,7 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
memset (&stm, 0, sizeof (stm));
|
||||
if (!str) return ts;
|
||||
dupe = g_strdup(str);
|
||||
stm.tm_year = atoi(str) - 1900;
|
||||
@ -1299,67 +1505,31 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that mktime returns 'local seconds' which is the true time
|
||||
/* Note that gnc_mktime returns 'local seconds' which is the true time
|
||||
* minus the timezone offset. We don't want to work with local
|
||||
* seconds, since they swim around acording to daylight savings, etc.
|
||||
* We want to work with universal time. Thus, add an offset
|
||||
* to undo the damage that mktime causes.
|
||||
* to undo the damage that gnc_mktime causes.
|
||||
*/
|
||||
{
|
||||
struct tm tmp_tm;
|
||||
struct tm tm;
|
||||
long int tz;
|
||||
int tz_hour;
|
||||
time_t secs;
|
||||
gint64 secs;
|
||||
|
||||
/* Use a temporary tm struct so the mktime call below
|
||||
/* Use a temporary tm struct so the gnc_mktime call below
|
||||
* doesn't mess up stm. */
|
||||
tmp_tm = stm;
|
||||
tmp_tm.tm_isdst = -1;
|
||||
|
||||
secs = mktime (&tmp_tm);
|
||||
|
||||
if (secs < 0)
|
||||
{
|
||||
/* Workaround buggy mktime implementations that get confused
|
||||
on the day daylight saving starts or ends. (OSX) */
|
||||
PWARN (" mktime failed to handle daylight saving: "
|
||||
"tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d for string=%s",
|
||||
stm.tm_hour, stm.tm_year, stm.tm_min,
|
||||
stm.tm_sec, stm.tm_isdst, dupe );
|
||||
tmp_tm.tm_hour++;
|
||||
secs = mktime (&tmp_tm);
|
||||
if (secs < 0)
|
||||
{
|
||||
/* if, for some strange reason, first attempt didn't fix it,
|
||||
try reversing the workaround. */
|
||||
tmp_tm.tm_hour -= 2;
|
||||
secs = mktime (&tmp_tm);
|
||||
}
|
||||
/* CAS: Even correct implementations of mktime can return
|
||||
(time_t)(-1): From the libc info page: "If the specified
|
||||
broken-down time cannot be represented as a simple time,
|
||||
`mktime' returns a value of `(time_t)(-1)' and does not modify
|
||||
the contents of BROKENTIME." This happens for dates after 2038
|
||||
when time_t is 32 bits. In those cases, this code above is
|
||||
just noisy and has a slight risk of returning the incorrect
|
||||
time.
|
||||
*/
|
||||
if (secs < 0)
|
||||
{
|
||||
/* Seriously buggy mktime - give up. */
|
||||
PERR (" unable to recover from buggy mktime ");
|
||||
g_free(dupe);
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/* The call to localtime is 'bogus', but it forces 'timezone' to
|
||||
secs = gnc_mktime (&tmp_tm);
|
||||
/* The call to gnc_localtime is 'bogus', but it forces 'timezone' to
|
||||
* be set. Note that we must use the accurate date, since the
|
||||
* value of 'gnc_timezone' includes daylight savings corrections
|
||||
* for that date. */
|
||||
|
||||
localtime_r (&secs, &tm);
|
||||
gnc_localtime_r (&secs, &tm);
|
||||
|
||||
tz = gnc_timezone (&tmp_tm);
|
||||
|
||||
@ -1367,16 +1537,7 @@ gnc_iso8601_to_timespec_gmt(const char *str)
|
||||
stm.tm_hour -= tz_hour;
|
||||
stm.tm_min -= (tz % 3600) / 60;
|
||||
stm.tm_isdst = tmp_tm.tm_isdst;
|
||||
ts.tv_sec = mktime (&stm);
|
||||
if (ts.tv_sec < 0)
|
||||
{
|
||||
PWARN (" mktime failed to adjust calculated time:"
|
||||
" tm_hour=%d tm_year=%d tm_min=%d tm_sec=%d tm_isdst=%d",
|
||||
stm.tm_hour, stm.tm_year, stm.tm_min,
|
||||
stm.tm_sec, stm.tm_isdst );
|
||||
/* Try and make some sense of the result. */
|
||||
ts.tv_sec = secs - tz;
|
||||
}
|
||||
ts.tv_sec = gnc_mktime (&stm);
|
||||
ts.tv_nsec = nsec;
|
||||
}
|
||||
g_free(dupe);
|
||||
@ -1390,15 +1551,15 @@ char *
|
||||
gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
|
||||
{
|
||||
int len, tz_hour, tz_min;
|
||||
long int secs;
|
||||
gint64 secs;
|
||||
char cyn;
|
||||
time_t tmp;
|
||||
gint64 tmp;
|
||||
struct tm parsed;
|
||||
|
||||
g_return_val_if_fail (buff != NULL, NULL);
|
||||
|
||||
tmp = ts.tv_sec;
|
||||
localtime_r(&tmp, &parsed);
|
||||
gnc_localtime_r(&tmp, &parsed);
|
||||
|
||||
secs = gnc_timezone (&parsed);
|
||||
|
||||
@ -1436,8 +1597,8 @@ void
|
||||
gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)
|
||||
{
|
||||
struct tm result;
|
||||
time_t t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
|
||||
localtime_r(&t_secs, &result);
|
||||
gint64 t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
|
||||
gnc_localtime_r(&t_secs, &result);
|
||||
|
||||
if (day) *day = result.tm_mday;
|
||||
if (month) *month = result.tm_mon + 1;
|
||||
@ -1454,23 +1615,7 @@ gnc_dmy2timespec_internal (int day, int month, int year, gboolean start_of_day)
|
||||
long long secs = 0;
|
||||
long long era = 0;
|
||||
|
||||
year -= 1900;
|
||||
|
||||
/* make a crude attempt to deal with dates outside the range of Dec
|
||||
* 1901 to Jan 2038. Note we screw up centennial leap years here so
|
||||
* hack alert */
|
||||
if ((2 > year) || (136 < year))
|
||||
{
|
||||
era = year / 32;
|
||||
year %= 32;
|
||||
if (0 > year)
|
||||
{
|
||||
year += 32;
|
||||
era -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
date.tm_year = year;
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = day;
|
||||
|
||||
@ -1480,9 +1625,7 @@ gnc_dmy2timespec_internal (int day, int month, int year, gboolean start_of_day)
|
||||
gnc_tm_set_day_end(&date);
|
||||
|
||||
/* compute number of seconds */
|
||||
secs = mktime (&date);
|
||||
|
||||
secs += era * THIRTY_TWO_YEARS;
|
||||
secs = gnc_mktime (&date);
|
||||
|
||||
result.tv_sec = secs;
|
||||
result.tv_nsec = 0;
|
||||
@ -1542,7 +1685,7 @@ gnc_timezone (const struct tm *tm)
|
||||
|
||||
|
||||
void
|
||||
timespecFromTime_t( Timespec *ts, time_t t )
|
||||
timespecFromTime_t( Timespec *ts, gint64 t )
|
||||
{
|
||||
ts->tv_sec = t;
|
||||
ts->tv_nsec = 0;
|
||||
@ -1552,31 +1695,46 @@ Timespec
|
||||
timespec_now()
|
||||
{
|
||||
Timespec ts;
|
||||
ts.tv_sec = time(NULL);
|
||||
ts.tv_sec = gnc_time(NULL);
|
||||
ts.tv_nsec = 0;
|
||||
return ts;
|
||||
}
|
||||
|
||||
time_t
|
||||
gint64
|
||||
timespecToTime_t (Timespec ts)
|
||||
{
|
||||
return ts.tv_sec;
|
||||
}
|
||||
|
||||
/* The GDate setter functions all in the end use g_date_set_time_t,
|
||||
* which in turn relies on localtime and is therefore subject to the
|
||||
* 2038 bug.
|
||||
*/
|
||||
GDate timespec_to_gdate (Timespec ts)
|
||||
{
|
||||
GDate result;
|
||||
g_date_clear(&result, 1);
|
||||
g_date_set_time_t(&result, timespecToTime_t(ts));
|
||||
g_assert(g_date_valid(&result));
|
||||
gint day, month, year;
|
||||
|
||||
g_date_clear (&result, 1);
|
||||
gnc_timespec2dmy (ts, &day, &month, &year);
|
||||
g_date_set_dmy (&result, day, month, year);
|
||||
g_assert(g_date_valid (&result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GDate* gnc_g_date_new_today ()
|
||||
{
|
||||
GDate *result = g_date_new();
|
||||
g_date_set_time_t(result, time(NULL));
|
||||
return result;
|
||||
GDateTime *gdt = gnc_g_date_time_new_now_local ();
|
||||
gint day, month, year;
|
||||
GDate *result;
|
||||
|
||||
g_date_time_get_ymd (gdt, &day, &month, &year);
|
||||
result = g_date_new_dmy (day, month, year);
|
||||
g_date_time_unref (gdt);
|
||||
g_assert(g_date_valid (result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Timespec gdate_to_timespec (GDate d)
|
||||
@ -1587,39 +1745,43 @@ Timespec gdate_to_timespec (GDate d)
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_tm_get_day_start (struct tm *tm, time_t time_val)
|
||||
gnc_tm_get_day_start (struct tm *tm, gint64 time_val)
|
||||
{
|
||||
/* Get the equivalent time structure */
|
||||
if (!localtime_r(&time_val, tm))
|
||||
if (!gnc_localtime_r(&time_val, tm))
|
||||
return;
|
||||
gnc_tm_set_day_start(tm);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_tm_get_day_end (struct tm *tm, time_t time_val)
|
||||
gnc_tm_get_day_end (struct tm *tm, gint64 time_val)
|
||||
{
|
||||
/* Get the equivalent time structure */
|
||||
if (!localtime_r(&time_val, tm))
|
||||
if (!gnc_localtime_r(&time_val, tm))
|
||||
return;
|
||||
gnc_tm_set_day_end(tm);
|
||||
}
|
||||
|
||||
time_t
|
||||
gnc_timet_get_day_start (time_t time_val)
|
||||
gint64
|
||||
gnc_timet_get_day_start (gint64 time_val)
|
||||
{
|
||||
struct tm tm;
|
||||
gint64 new_time;
|
||||
|
||||
gnc_tm_get_day_start(&tm, time_val);
|
||||
return mktime(&tm);
|
||||
new_time = gnc_mktime(&tm);
|
||||
return new_time;
|
||||
}
|
||||
|
||||
time_t
|
||||
gnc_timet_get_day_end (time_t time_val)
|
||||
gint64
|
||||
gnc_timet_get_day_end (gint64 time_val)
|
||||
{
|
||||
struct tm tm;
|
||||
gint64 new_time;
|
||||
|
||||
gnc_tm_get_day_end(&tm, time_val);
|
||||
return mktime(&tm);
|
||||
new_time = gnc_mktime(&tm);
|
||||
return new_time;
|
||||
}
|
||||
|
||||
|
||||
@ -1637,22 +1799,22 @@ gnc_tm_get_today_end (struct tm *tm)
|
||||
gnc_tm_get_day_end(tm, time(NULL));
|
||||
}
|
||||
|
||||
time_t
|
||||
gint64
|
||||
gnc_timet_get_today_start (void)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
gnc_tm_get_day_start(&tm, time(NULL));
|
||||
return mktime(&tm);
|
||||
return gnc_mktime(&tm);
|
||||
}
|
||||
|
||||
time_t
|
||||
gint64
|
||||
gnc_timet_get_today_end (void)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
gnc_tm_get_day_end(&tm, time(NULL));
|
||||
return mktime(&tm);
|
||||
return gnc_mktime(&tm);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -132,6 +132,84 @@ typedef enum
|
||||
GNCDATE_MONTH_NAME
|
||||
} GNCDateMonthFormat;
|
||||
|
||||
/* Replacements for POSIX functions which use time_t. Time_t is still
|
||||
* 32 bits in Microsoft Windows, Apple OSX, and some BSD versions even
|
||||
* when the rest of the system is 64-bits, as well as all 32-bit
|
||||
* versions of Unix. 32-bit time_t overflows at 03:14:07 UTC on
|
||||
* Tuesday, 19 January 2038 and so cannot represent dates after that.
|
||||
*/
|
||||
/** \brief fill out a time struct from a 64-bit time value.
|
||||
* \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment).
|
||||
* \return A struct tm*, allocated on the heap. Must be freed with gnc_tm_free().
|
||||
* The time is adjusted for the current local time zone.
|
||||
*/
|
||||
struct tm* gnc_localtime (const gint64 *secs);
|
||||
|
||||
/** \brief fill out a time struct from a 64-bit time value adjusted for the current time zone.
|
||||
* \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment)
|
||||
* \param time: A struct tm* for the function to fill.
|
||||
* The time is adjusted for the current local time zone.
|
||||
*/
|
||||
struct tm* gnc_localtime_r (const gint64 *secs, struct tm* time);
|
||||
|
||||
/** \brief fill out a time struct from a 64-bit time value
|
||||
* \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment)
|
||||
* \return A struct tm*, allocated on the heap. Must be freed with gnc_tm_free()
|
||||
* The time is UTC.
|
||||
*/
|
||||
struct tm* gnc_gmtime (const gint64 *secs);
|
||||
|
||||
/** \brief calculate seconds from the epoch given a time struct
|
||||
* \param time: A struct tm* for the function to fill.
|
||||
* The time is understood to be in the current local time zone.
|
||||
* \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment).
|
||||
*/
|
||||
gint64 gnc_mktime (struct tm* time);
|
||||
|
||||
/** \brief calculate seconds from the epoch given a time struct
|
||||
* \param time: A struct tm* for the function to fill.
|
||||
* The time is understood to be utc.
|
||||
* \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment).
|
||||
*/
|
||||
gint64 gnc_timegm (struct tm* time);
|
||||
|
||||
/** \brief Return a string representation of a date from a 64-bit time value
|
||||
* \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment)
|
||||
* \return A string, which must be freed with g_free(), representing the date
|
||||
* in the following format:
|
||||
* Thu Nov 24 18:22:48 1986\n\0
|
||||
* This is equivalent to the strftime format %a %b %H:%M:%S %Y.
|
||||
*/
|
||||
gchar* gnc_ctime (const gint64 *secs);
|
||||
|
||||
/** \brief get the current local time
|
||||
* \param A gint64* which, if not NULL, will be filled in with the same
|
||||
* value as is returned.
|
||||
* \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
|
||||
* are seconds before that moment)
|
||||
*/
|
||||
gint64 gnc_time (gint64 *tbuf);
|
||||
|
||||
/** \brief Find the difference in seconds between two time values
|
||||
* \param secs1: The first time value, in Seconds since
|
||||
* 00:00:01 UTC 01 January 1970 (negative values are seconds before that moment)
|
||||
* \param secs2: The second time value, in Seconds since
|
||||
* 00:00:01 UTC 01 January 1970 (negative values are seconds before that moment)
|
||||
* \return The difference in seconds between secs1 and secs2. If secs1 is
|
||||
* later than secs2 the value will be negative.
|
||||
*/
|
||||
gdouble gnc_difftime (const gint64 secs1, const gint64 secs2);
|
||||
|
||||
/** \brief free a struct tm* created with gnc_localtime() or gnc_gmtime()
|
||||
* \param time: The struct tm* to be freed.
|
||||
*/
|
||||
void gnc_tm_free (struct tm* time);
|
||||
|
||||
/** \name String / DateFormat conversion. */
|
||||
//@{
|
||||
@ -217,11 +295,11 @@ Timespec timespecCanonicalDayTime(Timespec t);
|
||||
/** Returns the current clock time as a Timespec, taken from time(2). */
|
||||
Timespec timespec_now (void);
|
||||
|
||||
/** Turns a time_t into a Timespec */
|
||||
void timespecFromTime_t( Timespec *ts, time_t t );
|
||||
/** Turns a gint64 into a Timespec */
|
||||
void timespecFromTime_t( Timespec *ts, gint64 t );
|
||||
|
||||
/** Turns a Timespec into a time_t */
|
||||
time_t timespecToTime_t (Timespec ts);
|
||||
/** Turns a Timespec into a gint64 */
|
||||
gint64 timespecToTime_t (Timespec ts);
|
||||
|
||||
/** Returns a newly allocated date of the current clock time, taken from
|
||||
* time(2). The caller must g_date_free() the object afterwards. */
|
||||
@ -423,7 +501,7 @@ gsize qof_strftime(gchar *buf, gsize max, const gchar *format,
|
||||
size_t qof_print_date_dmy_buff (gchar * buff, size_t buflen, int day, int month, int year);
|
||||
|
||||
/** Convenience: calls through to qof_print_date_dmy_buff(). **/
|
||||
size_t qof_print_date_buff (char * buff, size_t buflen, time_t secs);
|
||||
size_t qof_print_date_buff (char * buff, size_t buflen, gint64 secs);
|
||||
|
||||
/** Convenience; calls through to qof_print_date_dmy_buff(). **/
|
||||
size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd);
|
||||
@ -431,7 +509,7 @@ size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd);
|
||||
/** Convenience; calls through to qof_print_date_dmy_buff().
|
||||
* Return: string, which should be freed when no longer needed.
|
||||
* **/
|
||||
char * qof_print_date (time_t secs);
|
||||
char * qof_print_date (gint64 secs);
|
||||
|
||||
/** Convenience; calls through to qof_print_date_dmy_buff().
|
||||
* Return: static global string.
|
||||
@ -448,7 +526,7 @@ const char * gnc_print_date(Timespec ts);
|
||||
* Returns the number of bytes printed.
|
||||
*/
|
||||
|
||||
size_t qof_print_date_time_buff (char * buff, size_t len, time_t secs);
|
||||
size_t qof_print_date_time_buff (char * buff, size_t len, gint64 secs);
|
||||
|
||||
/** qof_scan_date
|
||||
* Convert a string into day / month / year integers according to
|
||||
@ -518,11 +596,11 @@ void gnc_tm_set_day_end (struct tm *tm)
|
||||
|
||||
/** The gnc_timet_get_day_start() routine will take the given time in
|
||||
* seconds and adjust it to the last second of that day. */
|
||||
time_t gnc_timet_get_day_start(time_t time_val);
|
||||
gint64 gnc_timet_get_day_start(gint64 time_val);
|
||||
|
||||
/** The gnc_timet_get_day_end() routine will take the given time in
|
||||
* seconds and adjust it to the last second of that day. */
|
||||
time_t gnc_timet_get_day_end(time_t time_val);
|
||||
gint64 gnc_timet_get_day_end(gint64 time_val);
|
||||
|
||||
/** Get the numerical last date of the month. (28, 29, 30, 31) */
|
||||
int gnc_date_get_last_mday (int month, int year);
|
||||
@ -541,13 +619,13 @@ void gnc_tm_get_today_start(struct tm *tm);
|
||||
* tm and fills it in with the last second of the today. */
|
||||
void gnc_tm_get_today_end(struct tm *tm);
|
||||
|
||||
/** The gnc_timet_get_today_start() routine returns a time_t value
|
||||
/** The gnc_timet_get_today_start() routine returns a gint64 value
|
||||
* corresponding to the first second of today. */
|
||||
time_t gnc_timet_get_today_start(void);
|
||||
gint64 gnc_timet_get_today_start(void);
|
||||
|
||||
/** The gnc_timet_get_today_end() routine returns a time_t value
|
||||
/** The gnc_timet_get_today_end() routine returns a gint64 value
|
||||
* corresponding to the last second of today. */
|
||||
time_t gnc_timet_get_today_end(void);
|
||||
gint64 gnc_timet_get_today_end(void);
|
||||
|
||||
/** The xaccDateUtilGetStampNow() routine returns the current time in
|
||||
* seconds in textual format.
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user