aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--e-util/ChangeLog11
-rw-r--r--e-util/e-time-utils.c313
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);
}