| 83 |
83 |
| 84 const char * |
84 const char * |
| 85 purple_date_format_full(const struct tm *tm) |
85 purple_date_format_full(const struct tm *tm) |
| 86 { |
86 { |
| 87 return purple_utf8_strftime("%c", tm); |
87 return purple_utf8_strftime("%c", tm); |
| 88 } |
|
| 89 |
|
| 90 /* originally taken from GLib trunk 1-6-11 */ |
|
| 91 /* originally licensed as LGPL 2+ */ |
|
| 92 static time_t |
|
| 93 mktime_utc(struct tm *tm) |
|
| 94 { |
|
| 95 time_t retval; |
|
| 96 |
|
| 97 #ifndef HAVE_TIMEGM |
|
| 98 static const gint days_before[] = |
|
| 99 { |
|
| 100 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 |
|
| 101 }; |
|
| 102 #endif |
|
| 103 |
|
| 104 #ifndef HAVE_TIMEGM |
|
| 105 if (tm->tm_mon < 0 || tm->tm_mon > 11) |
|
| 106 return (time_t) -1; |
|
| 107 |
|
| 108 retval = (tm->tm_year - 70) * 365; |
|
| 109 retval += (tm->tm_year - 68) / 4; |
|
| 110 retval += days_before[tm->tm_mon] + tm->tm_mday - 1; |
|
| 111 |
|
| 112 if (tm->tm_year % 4 == 0 && tm->tm_mon < 2) |
|
| 113 retval -= 1; |
|
| 114 |
|
| 115 retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec; |
|
| 116 #else |
|
| 117 retval = timegm (tm); |
|
| 118 #endif /* !HAVE_TIMEGM */ |
|
| 119 |
|
| 120 return retval; |
|
| 121 } |
|
| 122 |
|
| 123 time_t |
|
| 124 purple_str_to_time(const char *timestamp, gboolean utc, |
|
| 125 struct tm *tm, long *tz_off, const char **rest) |
|
| 126 { |
|
| 127 struct tm t; |
|
| 128 const gchar *str; |
|
| 129 gint year = 0; |
|
| 130 long tzoff = PURPLE_NO_TZ_OFF; |
|
| 131 time_t retval; |
|
| 132 gboolean mktime_with_utc = FALSE; |
|
| 133 |
|
| 134 if (rest != NULL) |
|
| 135 *rest = NULL; |
|
| 136 |
|
| 137 g_return_val_if_fail(timestamp != NULL, 0); |
|
| 138 |
|
| 139 memset(&t, 0, sizeof(struct tm)); |
|
| 140 |
|
| 141 str = timestamp; |
|
| 142 |
|
| 143 /* Strip leading whitespace */ |
|
| 144 while (g_ascii_isspace(*str)) |
|
| 145 str++; |
|
| 146 |
|
| 147 if (*str == '\0') { |
|
| 148 if (rest != NULL) { |
|
| 149 *rest = str; |
|
| 150 } |
|
| 151 |
|
| 152 return 0; |
|
| 153 } |
|
| 154 |
|
| 155 if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') { |
|
| 156 if (rest != NULL && *str != '\0') |
|
| 157 *rest = str; |
|
| 158 |
|
| 159 return 0; |
|
| 160 } |
|
| 161 |
|
| 162 /* 4 digit year */ |
|
| 163 if (sscanf(str, "%04d", &year) && year >= 1900) { |
|
| 164 str += 4; |
|
| 165 |
|
| 166 if (*str == '-' || *str == '/') |
|
| 167 str++; |
|
| 168 |
|
| 169 t.tm_year = year - 1900; |
|
| 170 } |
|
| 171 |
|
| 172 /* 2 digit month */ |
|
| 173 if (!sscanf(str, "%02d", &t.tm_mon)) { |
|
| 174 if (rest != NULL && *str != '\0') |
|
| 175 *rest = str; |
|
| 176 |
|
| 177 return 0; |
|
| 178 } |
|
| 179 |
|
| 180 str += 2; |
|
| 181 t.tm_mon -= 1; |
|
| 182 |
|
| 183 if (*str == '-' || *str == '/') |
|
| 184 str++; |
|
| 185 |
|
| 186 /* 2 digit day */ |
|
| 187 if (!sscanf(str, "%02d", &t.tm_mday)) { |
|
| 188 if (rest != NULL && *str != '\0') |
|
| 189 *rest = str; |
|
| 190 |
|
| 191 return 0; |
|
| 192 } |
|
| 193 |
|
| 194 str += 2; |
|
| 195 |
|
| 196 /* Grab the year off the end if there's still stuff */ |
|
| 197 if (*str == '/' || *str == '-') { |
|
| 198 /* But make sure we don't read the year twice */ |
|
| 199 if (year >= 1900) { |
|
| 200 if (rest != NULL && *str != '\0') |
|
| 201 *rest = str; |
|
| 202 |
|
| 203 return 0; |
|
| 204 } |
|
| 205 |
|
| 206 str++; |
|
| 207 |
|
| 208 if (!sscanf(str, "%04d", &t.tm_year)) { |
|
| 209 if (rest != NULL && *str != '\0') |
|
| 210 *rest = str; |
|
| 211 |
|
| 212 return 0; |
|
| 213 } |
|
| 214 |
|
| 215 t.tm_year -= 1900; |
|
| 216 } else if (*str == 'T' || *str == '.') { |
|
| 217 str++; |
|
| 218 |
|
| 219 /* Continue grabbing the hours/minutes/seconds */ |
|
| 220 if ((sscanf(str, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && |
|
| 221 (str += 8)) || |
|
| 222 (sscanf(str, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && |
|
| 223 (str += 6))) |
|
| 224 { |
|
| 225 gint sign, tzhrs, tzmins; |
|
| 226 |
|
| 227 if (*str == '.') { |
|
| 228 /* Cut off those pesky micro-seconds */ |
|
| 229 do { |
|
| 230 str++; |
|
| 231 } while (*str >= '0' && *str <= '9'); |
|
| 232 } |
|
| 233 |
|
| 234 sign = (*str == '+') ? 1 : -1; |
|
| 235 |
|
| 236 /* Process the timezone */ |
|
| 237 if (*str == '+' || *str == '-') { |
|
| 238 str++; |
|
| 239 |
|
| 240 if (((sscanf(str, "%02d:%02d", &tzhrs, &tzmins) == 2 && (str += 5)) || |
|
| 241 (sscanf(str, "%02d%02d", &tzhrs, &tzmins) == 2 && (str += 4)))) |
|
| 242 { |
|
| 243 mktime_with_utc = TRUE; |
|
| 244 tzoff = tzhrs * 60 * 60 + tzmins * 60; |
|
| 245 tzoff *= sign; |
|
| 246 } |
|
| 247 } else if (*str == 'Z') { |
|
| 248 /* 'Z' = Zulu = UTC */ |
|
| 249 str++; |
|
| 250 mktime_with_utc = TRUE; |
|
| 251 tzoff = 0; |
|
| 252 } |
|
| 253 |
|
| 254 if (!mktime_with_utc) |
|
| 255 { |
|
| 256 /* No timezone specified. */ |
|
| 257 |
|
| 258 if (utc) { |
|
| 259 mktime_with_utc = TRUE; |
|
| 260 tzoff = 0; |
|
| 261 } else { |
|
| 262 /* Local Time */ |
|
| 263 t.tm_isdst = -1; |
|
| 264 } |
|
| 265 } |
|
| 266 } |
|
| 267 } |
|
| 268 |
|
| 269 if (rest != NULL && *str != '\0') { |
|
| 270 /* Strip trailing whitespace */ |
|
| 271 while (g_ascii_isspace(*str)) |
|
| 272 str++; |
|
| 273 |
|
| 274 if (*str != '\0') |
|
| 275 *rest = str; |
|
| 276 } |
|
| 277 |
|
| 278 if (mktime_with_utc) |
|
| 279 retval = mktime_utc(&t); |
|
| 280 else |
|
| 281 retval = mktime(&t); |
|
| 282 |
|
| 283 if (tm != NULL) |
|
| 284 *tm = t; |
|
| 285 |
|
| 286 if (tzoff != PURPLE_NO_TZ_OFF) |
|
| 287 retval -= tzoff; |
|
| 288 |
|
| 289 if (tz_off != NULL) |
|
| 290 *tz_off = tzoff; |
|
| 291 |
|
| 292 return retval; |
|
| 293 } |
|
| 294 |
|
| 295 GDateTime * |
|
| 296 purple_str_to_date_time(const char *timestamp, gboolean utc) |
|
| 297 { |
|
| 298 const gchar *str; |
|
| 299 gint year = 0; |
|
| 300 gint month = 0; |
|
| 301 gint day = 0; |
|
| 302 gint hour = 0; |
|
| 303 gint minute = 0; |
|
| 304 gint seconds = 0; |
|
| 305 gint microseconds = 0; |
|
| 306 int chars = 0; |
|
| 307 GTimeZone *tz = NULL; |
|
| 308 GDateTime *retval; |
|
| 309 |
|
| 310 g_return_val_if_fail(timestamp != NULL, NULL); |
|
| 311 |
|
| 312 str = timestamp; |
|
| 313 |
|
| 314 /* Strip leading whitespace */ |
|
| 315 while (g_ascii_isspace(*str)) |
|
| 316 str++; |
|
| 317 |
|
| 318 if (*str == '\0') { |
|
| 319 return NULL; |
|
| 320 } |
|
| 321 |
|
| 322 if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') { |
|
| 323 return NULL; |
|
| 324 } |
|
| 325 |
|
| 326 /* 4 digit year */ |
|
| 327 if (sscanf(str, "%04d", &year) && year > 0) { |
|
| 328 str += 4; |
|
| 329 |
|
| 330 if (*str == '-' || *str == '/') |
|
| 331 str++; |
|
| 332 } |
|
| 333 |
|
| 334 /* 2 digit month */ |
|
| 335 if (!sscanf(str, "%02d", &month)) { |
|
| 336 return NULL; |
|
| 337 } |
|
| 338 |
|
| 339 str += 2; |
|
| 340 |
|
| 341 if (*str == '-' || *str == '/') |
|
| 342 str++; |
|
| 343 |
|
| 344 /* 2 digit day */ |
|
| 345 if (!sscanf(str, "%02d", &day)) { |
|
| 346 return NULL; |
|
| 347 } |
|
| 348 |
|
| 349 str += 2; |
|
| 350 |
|
| 351 /* Grab the year off the end if there's still stuff */ |
|
| 352 if (*str == '/' || *str == '-') { |
|
| 353 /* But make sure we don't read the year twice */ |
|
| 354 if (year > 0) { |
|
| 355 return NULL; |
|
| 356 } |
|
| 357 |
|
| 358 str++; |
|
| 359 |
|
| 360 if (!sscanf(str, "%04d", &year)) { |
|
| 361 return NULL; |
|
| 362 } |
|
| 363 } else if (*str == 'T' || *str == '.') { |
|
| 364 str++; |
|
| 365 |
|
| 366 /* Continue grabbing the hours/minutes/seconds */ |
|
| 367 if ((sscanf(str, "%02d:%02d:%02d", &hour, &minute, &seconds) == 3 && |
|
| 368 (str += 8)) || |
|
| 369 (sscanf(str, "%02d%02d%02d", &hour, &minute, &seconds) == 3 && |
|
| 370 (str += 6))) |
|
| 371 { |
|
| 372 if (*str == '.') { |
|
| 373 str++; |
|
| 374 if (sscanf(str, "%d%n", µseconds, &chars) == 1) { |
|
| 375 str += chars; |
|
| 376 } |
|
| 377 } |
|
| 378 |
|
| 379 if (*str) { |
|
| 380 const gchar *end = str; |
|
| 381 if (*end == '+' || *end == '-') { |
|
| 382 end++; |
|
| 383 } |
|
| 384 |
|
| 385 while (isdigit(*end) || *end == ':') { |
|
| 386 end++; |
|
| 387 } |
|
| 388 |
|
| 389 if (str != end) { |
|
| 390 /* Trim anything trailing a purely numeric time zone. */ |
|
| 391 gchar *tzstr = g_strndup(str, end - str); |
|
| 392 tz = g_time_zone_new_identifier(tzstr); |
|
| 393 g_free(tzstr); |
|
| 394 if (tz == NULL) { |
|
| 395 tz = g_time_zone_new_identifier("UTC"); |
|
| 396 } |
|
| 397 } else { |
|
| 398 /* Just try whatever is there. */ |
|
| 399 tz = g_time_zone_new_identifier(str); |
|
| 400 if (tz == NULL) { |
|
| 401 tz = g_time_zone_new_identifier("UTC"); |
|
| 402 } |
|
| 403 } |
|
| 404 } |
|
| 405 } |
|
| 406 } |
|
| 407 |
|
| 408 if (!tz) { |
|
| 409 /* No timezone specified. */ |
|
| 410 if (utc) { |
|
| 411 tz = g_time_zone_new_utc(); |
|
| 412 } else { |
|
| 413 tz = g_time_zone_new_local(); |
|
| 414 } |
|
| 415 } |
|
| 416 |
|
| 417 retval = g_date_time_new(tz, year, month, day, hour, minute, |
|
| 418 seconds + microseconds * pow(10, -chars)); |
|
| 419 g_time_zone_unref(tz); |
|
| 420 |
|
| 421 return retval; |
|
| 422 } |
|
| 423 |
|
| 424 gint purple_time_parse_month(const char *month_abbr) |
|
| 425 { |
|
| 426 const char *months[] = { |
|
| 427 "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
|
| 428 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", |
|
| 429 NULL}; |
|
| 430 for (gint month = 0; months[month] != NULL; month++) { |
|
| 431 if (purple_strequal(month_abbr, months[month])) { |
|
| 432 return month + 1; |
|
| 433 } |
|
| 434 } |
|
| 435 return 0; |
|
| 436 } |
88 } |
| 437 |
89 |
| 438 /************************************************************************** |
90 /************************************************************************** |
| 439 * Path/Filename Functions |
91 * Path/Filename Functions |
| 440 **************************************************************************/ |
92 **************************************************************************/ |