# HG changeset patch # User Richard Laager # Date 1139086552 0 # Node ID fcde3faa1f57031e79ade6e92244ab9bf93e5798 # Parent 8855973b487b4385e6a9bddef725859760a57b20 [gaim-migrate @ 15481] This adds support for displaying log timestamps in their original timezone. If your OS's definition of struct tm sucks, then the log timestamps will show up in your local timezone, but converted, so the time is accurate. Yay! Anyway, this all works, as I've renamed lots of my log files locally, but currently, there's no code to save new logs in this name format. That's held up on a portability issue and backwards compatibility issue. committer: Tailor Script diff -r 8855973b487b -r fcde3faa1f57 plugins/history.c --- a/plugins/history.c Sat Feb 04 05:17:46 2006 +0000 +++ b/plugins/history.c Sat Feb 04 20:55:52 2006 +0000 @@ -115,7 +115,7 @@ gaim_account_get_protocol_name(((GaimLog*)logs->data)->account)); header = g_strdup_printf("Conversation with %s on %s:
", alias, - gaim_date_format_full(((GaimLog *)logs->data)->time)); + gaim_date_format_full(localtime(&((GaimLog *)logs->data)->time))); gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), header, options); g_free(header); diff -r 8855973b487b -r fcde3faa1f57 plugins/log_reader.c --- a/plugins/log_reader.c Sat Feb 04 05:17:46 2006 +0000 +++ b/plugins/log_reader.c Sat Feb 04 20:55:52 2006 +0000 @@ -156,7 +156,8 @@ tm.tm_year -= 1900; tm.tm_mon -= 1; - log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm)); + /* XXX: Look into this later... Should we pass in a struct tm? */ + log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm), NULL); log->logger = adium_logger; log->logger_data = data; @@ -216,7 +217,8 @@ data->path = filename; data->type = ADIUM_TEXT; - log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm)); + /* XXX: Look into this later... Should we pass in a struct tm? */ + log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm), NULL); log->logger = adium_logger; log->logger_data = data; @@ -730,7 +732,8 @@ data->text = NULL; data->last_log = FALSE; - log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, msn_logger_parse_timestamp(message)); + /* XXX: Look into this later... Should we pass in a struct tm? */ + log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, msn_logger_parse_timestamp(message), NULL); log->logger = msn_logger; log->logger_data = data; @@ -1244,8 +1247,9 @@ data->their_nickname = g_strdup(their_nickname); + /* XXX: Look into this later... Should we pass in a struct tm? */ log = gaim_log_new(GAIM_LOG_IM, - sn, account, NULL, mktime(&tm)); + sn, account, NULL, mktime(&tm), NULL); log->logger = trillian_logger; log->logger_data = data; diff -r 8855973b487b -r fcde3faa1f57 plugins/perl/common/Util.xs --- a/plugins/perl/common/Util.xs Sat Feb 04 05:17:46 2006 +0000 +++ b/plugins/perl/common/Util.xs Sat Feb 04 20:55:52 2006 +0000 @@ -52,8 +52,8 @@ int mode const char * -gaim_date_format_full(time) - time_t time +gaim_date_format_full(tm) + const struct tm *tm const char * gaim_date_format_long(tm) @@ -182,9 +182,12 @@ const char *name time_t -gaim_str_to_time(timestamp, utc) +gaim_str_to_time(timestamp, utc = FALSE, tm = NULL, tz_off = NULL, rest = NULL) const char *timestamp gboolean utc + struct tm *tm + long *tz_off + const char **rest gchar * gaim_strcasereplace(string, delimiter, replacement) diff -r 8855973b487b -r fcde3faa1f57 plugins/perl/common/typemap --- a/plugins/perl/common/typemap Sat Feb 04 05:17:46 2006 +0000 +++ b/plugins/perl/common/typemap Sat Feb 04 20:55:52 2006 +0000 @@ -22,6 +22,7 @@ const guchar * T_PV char * T_PV int * T_PTR +long * T_PTR size_t * T_PTR Gaim::GTK::Widget * T_PTR GCallback T_PTR @@ -30,6 +31,7 @@ GData * T_PTR GData ** T_PTR const unsigned char * T_PTR +struct tm * T_PTR const struct tm * T_PTR xmlnode * T_PTR const xmlnode * T_PTR diff -r 8855973b487b -r fcde3faa1f57 src/account.c --- a/src/account.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/account.c Sat Feb 04 20:55:52 2006 +0000 @@ -1929,7 +1929,7 @@ account->system_log = gaim_log_new(GAIM_LOG_SYSTEM, gaim_account_get_username(account), account, NULL, - (login_time != 0) ? login_time : time(NULL)); + (login_time != 0) ? login_time : time(NULL), NULL); } return account->system_log; diff -r 8855973b487b -r fcde3faa1f57 src/conversation.c --- a/src/conversation.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/conversation.c Sat Feb 04 20:55:52 2006 +0000 @@ -211,7 +211,7 @@ { conv->logs = g_list_append(NULL, gaim_log_new(conv->type == GAIM_CONV_TYPE_CHAT ? GAIM_LOG_CHAT : GAIM_LOG_IM, conv->name, conv->account, - conv, time(NULL))); + conv, time(NULL), NULL)); } diff -r 8855973b487b -r fcde3faa1f57 src/gtkdebug.c --- a/src/gtkdebug.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/gtkdebug.c Sat Feb 04 20:55:52 2006 +0000 @@ -219,7 +219,7 @@ } tmp = gtk_imhtml_get_text(GTK_IMHTML(win->text), NULL, NULL); - fprintf(fp, "Gaim Debug Log : %s\n", gaim_date_format_full(time(NULL))); + fprintf(fp, "Gaim Debug Log : %s\n", gaim_date_format_full(NULL)); fprintf(fp, "%s", tmp); g_free(tmp); diff -r 8855973b487b -r fcde3faa1f57 src/gtklog.c --- a/src/gtklog.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/gtklog.c Sat Feb 04 20:55:52 2006 +0000 @@ -117,7 +117,7 @@ gtk_tree_store_append (lv->treestore, &iter, NULL); gtk_tree_store_set(lv->treestore, &iter, - 0, gaim_date_format_full(log->time), + 0, gaim_date_format_full(localtime(&log->time)), 1, log, -1); } g_free(read); @@ -200,10 +200,14 @@ char *title; if (log->type == GAIM_LOG_CHAT) title = g_strdup_printf(_("Conversation in %s on %s"), - log->name, gaim_date_format_full(log->time)); + log->name, + log->tm ? gaim_date_format_full(log->tm) : + gaim_date_format_full(localtime(&log->time))); else title = g_strdup_printf(_("Conversation with %s on %s"), - log->name, gaim_date_format_full(log->time)); + log->name, + log->tm ? gaim_date_format_full(log->tm) : + gaim_date_format_full(localtime(&log->time))); gtk_label_set_markup(GTK_LABEL(viewer->label), title); g_free(title); @@ -251,7 +255,8 @@ while (logs != NULL) { GaimLog *log = logs->data; - month = gaim_utf8_strftime(_("%B %Y"), localtime(&log->time)); + month = gaim_utf8_strftime(_("%B %Y"), + log->tm ? log->tm : localtime(&log->time)); if (strcmp(month, prev_top_month) != 0) { @@ -265,7 +270,7 @@ /* sub */ gtk_tree_store_append(lv->treestore, &child, &toplevel); gtk_tree_store_set(lv->treestore, &child, - 0, gaim_date_format_full(log->time), + 0, log->tm ? gaim_date_format_full(log->tm) : gaim_date_format_full(localtime(&log->time)), 1, log, -1); diff -r 8855973b487b -r fcde3faa1f57 src/gtkpounce.c --- a/src/gtkpounce.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/gtkpounce.c Sat Feb 04 20:55:52 2006 +0000 @@ -1472,10 +1472,12 @@ name_shown = gaim_account_get_username(account); if (reason == NULL) - gaim_notify_info(NULL, name_shown, tmp, gaim_date_format_full(time(NULL))); + { + gaim_notify_info(NULL, name_shown, tmp, gaim_date_format_full(NULL)); + } else { - char *tmp2 = g_strdup_printf("%s\n\n%s", reason, gaim_date_format_full(time(NULL))); + char *tmp2 = g_strdup_printf("%s\n\n%s", reason, gaim_date_format_full(NULL)); gaim_notify_info(NULL, name_shown, tmp, tmp2); g_free(tmp2); } diff -r 8855973b487b -r fcde3faa1f57 src/log.c --- a/src/log.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/log.c Sat Feb 04 20:55:52 2006 +0000 @@ -72,7 +72,7 @@ **************************************************************************/ GaimLog *gaim_log_new(GaimLogType type, const char *name, GaimAccount *account, - GaimConversation *conv, time_t time) + GaimConversation *conv, time_t time, const struct tm *tm) { GaimLog *log = g_new0(GaimLog, 1); log->name = g_strdup(gaim_normalize(account, name)); @@ -81,6 +81,17 @@ log->time = time; log->type = type; log->logger_data = NULL; + if (tm != NULL) + { + log->tm = g_new0(struct tm, 1); + *(log->tm) = *tm; + +#ifdef HAVE_STRUCT_TM_TM_ZONE + /* XXX: This is so wrong... */ + if (log->tm->tm_zone != NULL) + log->tm->tm_zone = (const char *)g_strdup(log->tm->tm_zone); +#endif + } log->logger = gaim_log_logger_get(); if (log->logger && log->logger->create) log->logger->create(log); @@ -93,6 +104,16 @@ if (log->logger && log->logger->finalize) log->logger->finalize(log); g_free(log->name); + + if (log->tm != NULL) + { +#ifdef HAVE_STRUCT_TM_TM_ZONE + /* XXX: This is so wrong... */ + g_free((char *)log->tm->tm_zone); +#endif + g_free(log->tm); + } + g_free(log); } @@ -666,9 +687,35 @@ { GaimLog *log; GaimLogCommonLoggerData *data; - time_t stamp = gaim_str_to_time(filename, FALSE); +#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE) + struct tm tm; + long tz_off; + const char *rest; + time_t stamp = gaim_str_to_time(filename, FALSE, &tm, &tz_off, &rest); + char *end; + + /* As zero is a valid offset, GAIM_NO_TZ_OFF means no offset was + * provided. See util.h. Yes, it's kinda ugly. */ + if (tz_off != GAIM_NO_TZ_OFF) + tm.tm_gmtoff = tz_off - tm.tm_gmtoff; - log = gaim_log_new(type, name, account, NULL, stamp); + if (rest == NULL || (end = strchr(rest, '.')) == NULL) + { + log = gaim_log_new(type, name, account, NULL, stamp, NULL); + } + else + { + char *tmp = g_strndup(rest, end - rest); + tm.tm_zone = tmp; + log = gaim_log_new(type, name, account, NULL, stamp, &tm); + g_free(tmp); + } +#else + time_t stamp = gaim_str_to_time(filename, FALSE, NULL, NULL, NULL); + + log = gaim_log_new(type, name, account, NULL, stamp, NULL); +#endif + log->logger = logger; log->logger_data = data = g_new0(GaimLogCommonLoggerData, 1); data->path = g_build_filename(path, filename, NULL); @@ -932,7 +979,7 @@ if(!data->file) return 0; - date = gaim_date_format_full(log->time); + date = gaim_date_format_full(localtime(&log->time)); written += fprintf(data->file, ""); written += fprintf(data->file, ""); @@ -1071,7 +1118,7 @@ return 0; written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n", - log->name, gaim_date_format_full(log->time), + log->name, gaim_date_format_full(localtime(&log->time)), gaim_account_get_username(log->account), prpl); } @@ -1234,7 +1281,7 @@ newlen--; if (newlen != 0) { - log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, -1); + log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, -1, NULL); log->logger = old_logger; log->time = lasttime; data = g_new0(struct old_logger_data, 1); @@ -1285,7 +1332,7 @@ if (logfound) { if ((newlen = ftell(file) - lastoff) != 0) { - log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, -1); + log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, -1, NULL); log->logger = old_logger; log->time = lasttime; data = g_new0(struct old_logger_data, 1); diff -r 8855973b487b -r fcde3faa1f57 src/log.h --- a/src/log.h Sat Feb 04 05:17:46 2006 +0000 +++ b/src/log.h Sat Feb 04 20:55:52 2006 +0000 @@ -112,13 +112,20 @@ GaimLogType type; /**< The type of log this is */ char *name; /**< The name of this log */ GaimAccount *account; /**< The account this log is taking - place on */ + place on */ GaimConversation *conv; /**< The conversation being logged */ time_t time; /**< The time this conversation - started */ + started, converted to the local timezone */ + GaimLogLogger *logger; /**< The logging mechanism this log - is to use */ + is to use */ void *logger_data; /**< Data used by the log logger */ + struct tm *tm; /**< The time this conversation + started, saved with original + timezone data, if available and + if struct tm has the BSD + timezone fields, else @c NULL. + Do NOT modify anything in this struct.*/ }; /** @@ -173,10 +180,12 @@ * @param account The account the conversation is occurring on * @param conv The conversation being logged * @param time The time this conversation started + * @param tm The time this conversation started, with timezone data, + * if available and if struct tm has the BSD timezone fields. * @return The new log */ GaimLog *gaim_log_new(GaimLogType type, const char *name, GaimAccount *account, - GaimConversation *conv, time_t time); + GaimConversation *conv, time_t time, const struct tm *tm); /** * Frees a log diff -r 8855973b487b -r fcde3faa1f57 src/protocols/irc/msgs.c --- a/src/protocols/irc/msgs.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/irc/msgs.c Sat Feb 04 20:55:52 2006 +0000 @@ -241,7 +241,8 @@ gchar *timex = gaim_str_seconds_to_string(irc->whois.idle); g_string_append_printf(info, _("Idle for: %s
"), timex); g_free(timex); - g_string_append_printf(info, _("%s: %s"), _("Online since"), gaim_date_format_full(irc->whois.signon)); + g_string_append_printf(info, _("%s: %s"), _("Online since"), + gaim_date_format_full(localtime(&irc->whois.signon))); } if (!strcmp(irc->whois.nick, "Paco-Paco")) { g_string_append_printf(info, _("
Defining adjective: Glorious
")); diff -r 8855973b487b -r fcde3faa1f57 src/protocols/jabber/message.c --- a/src/protocols/jabber/message.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/jabber/message.c Sat Feb 04 20:55:52 2006 +0000 @@ -311,7 +311,7 @@ const char *timestamp = xmlnode_get_attrib(child, "stamp"); jm->delayed = TRUE; if(timestamp) - jm->sent = gaim_str_to_time(timestamp, TRUE); + jm->sent = gaim_str_to_time(timestamp, TRUE, NULL, NULL, NULL); } else if(xmlns && !strcmp(xmlns, "jabber:x:conference") && jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE && jm->type != JABBER_MESSAGE_ERROR) { diff -r 8855973b487b -r fcde3faa1f57 src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/msn/msn.c Sat Feb 04 20:55:52 2006 +0000 @@ -1425,7 +1425,7 @@ static char *msn_info_date_reformat(const char *field, size_t len) { char *tmp = g_strndup(field, len); - time_t t = gaim_str_to_time(tmp, FALSE); + time_t t = gaim_str_to_time(tmp, FALSE, NULL, NULL, NULL); g_free(tmp); return g_strdup(gaim_date_format_short(localtime(&t))); diff -r 8855973b487b -r fcde3faa1f57 src/protocols/novell/nmevent.c --- a/src/protocols/novell/nmevent.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/novell/nmevent.c Sat Feb 04 20:55:52 2006 +0000 @@ -803,13 +803,13 @@ return -1; } -guint32 +time_t nm_event_get_gmt(NMEvent * event) { if (event) return event->gmt; else - return (guint32)-1; + return (time_t)-1; } NMERR_T diff -r 8855973b487b -r fcde3faa1f57 src/protocols/novell/nmevent.h --- a/src/protocols/novell/nmevent.h Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/novell/nmevent.h Sat Feb 04 20:55:52 2006 +0000 @@ -170,10 +170,8 @@ * * @param event The event. * - * @return The timestamp for the event. This is the number of - * seconds since 1/1/1970 (as returned by the time() - * system call). + * @return The timestamp for the event. */ -guint32 nm_event_get_gmt(NMEvent * event); +time_t nm_event_get_gmt(NMEvent * event); #endif diff -r 8855973b487b -r fcde3faa1f57 src/protocols/novell/novell.c --- a/src/protocols/novell/novell.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/novell/novell.c Sat Feb 04 20:55:52 2006 +0000 @@ -1903,7 +1903,7 @@ gmt = nm_event_get_gmt(event); title = _("Invitation to Conversation"); primary = g_strdup_printf(_("Invitation from: %s\n\nSent: %s"), - name, gaim_date_format_full(gmt)); + name, gaim_date_format_full(localtime(&gmt))); secondary = _("Would you like to join the conversation?"); /* Set up parms list for the callbacks diff -r 8855973b487b -r fcde3faa1f57 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/oscar/oscar.c Sat Feb 04 20:55:52 2006 +0000 @@ -5166,12 +5166,12 @@ if (userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) { time_t t = userinfo->onlinesince - od->timeoffset; - oscar_string_append(gc->account, str, "\n
", _("Online Since"), gaim_date_format_full(t)); + oscar_string_append(gc->account, str, "\n
", _("Online Since"), gaim_date_format_full(localtime(&t))); } if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) { time_t t = userinfo->membersince - od->timeoffset; - oscar_string_append(gc->account, str, "\n
", _("Member Since"), gaim_date_format_full(t)); + oscar_string_append(gc->account, str, "\n
", _("Member Since"), gaim_date_format_full(localtime(&t))); } if (userinfo->capabilities != 0) { diff -r 8855973b487b -r fcde3faa1f57 src/protocols/yahoo/yahoo_profile.c --- a/src/protocols/yahoo/yahoo_profile.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/protocols/yahoo/yahoo_profile.c Sat Feb 04 20:55:52 2006 +0000 @@ -650,7 +650,7 @@ static char *yahoo_info_date_reformat(const char *field, size_t len) { char *tmp = g_strndup(field, len); - time_t t = gaim_str_to_time(tmp, FALSE); + time_t t = gaim_str_to_time(tmp, FALSE, NULL, NULL, NULL); g_free(tmp); return g_strdup(gaim_date_format_short(localtime(&t))); diff -r 8855973b487b -r fcde3faa1f57 src/util.c --- a/src/util.c Sat Feb 04 05:17:46 2006 +0000 +++ b/src/util.c Sat Feb 04 20:55:52 2006 +0000 @@ -490,6 +490,14 @@ static char buf[128]; char *utf8; + g_return_val_if_fail(format != NULL, NULL); + + if (tm == NULL) + { + time_t now = time(NULL); + tm = localtime(&now); + } + /* A return value of 0 is either an error (in * which case, the contents of the buffer are * undefined) or the empty string (in which @@ -522,9 +530,9 @@ } const char * -gaim_date_format_full(time_t time) +gaim_date_format_full(const struct tm *tm) { - return gaim_utf8_strftime("%c", localtime(&time)); + return gaim_utf8_strftime("%c", tm); } const char * @@ -549,21 +557,18 @@ } time_t -gaim_str_to_time(const char *timestamp, gboolean utc) +gaim_str_to_time(const char *timestamp, gboolean utc, + struct tm *tm, long *tz_off, const char **rest) { time_t retval = 0; struct tm *t; - char buf[32]; - char *c; + const char *c = timestamp; int year = 0; - int tzoff = 0; + long tzoff = GAIM_NO_TZ_OFF; time(&retval); t = localtime(&retval); - snprintf(buf, sizeof(buf), "%s", timestamp); - c = buf; - /* 4 digit year */ if (sscanf(c, "%04d", &year) && year > 1900) { @@ -575,7 +580,11 @@ /* 2 digit month */ if (!sscanf(c, "%02d", &t->tm_mon)) + { + if (rest != NULL && *c != '\0') + *rest = c; return 0; + } c += 2; if (*c == '-' || *c == '/') c++; @@ -583,46 +592,83 @@ /* 2 digit day */ if (!sscanf(c, "%02d", &t->tm_mday)) + { + if (rest != NULL && *c != '\0') + *rest = c; return 0; + } c += 2; if (*c == '/') { c++; if (!sscanf(c, "%04d", &t->tm_year)) - return 0; + { + if (rest != NULL && *c != '\0') + *rest = c; + return 0; + } t->tm_year -= 1900; } - else if (*c == 'T' || *c == '.') { /* we have more than a date, keep going */ - c++; /* skip the "T" */ + else if (*c == 'T' || *c == '.') + { + c++; + /* we have more than a date, keep going */ /* 2 digit hour */ - if (sscanf(c, "%02d:%02d:%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3 || - sscanf(c, "%02d%02d%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3) { - int tzhrs, tzmins; - c += 8; - if (*c == '.') /* dealing with precision we don't care about */ - c += 4; - if ((*c == '+' || *c == '-') && - sscanf(c+1, "%02d:%02d", &tzhrs, &tzmins)) { - tzoff = tzhrs*60*60 + tzmins*60; - if (*c == '+') - tzoff *= -1; - } + if ((sscanf(c, "%02d:%02d:%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3 && (c = c + 8)) || + (sscanf(c, "%02d%02d%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3 && (c = c + 6))) + { + gboolean offset_positive = FALSE; + int tzhrs; + int tzmins; t->tm_isdst = -1; - if (tzoff || utc) { + if (*c == '.' && *(c+1) >= '0' && *(c+1) <= '9') /* dealing with precision we don't care about */ + c += 4; + if (*c == '+') + offset_positive = TRUE; + if (((*c == '+' || *c == '-') && (c = c + 1)) && + ((sscanf(c, "%02d:%02d", &tzhrs, &tzmins) == 2 && (c = c + 5)) || + (sscanf(c, "%02d%02d", &tzhrs, &tzmins) == 2 && (c = c + 4)))) + { + tzoff = tzhrs*60*60 + tzmins*60; + if (offset_positive) + tzoff *= -1; + /* We don't want the C library doing DST calculations + * if we know the UTC offset already. */ + t->tm_isdst = 0; + } + + if (rest != NULL && *c != '\0') + { + if (*c == ' ') + c++; + if (*c != '\0') + *rest = c; + } + + if (tzoff != GAIM_NO_TZ_OFF || utc) + { +#if defined(_WIN32) || defined(HAVE_TM_GMTOFF) || defined (HAVE_TIMEZONE) + if (tzoff == GAIM_NO_TZ_OFF) + tzoff = 0; +#endif + #ifdef _WIN32 TIME_ZONE_INFORMATION tzi; DWORD ret; - if ((ret = GetTimeZoneInformation(&tzi)) - != TIME_ZONE_ID_INVALID) { + if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID) + { tzoff -= tzi.Bias * 60; - if (ret == TIME_ZONE_ID_DAYLIGHT) { + if (ret == TIME_ZONE_ID_DAYLIGHT) + { tzoff -= tzi.DaylightBias * 60; } } + else + tzoff = GAIM_NO_TZ_OFF; #else #ifdef HAVE_TM_GMTOFF tzoff += t->tm_gmtoff; @@ -630,21 +676,35 @@ # ifdef HAVE_TIMEZONE tzset(); /* making sure */ tzoff -= timezone; - t->tm_isdst = 0; /* I think this might fix it */ # endif #endif #endif /* _WIN32 */ } } + else + { + if (*rest != NULL && *c != '\0') + *rest = c; + } + } + + if (tm != NULL) + { + *tm = *t; + tm->tm_isdst = -1; + mktime(tm); } retval = mktime(t); - retval += tzoff; + if (tzoff != GAIM_NO_TZ_OFF) + retval += tzoff; + + if (tz_off != NULL) + *tz_off = tzoff; return retval; } - /************************************************************************** * Markup Functions **************************************************************************/ diff -r 8855973b487b -r fcde3faa1f57 src/util.h --- a/src/util.h Sat Feb 04 05:17:46 2006 +0000 +++ b/src/util.h Sat Feb 04 20:55:52 2006 +0000 @@ -215,6 +215,11 @@ * * This is essentially strftime(), but it has a static buffer * and handles the UTF-8 conversion for the caller. + * + * @param format The format string + * @param tm The time to format, or @c NULL to use the current local time + * + * @return The formatted time, in UTF-8. */ const char *gaim_utf8_strftime(const char *format, const struct tm *tm); @@ -224,7 +229,7 @@ * The returned string is stored in a static buffer, so the result * should be g_strdup()'d if it's going to be kept. * - * @param time The time value to format (in local time). + * @param time The time to format, or @c NULL to use the current local time * * @return The date, formatted as per the user's settings. */ @@ -236,7 +241,7 @@ * The returned string is stored in a static buffer, so the result * should be g_strdup()'d if it's going to be kept. * - * @param time The time value to format (in local time). + * @param time The time to format, or @c NULL to use the current local time * * @return The timestamp, formatted as per the user's settings. */ @@ -248,11 +253,11 @@ * The returned string is stored in a static buffer, so the result * should be g_strdup()'d if it's going to be kept. * - * @param time The time value to format (in local time). + * @param time The time to format, or @c NULL to use the current local time * * @return The date and time, formatted as per the user's settings. */ -const char *gaim_date_format_full(time_t time); +const char *gaim_date_format_full(const struct tm *tm); /** * Formats a time into the user's preferred time format. @@ -260,7 +265,8 @@ * The returned string is stored in a static buffer, so the result * should be g_strdup()'d if it's going to be kept. * - * @param time The time value to format (in local time). + * @param time The time value to format. + * @param time The time to format, or @c NULL to use the current local time * * @return The time, formatted as per the user's settings. */ @@ -281,16 +287,32 @@ time_t gaim_time_build(int year, int month, int day, int hour, int min, int sec); +/** Used by gaim_str_to_time to indicate no timezone offset was + * specified in the timestamp string. */ +#define GAIM_NO_TZ_OFF -500000 + /** * Parses a timestamp in jabber, ISO8601, or MM/DD/YYYY format and returns * a time_t. * * @param timestamp The timestamp - * @param utc Assume UTC if no timezone specified + * @param utc Assume UTC if no timezone specified + * @param tm If not @c NULL, the caller can get a copy of the + * struct tm used to calculate the time_t return value. + * @param tz_off If not @c NULL, the caller can get a copy of the + * timezone offset (from UTC) used to calculate the time_t + * return value. Note: Zero is a valid offset. As such, + * the value of the macro @c GAIM_NO_TZ_OFF indicates no + * offset was specified (which means that the local + * timezone was used in the calculation). + * @param rest If not @c NULL, the caller can get a pointer to the + * part of @a timestamp left over after parsing is + * completed, if it's not the end of @a timestamp. * * @return A time_t. */ -time_t gaim_str_to_time(const char *timestamp, gboolean utc); +time_t gaim_str_to_time(const char *timestamp, gboolean utc, + struct tm *tm, long *tz_off, const char **rest); /*@}*/