diff options
-rw-r--r-- | e-util/ChangeLog | 11 | ||||
-rw-r--r-- | e-util/e-time-utils.c | 313 |
2 files changed, 183 insertions, 141 deletions
diff --git a/e-util/ChangeLog b/e-util/ChangeLog index c4b8864f9d..1cdde3e591 100644 --- a/e-util/ChangeLog +++ b/e-util/ChangeLog @@ -1,3 +1,14 @@ +2001-09-17 Damon Chaplin <damon@ximian.com> + + * e-time-utils.c (e_time_parse_date): only use 1 format, so we are + consistent everywhere. If we support multiple formats we have to + support that in e_time_parse_date_and_time() which means an explosion + of different formats. I don't think the alternatives are that useful, + anyway. + (e_time_parse_date_and_time): parse everything in one go, to avoid + i18n problems. Also only use '%p' if the locale has am/pm strings. + (e_time_parse_time): Only use '%p' if locale has am/pm strings. + 2001-09-17 Ettore Perazzoli <ettore@ximian.com> * e-gtk-utils.c (gtk_radio_button_get_nth_selected): Removed. diff --git a/e-util/e-time-utils.c b/e-util/e-time-utils.c index 59650a31d3..64392de6ca 100644 --- a/e-util/e-time-utils.c +++ b/e-util/e-time-utils.c @@ -47,6 +47,68 @@ string_is_empty (const char *value) } +/* Takes a number of format strings for strptime() and attempts to parse a + * string with them. + */ +static ETimeParseStatus +parse_with_strptime (const char *value, struct tm *result, const char **formats, int n_formats) +{ + const char *parse_end = NULL, *pos; + gboolean parsed = FALSE; + int i; + + if (string_is_empty (value)) { + memset (result, 0, sizeof (*result)); + result->tm_isdst = -1; + return E_TIME_PARSE_NONE; + } + + pos = value; + + /* Skip whitespace */ + while (isspace (*pos)) + pos++; + + /* Try each of the formats in turn */ + + for (i = 0; i < n_formats; i++) { + memset (result, 0, sizeof (*result)); + parse_end = strptime (pos, formats[i], result); + if (parse_end) { + parsed = TRUE; + break; + } + } + + result->tm_isdst = -1; + + /* If we parsed something, make sure we parsed the entire string. */ + if (parsed) { + /* Skip whitespace */ + while (isspace (*parse_end)) + parse_end++; + + if (*parse_end == '\0') + return E_TIME_PARSE_OK; + } + + return E_TIME_PARSE_INVALID; +} + + +/* Returns TRUE if the locale has 'am' and 'pm' strings defined, in which + case the user can choose between 12 and 24-hour time formats. */ +static gboolean +locale_supports_12_hour_format (void) +{ + struct tm tmp_tm = { 0 }; + char s[16]; + + strftime (s, sizeof (s), "%p", &tmp_tm); + return s[0] != '\0'; +} + + /* * Parses a string containing a date and a time. The date is expected to be * in a format something like "Wed 3/13/00 14:20:00", though we use gettext @@ -61,13 +123,12 @@ ETimeParseStatus e_time_parse_date_and_time (const char *value, struct tm *result) { - struct tm time_tm; struct tm *today_tm; time_t t; - const char *pos, *parse_end; - char *format[5]; - gboolean parsed_date = FALSE, parsed_time = FALSE; - gint i; + const char *format[16]; + int num_formats = 0; + gboolean use_12_hour_formats = locale_supports_12_hour_format (); + ETimeParseStatus status; if (string_is_empty (value)) { memset (result, 0, sizeof (*result)); @@ -75,71 +136,95 @@ e_time_parse_date_and_time (const char *value, return E_TIME_PARSE_NONE; } - pos = value; + /* We'll parse the whole date and time in one go, otherwise we get + into i18n problems. We attempt to parse with several formats, + longest first. Note that we only use the '%p' specifier if the + locale actually has 'am' and 'pm' strings defined, otherwise we + will get incorrect results. Note also that we try to use exactly + the same strings as in e_time_format_date_and_time(), to try to + avoid i18n problems. We also use cut-down versions, so users don't + have to type in the weekday or the seconds, for example. + Note that all these formats include the full date, and the time + will be set to 00:00:00 before parsing, so we don't need to worry + about filling in any missing fields after parsing. */ + + /* + * Try the full times, with the weekday. Then try without seconds, + * and without minutes, and finally with no time at all. + */ + if (use_12_hour_formats) { + /* strptime format of a weekday, a date and a time, + in 12-hour format. */ + format[num_formats++] = _("%a %m/%d/%Y %I:%M:%S %p"); + } - /* Skip everything up to the first digit. */ - while (!isdigit (*pos)) - pos++; + /* strptime format of a weekday, a date and a time, + in 24-hour format. */ + format[num_formats++] = _("%a %m/%d/%Y %H:%M:%S"); - memset (result, 0, sizeof (*result)); - /* strptime format for a date. */ - parse_end = strptime (pos, _("%m/%d/%Y"), result); - if (parse_end) { - pos = parse_end; - parsed_date = TRUE; + if (use_12_hour_formats) { + /* strptime format of a weekday, a date and a time, + in 12-hour format, without seconds. */ + format[num_formats++] = _("%a %m/%d/%Y %I:%M %p"); } - /* FIXME: Skip everything up to the first digit. I hope the am/pm flag - never gets entered first - it does in Japanese, so fix this. */ - while (!isdigit (*pos)) - pos++; + /* strptime format of a weekday, a date and a time, + in 24-hour format, without seconds. */ + format[num_formats++] = _("%a %m/%d/%Y %H:%M"); + if (use_12_hour_formats) { + /* strptime format of a weekday, a date and a time, + in 12-hour format, without minutes or seconds. */ + format[num_formats++] = _("%a %m/%d/%Y %I %p"); + } - /* strptime format for a time of day, in 12-hour format. */ - format[0] = _("%I:%M:%S %p"); + /* strptime format of a weekday, a date and a time, + in 24-hour format, without minutes or seconds. */ + format[num_formats++] = _("%a %m/%d/%Y %H"); - /* strptime format for a time of day, in 24-hour format. */ - format[1] = _("%H:%M:%S"); + /* strptime format of a weekday and a date. */ + format[num_formats++] = _("%a %m/%d/%Y"); - /* strptime format for time of day, without seconds, 12-hour format. */ - format[2] = _("%I:%M %p"); - /* strptime format for hour and AM/PM */ - format[3] = _("%I %p"); + /* + * Now try all the above formats again, but without the weekday. + */ + if (use_12_hour_formats) { + /* strptime format of a date and a time, in 12-hour format. */ + format[num_formats++] = _("%m/%d/%Y %I:%M:%S %p"); + } - /* strptime format for time of day, without seconds 24-hour format. */ - format[4] = _("%H:%M"); + /* strptime format of a date and a time, in 24-hour format. */ + format[num_formats++] = _("%m/%d/%Y %H:%M:%S"); - for (i = 0; i < sizeof (format) / sizeof (format[0]); i++) { - memset (&time_tm, 0, sizeof (time_tm)); - parse_end = strptime (pos, format[i], &time_tm); - if (parse_end) { - pos = parse_end; - parsed_time = TRUE; - break; - } + if (use_12_hour_formats) { + /* strptime format of a date and a time, in 12-hour format, + without seconds. */ + format[num_formats++] = _("%m/%d/%Y %I:%M %p"); } - /* Skip any whitespace. */ - while (isspace (*pos)) - pos++; + /* strptime format of a date and a time, in 24-hour format, + without seconds. */ + format[num_formats++] = _("%m/%d/%Y %H:%M"); - /* If we haven't already parsed a date, try again. */ - if (!parsed_date) { - memset (result, 0, sizeof (*result)); - /* strptime format for a date. */ - parse_end = strptime (pos, _("%m/%d/%Y"), result); - if (parse_end) { - pos = parse_end; - parsed_date = TRUE; - } + if (use_12_hour_formats) { + /* strptime format of a date and a time, in 12-hour format, + without minutes or seconds. */ + format[num_formats++] = _("%m/%d/%Y %I %p"); } - /* If we don't have a date or a time it must be invalid. */ - if (!parsed_date && !parsed_time) - return E_TIME_PARSE_INVALID; + /* strptime format of a date and a time, in 24-hour format, + without minutes or seconds. */ + format[num_formats++] = _("%m/%d/%Y %H"); + + /* strptime format of a weekday and a date. */ + format[num_formats++] = _("%m/%d/%Y"); + - if (parsed_date) { + status = parse_with_strptime (value, result, format, num_formats); + /* Note that we checked if it was empty already, so it is either OK + or INVALID here. */ + if (status == E_TIME_PARSE_OK) { /* If a 2-digit year was used we use the current century. */ if (result->tm_year < 0) { t = time (NULL); @@ -153,73 +238,21 @@ e_time_parse_date_and_time (const char *value, - (today_tm->tm_year % 100); } } else { - /* If we didn't get a date we use the current day. */ - t = time (NULL); - today_tm = localtime (&t); - result->tm_mday = today_tm->tm_mday; - result->tm_mon = today_tm->tm_mon; - result->tm_year = today_tm->tm_year; - } - - if (parsed_time) { - result->tm_hour = time_tm.tm_hour; - result->tm_min = time_tm.tm_min; - result->tm_sec = time_tm.tm_sec; - } else { - result->tm_hour = 0; - result->tm_min = 0; - result->tm_sec = 0; - } - - result->tm_isdst = -1; - - return E_TIME_PARSE_OK; -} - -/* Takes a number of format strings for strptime() and attempts to parse a - * string with them. - */ -static ETimeParseStatus -parse_with_strptime (const char *value, struct tm *result, const char **formats, int n_formats) -{ - const char *pos, *parse_end; - gboolean parsed; - int i; - - if (string_is_empty (value)) { - memset (result, 0, sizeof (*result)); - result->tm_isdst = -1; - return E_TIME_PARSE_NONE; - } - - pos = value; - - /* Skip whitespace */ - while (isspace (*pos)) - pos++; - - /* Try each of the formats in turn */ - - for (i = 0; i < n_formats; i++) { - memset (result, 0, sizeof (*result)); - parse_end = strptime (pos, formats[i], result); - if (parse_end) { - pos = parse_end; - parsed = TRUE; - break; + /* Now we try to just parse a time, assuming the current day.*/ + status = e_time_parse_time (value, result); + if (status == E_TIME_PARSE_OK) { + /* We fill in the current day. */ + t = time (NULL); + today_tm = localtime (&t); + result->tm_mday = today_tm->tm_mday; + result->tm_mon = today_tm->tm_mon; + result->tm_year = today_tm->tm_year; } } - result->tm_isdst = -1; - - /* If we could not parse it it must be invalid. */ - if (!parsed) - return E_TIME_PARSE_INVALID; - - return E_TIME_PARSE_OK; + return status; } - /** * e_time_parse_date: * @value: A date string. @@ -234,7 +267,7 @@ parse_with_strptime (const char *value, struct tm *result, const char **formats, ETimeParseStatus e_time_parse_date (const char *value, struct tm *result) { - const char *format[4]; + const char *format[1]; g_return_val_if_fail (value != NULL, E_TIME_PARSE_INVALID); g_return_val_if_fail (result != NULL, E_TIME_PARSE_INVALID); @@ -242,18 +275,6 @@ e_time_parse_date (const char *value, struct tm *result) /* This is the preferred date format for the locale. */ format[0] = _("%m/%d/%Y"); - /* This is the second-choice date format for the locale, which we use - if previous attempts to parse the date string failed. */ - format[1] = _("%d/%m/%Y"); - - /* This is the third-choice date format for the locale, which we use - if previous attempts to parse the date string failed. */ - format[2] = _("%Y/%m/%d"); - - /* This is the final-choice date format for the locale, which we use - if previous attempts to parse the date string failed. */ - format[3] = _("%x"); /* catch-all give-up strptime()-sucks format */ - return parse_with_strptime (value, result, format, sizeof (format) / sizeof (format[0])); } @@ -270,26 +291,36 @@ e_time_parse_date (const char *value, struct tm *result) ETimeParseStatus e_time_parse_time (const char *value, struct tm *result) { - const char *format[5]; + const char *format[6]; + int num_formats = 0; + gboolean use_12_hour_formats = locale_supports_12_hour_format (); - /* strptime format for a time of day, in 12-hour format. - If it is not appropriate in the locale set to an empty string. */ - format[0] = _("%I:%M:%S %p"); + if (use_12_hour_formats) { + /* strptime format for a time of day, in 12-hour format. */ + format[num_formats++] = _("%I:%M:%S %p"); + } /* strptime format for a time of day, in 24-hour format. */ - format[1] = _("%H:%M:%S"); - - /* strptime format for time of day, without seconds, 12-hour format. - If it is is not appropriate in the locale set to an empty string. */ - format[2] = _("%I:%M %p"); + format[num_formats++] = _("%H:%M:%S"); - /* strptime format for hour and AM/PM */ - format[3] = _("%I %p"); + if (use_12_hour_formats) { + /* strptime format for time of day, without seconds, + in 12-hour format. */ + format[num_formats++] = _("%I:%M %p"); + } /* strptime format for time of day, without seconds 24-hour format. */ - format[4] = _("%H:%M"); + format[num_formats++] = _("%H:%M"); - return parse_with_strptime (value, result, format, sizeof (format) / sizeof (format[0])); + if (use_12_hour_formats) { + /* strptime format for hour and AM/PM, 12-hour format. */ + format[num_formats++] = _("%I %p"); + } + + /* strptime format for hour, 24-hour format. */ + format[num_formats++] = "%H"; + + return parse_with_strptime (value, result, format, num_formats); } |