mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Rewrite gnc_iso8601_to_timespec_gmt
Into something that isn't an ugly hack and actually works. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22606 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
586e124ba5
commit
16bf61fbcc
@ -1391,157 +1391,41 @@ xaccDateUtilGetStampNow (void)
|
|||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
* iso 8601 datetimes should look like 1998-07-02 11:00:00.68-05
|
* iso 8601 datetimes should look like 1998-07-02 11:00:00.68-05
|
||||||
\********************************************************************/
|
\********************************************************************/
|
||||||
/* hack alert -- this routine returns incorrect values for
|
/* Unfortunately, not all strptime or struct tm implementations
|
||||||
* dates before 1970 */
|
* support timezones, so we have to do this with sscanf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ISO_DATE_FORMAT "%d-%d-%d %d:%d:%lf%s"
|
||||||
Timespec
|
Timespec
|
||||||
gnc_iso8601_to_timespec_gmt(const char *str)
|
gnc_iso8601_to_timespec_gmt(const char *str)
|
||||||
{
|
{
|
||||||
char buf[4];
|
Timespec time = { 0L, 0L };
|
||||||
gchar *dupe;
|
GDateTime *gdt;
|
||||||
Timespec ts;
|
gint hour = 0, minute = 0, day = 0, month = 0, year = 0;
|
||||||
struct tm stm;
|
gchar zone[6] = "\0\0\0\0\0\0";
|
||||||
long int nsec = 0;
|
gdouble second = 0.0;
|
||||||
|
gint fields;
|
||||||
|
|
||||||
ts.tv_sec = 0;
|
if (!str)
|
||||||
ts.tv_nsec = 0;
|
return time;
|
||||||
memset (&stm, 0, sizeof (stm));
|
|
||||||
if (!str) return ts;
|
|
||||||
dupe = g_strdup(str);
|
|
||||||
stm.tm_year = atoi(str) - 1900;
|
|
||||||
str = strchr (str, '-');
|
|
||||||
if (str)
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
stm.tm_mon = atoi(str) - 1;
|
|
||||||
str = strchr (str, '-');
|
|
||||||
if (str)
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
stm.tm_mday = atoi(str);
|
|
||||||
|
|
||||||
str = strchr (str, ' ');
|
fields = sscanf (str, ISO_DATE_FORMAT, &year, &month,
|
||||||
if (str)
|
&day, &hour, &minute, &second, zone);
|
||||||
|
if (fields < 1)
|
||||||
|
return time;
|
||||||
|
else if (fields > 6 && strlen (zone) > 0) /* Date string included a timezone */
|
||||||
{
|
{
|
||||||
str++;
|
GTimeZone *tz = g_time_zone_new (zone);
|
||||||
|
gdt = g_date_time_new (tz, year, month, day, hour, minute, second);
|
||||||
|
g_time_zone_unref (tz);
|
||||||
}
|
}
|
||||||
else
|
else /* No zone info, assume UTC */
|
||||||
{
|
gdt = g_date_time_new_utc (year, month, day, hour, minute, second);
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
stm.tm_hour = atoi(str);
|
|
||||||
str = strchr (str, ':');
|
|
||||||
if (str)
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
stm.tm_min = atoi(str);
|
|
||||||
str = strchr (str, ':');
|
|
||||||
if (str)
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
stm.tm_sec = atoi (str);
|
|
||||||
|
|
||||||
/* The decimal point, optionally present ... */
|
time.tv_sec = g_date_time_to_unix (gdt);
|
||||||
/* hack alert -- this algo breaks if more than 9 decimal places present */
|
time.tv_nsec = g_date_time_get_microsecond (gdt) * 1000;
|
||||||
if (strchr (str, '.'))
|
g_date_time_unref (gdt);
|
||||||
{
|
return time;
|
||||||
int decimals, i, multiplier = 1000000000;
|
|
||||||
str = strchr (str, '.') + 1;
|
|
||||||
decimals = strcspn (str, "+- ");
|
|
||||||
for (i = 0; i < decimals; i++) multiplier /= 10;
|
|
||||||
nsec = atoi(str) * multiplier;
|
|
||||||
}
|
|
||||||
stm.tm_isdst = -1;
|
|
||||||
|
|
||||||
/* Timezone format can be +hh or +hhmm or +hh.mm (or -) (or not present) */
|
|
||||||
str += strcspn (str, "+-");
|
|
||||||
if (*str)
|
|
||||||
{
|
|
||||||
buf[0] = str[0];
|
|
||||||
buf[1] = str[1];
|
|
||||||
buf[2] = str[2];
|
|
||||||
buf[3] = 0;
|
|
||||||
stm.tm_hour -= atoi(buf);
|
|
||||||
|
|
||||||
str += 3;
|
|
||||||
if ('.' == *str) str++;
|
|
||||||
if (isdigit ((unsigned char)*str) && isdigit ((unsigned char)*(str + 1)))
|
|
||||||
{
|
|
||||||
int cyn;
|
|
||||||
/* copy sign from hour part */
|
|
||||||
if ('+' == buf[0])
|
|
||||||
{
|
|
||||||
cyn = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cyn = +1;
|
|
||||||
}
|
|
||||||
buf[0] = str[0];
|
|
||||||
buf[1] = str[1];
|
|
||||||
buf[2] = str[2];
|
|
||||||
buf[3] = 0;
|
|
||||||
stm.tm_min += cyn * atoi(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 gnc_mktime causes.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
struct tm tmp_tm;
|
|
||||||
struct tm tm;
|
|
||||||
long int tz;
|
|
||||||
int tz_hour;
|
|
||||||
gint64 secs;
|
|
||||||
|
|
||||||
/* 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 = 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. */
|
|
||||||
|
|
||||||
gnc_localtime_r (&secs, &tm);
|
|
||||||
|
|
||||||
tz = gnc_timezone (&tmp_tm);
|
|
||||||
|
|
||||||
tz_hour = tz / 3600;
|
|
||||||
stm.tm_hour -= tz_hour;
|
|
||||||
stm.tm_min -= (tz % 3600) / 60;
|
|
||||||
stm.tm_isdst = tmp_tm.tm_isdst;
|
|
||||||
ts.tv_sec = gnc_mktime (&stm);
|
|
||||||
ts.tv_nsec = nsec;
|
|
||||||
}
|
|
||||||
g_free(dupe);
|
|
||||||
return ts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************\
|
/********************************************************************\
|
||||||
|
@ -1617,7 +1617,7 @@ test_gnc_iso8601_to_timespec_gmt (void)
|
|||||||
g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt2));
|
g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt2));
|
||||||
g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt2));
|
g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt2));
|
||||||
|
|
||||||
t = gnc_iso8601_to_timespec_gmt ("2012-07-04 19:27:44.0+08.40");
|
t = gnc_iso8601_to_timespec_gmt ("2012-07-04 19:27:44.0+08:40");
|
||||||
g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt3));
|
g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt3));
|
||||||
g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt3));
|
g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt3));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user