After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 780594 - GDateTime/GTimeZone problems
GDateTime/GTimeZone problems
Status: RESOLVED NOTABUG
Product: glib
Classification: Platform
Component: general
2.50.x
Other Windows
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2017-03-27 13:42 UTC by Jeffrey Stedfast
Modified: 2017-04-04 08:45 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Jeffrey Stedfast 2017-03-27 13:42:29 UTC
I'm trying to migrate GMime over to using GDateTime instead of time_t & an int tz_offset.

Here's the problem:

When parsing a date/time with a timezone of "-0400" or "EDT", g_time_zone_new() seems to gobble that up just fine.

I then pass that off to g_date_time_new() along with the parsed year/month/day/hour/minute/second values that I parsed from the Date header.

So far so good...

However, when I go to format the GDateTime, g_date_time_get_utc_offset() is returning 0.

If I modify the Date header and replace "EDT" with "EST" and/or replace "-0400" with "-0500", then I get the expected UTC offset (-5 hours).

Why?
Comment 1 Philip Withnall 2017-03-27 13:45:02 UTC
Some example code which reproduces the problem (ideally in the form of a unit test) would help here.
Comment 2 Jeffrey Stedfast 2017-03-27 13:57:41 UTC
#include <stdio.h>
#include <glib.h>

static char *tm_months[] = {
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

static char *tm_days[] = {
	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

static char *
format_date (GDateTime *date)
{
	int wday, year, month, day, hour, min, sec, tz_offset, sign;
	GTimeSpan tz;
	
	wday = g_date_time_get_day_of_week (date);
	year = g_date_time_get_year (date);
	month = g_date_time_get_month (date);
	day = g_date_time_get_day_of_month (date);
	hour = g_date_time_get_hour (date);
	min = g_date_time_get_minute (date);
	sec = g_date_time_get_second (date);
	tz = g_date_time_get_utc_offset (date);
	
	printf ("tz = %lld\n", tz);
	
	sign = tz < 0 ? -1 : 1;
	tz *= sign;
	
	tz_offset = 100 * (tz / G_TIME_SPAN_HOUR);
	tz_offset += (tz % G_TIME_SPAN_HOUR) / G_TIME_SPAN_MINUTE;
	tz_offset *= sign;
 	
 	return g_strdup_printf ("%s, %02d %s %04d %02d:%02d:%02d %+05d",
				tm_days[wday % 7], day, tm_months[month - 1],
				year, hour, min, sec, tz_offset);
}

int main (int argc, char **argv)
{
	GTimeZone *tz = g_time_zone_new ("EDT");
	GDateTime *date = g_date_time_new (tz, 2017, 3, 27, 9, 51, 27);
	char *str = format_date (date);
	
	printf ("%s\n", str);
	g_free (str);
	
	return 0;
}
Comment 3 Jeffrey Stedfast 2017-03-27 13:59:14 UTC
Output:

[fejj@localhost gmime]$ ./test-case 
tz = 0
Mon, 27 Mar 2017 09:51:27 +0000
Comment 4 Jeffrey Stedfast 2017-03-27 14:00:37 UTC
[fejj@localhost gmime]$ pkg-config --modversion glib-2.0
2.50.3
Comment 5 Jeffrey Stedfast 2017-03-27 14:17:37 UTC
FWIW, in this simple test case, a string of "-0400" seems to work fine, but as you can see, "EDT" does not.

I might have to double-check my parsing code to make sure that the cases where I thought "-0400" were failing weren't due to something else.

It's odd tho because my own GMime unit tests have exactly the same dates where I use -0500 and -0400 and the one with -0400 fails while -0500 doesn't.

Same with EDT vs EST which is how I noticed this problem.

Perhaps the -0400 issue is due to me using a different OS?

This test case was written/run on Fedora 25 but I was writing the patch for GMime on Mac OS X with glib 2.50.3 (from brew).
Comment 6 Jeffrey Stedfast 2017-03-27 14:24:29 UTC
Hmmm, nope, test case produces the same results on Mac OS X.

I guess never mind about the "-0400" thing.
Comment 7 Jeffrey Stedfast 2017-03-27 17:25:26 UTC
Re-examined my GMime unit tests and I was wrong, it was only failing when EDT was specified, not "-0400". I was confused because I was looking at the expected output string (the expected date string after it had been parsed + re-formatted) and not the input string.

I'm now working around this EDT issue by mapping timezone names like "EDT" to "-0400" and then passing "-0400" to g_time_zone_new().
Comment 9 Philip Withnall 2017-04-04 08:45:30 UTC
I think this is not a bug: the ‘EDT’ timezone doesn’t exist in the tz database. You might want ‘EST5EDT’ instead, or to use hour offsets as your workaround does already.

$ find /usr/share/zoneinfo/ -name '*EDT*'
/usr/share/zoneinfo/right/EST5EDT
/usr/share/zoneinfo/posix/EST5EDT
/usr/share/zoneinfo/EST5EDT

See bug #677522 for the fact that g_time_zone_new() doesn’t provide any feedback when passed an invalid tz identifier.