X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgdatetime.c;h=cbbf620088f9a70a1696a057e1496d43e33f75f0;hb=ecf1359191b2f796a7d63288652dd1a93525417d;hp=3a3557c924d583b684e8d1cbfd3fac456d15e456;hpb=1b033919845cef366842373da9f1cfb56f522d01;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gdatetime.c b/glib/gdatetime.c index 3a3557c..cbbf620 100644 --- a/glib/gdatetime.c +++ b/glib/gdatetime.c @@ -50,17 +50,16 @@ #include #include -#ifdef HAVE_UNISTD_H -#include -#endif - #ifdef HAVE_LANGINFO_TIME #include #endif #include "gdatetime.h" +#include "gslice.h" #include "gatomic.h" +#include "gcharset.h" +#include "gconvert.h" #include "gfileutils.h" #include "ghash.h" #include "gmain.h" @@ -80,7 +79,7 @@ /** * SECTION:date-time * @title: GDateTime - * @short_description: A structure representing Date and Time + * @short_description: a structure representing Date and Time * @see_also: #GTimeZone * * #GDateTime is a structure that combines a Gregorian date and time @@ -112,9 +111,6 @@ struct _GDateTime { - /* 1 is 0001-01-01 in Proleptic Gregorian */ - gint32 days; - /* Microsecond timekeeping within Day */ guint64 usec; @@ -122,6 +118,9 @@ struct _GDateTime GTimeZone *tz; gint interval; + /* 1 is 0001-01-01 in Proleptic Gregorian */ + gint32 days; + volatile gint ref_count; }; @@ -439,7 +438,7 @@ g_date_time_alloc (GTimeZone *tz) * * Atomically increments the reference count of @datetime by one. * - * Return value: the #GDateTime with the reference count increased + * Returns: the #GDateTime with the reference count increased * * Since: 2.26 */ @@ -945,6 +944,16 @@ g_date_time_new (GTimeZone *tz, GDateTime *datetime; gint64 full_time; + g_return_val_if_fail (tz != NULL, NULL); + + if (year < 1 || year > 9999 || + month < 1 || month > 12 || + day < 1 || day > 31 || + hour < 0 || hour > 23 || + minute < 0 || minute > 59 || + seconds < 0.0 || seconds >= 60.0) + return NULL; + datetime = g_date_time_alloc (tz); datetime->days = ymd_to_days (year, month, day); datetime->usec = (hour * USEC_PER_HOUR) @@ -986,7 +995,7 @@ g_date_time_new (GTimeZone *tz, * * Returns: a #GDateTime, or %NULL * - * Since: 2.26. + * Since: 2.26 **/ GDateTime * g_date_time_new_local (gint year, @@ -1023,7 +1032,7 @@ g_date_time_new_local (gint year, * * Returns: a #GDateTime, or %NULL * - * Since: 2.26. + * Since: 2.26 **/ GDateTime * g_date_time_new_utc (gint year, @@ -1052,7 +1061,7 @@ g_date_time_new_utc (gint year, * * Creates a copy of @datetime and adds the specified timespan to the copy. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1071,9 +1080,9 @@ g_date_time_add (GDateTime *datetime, * @years: the number of years * * Creates a copy of @datetime and adds the specified number of years to the - * copy. + * copy. Add negative values to subtract years. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1106,9 +1115,9 @@ g_date_time_add_years (GDateTime *datetime, * @months: the number of months * * Creates a copy of @datetime and adds the specified number of months to the - * copy. + * copy. Add negative values to subtract months. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1149,9 +1158,9 @@ g_date_time_add_months (GDateTime *datetime, * @weeks: the number of weeks * * Creates a copy of @datetime and adds the specified number of weeks to the - * copy. + * copy. Add negative values to subtract weeks. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1171,9 +1180,9 @@ g_date_time_add_weeks (GDateTime *datetime, * @days: the number of days * * Creates a copy of @datetime and adds the specified number of days to the - * copy. + * copy. Add negative values to subtract days. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1195,9 +1204,10 @@ g_date_time_add_days (GDateTime *datetime, * @datetime: a #GDateTime * @hours: the number of hours to add * - * Creates a copy of @datetime and adds the specified number of hours + * Creates a copy of @datetime and adds the specified number of hours. + * Add negative values to subtract hours. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1215,8 +1225,9 @@ g_date_time_add_hours (GDateTime *datetime, * @minutes: the number of minutes to add * * Creates a copy of @datetime adding the specified number of minutes. + * Add negative values to subtract minutes. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1235,8 +1246,9 @@ g_date_time_add_minutes (GDateTime *datetime, * @seconds: the number of seconds to add * * Creates a copy of @datetime and adds the specified number of seconds. + * Add negative values to subtract seconds. * - * Return value: the newly created #GDateTime which should be freed with + * Returns: the newly created #GDateTime which should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1259,9 +1271,9 @@ g_date_time_add_seconds (GDateTime *datetime, * @seconds: the number of seconds to add * * Creates a new #GDateTime adding the specified values to the current date and - * time in @datetime. + * time in @datetime. Add negative values to subtract. * - * Return value: the newly created #GDateTime that should be freed with + * Returns: the newly created #GDateTime that should be freed with * g_date_time_unref(). * * Since: 2.26 @@ -1357,7 +1369,7 @@ g_date_time_add_full (GDateTime *datetime, * A comparison function for #GDateTimes that is suitable * as a #GCompareFunc. Both #GDateTimes must be non-%NULL. * - * Return value: -1, 0 or 1 if @dt1 is less than, equal to or greater + * Returns: -1, 0 or 1 if @dt1 is less than, equal to or greater * than @dt2. * * Since: 2.26 @@ -1387,9 +1399,9 @@ g_date_time_compare (gconstpointer dt1, * * Calculates the difference in time between @end and @begin. The * #GTimeSpan that is returned is effectively @end - @begin (ie: - * positive if the first simparameter is larger). + * positive if the first parameter is larger). * - * Return value: the difference between the two #GDateTime, as a time + * Returns: the difference between the two #GDateTime, as a time * span expressed in microseconds. * * Since: 2.26 @@ -1411,7 +1423,7 @@ g_date_time_difference (GDateTime *end, * * Hashes @datetime into a #guint, suitable for use within #GHashTable. * - * Return value: a #guint containing the hash + * Returns: a #guint containing the hash * * Since: 2.26 */ @@ -1431,7 +1443,7 @@ g_date_time_hash (gconstpointer datetime) * Equal here means that they represent the same moment after converting * them to the same time zone. * - * Return value: %TRUE if @dt1 and @dt2 are equal + * Returns: %TRUE if @dt1 and @dt2 are equal * * Since: 2.26 */ @@ -1446,9 +1458,9 @@ g_date_time_equal (gconstpointer dt1, /** * g_date_time_get_ymd: * @datetime: a #GDateTime. - * @year: (out): the return location for the gregorian year, or %NULL. - * @month: (out): the return location for the month of the year, or %NULL. - * @day: (out): the return location for the day of the month, or %NULL. + * @year: (out) (allow-none): the return location for the gregorian year, or %NULL. + * @month: (out) (allow-none): the return location for the month of the year, or %NULL. + * @day: (out) (allow-none): the return location for the day of the month, or %NULL. * * Retrieves the Gregorian day, month, and year of a given #GDateTime. * @@ -1545,7 +1557,7 @@ end: * * Retrieves the year represented by @datetime in the Gregorian calendar. * - * Return value: the year represented by @datetime + * Returns: the year represented by @datetime * * Since: 2.26 */ @@ -1568,7 +1580,7 @@ g_date_time_get_year (GDateTime *datetime) * Retrieves the month of the year represented by @datetime in the Gregorian * calendar. * - * Return value: the month represented by @datetime + * Returns: the month represented by @datetime * * Since: 2.26 */ @@ -1591,7 +1603,7 @@ g_date_time_get_month (GDateTime *datetime) * Retrieves the day of the month represented by @datetime in the gregorian * calendar. * - * Return value: the day of the month + * Returns: the day of the month * * Since: 2.26 */ @@ -1739,7 +1751,7 @@ g_date_time_get_week_of_year (GDateTime *datetime) * Retrieves the ISO 8601 day of the week on which @datetime falls (1 is * Monday, 2 is Tuesday... 7 is Sunday). * - * Return value: the day of the week + * Returns: the day of the week * * Since: 2.26 */ @@ -1759,7 +1771,7 @@ g_date_time_get_day_of_week (GDateTime *datetime) * Retrieves the day of the year represented by @datetime in the Gregorian * calendar. * - * Return value: the day of the year + * Returns: the day of the year * * Since: 2.26 */ @@ -1782,7 +1794,7 @@ g_date_time_get_day_of_year (GDateTime *datetime) * * Retrieves the hour of the day represented by @datetime * - * Return value: the hour of the day + * Returns: the hour of the day * * Since: 2.26 */ @@ -1800,7 +1812,7 @@ g_date_time_get_hour (GDateTime *datetime) * * Retrieves the minute of the hour represented by @datetime * - * Return value: the minute of the hour + * Returns: the minute of the hour * * Since: 2.26 */ @@ -1818,7 +1830,7 @@ g_date_time_get_minute (GDateTime *datetime) * * Retrieves the second of the minute represented by @datetime * - * Return value: the second represented by @datetime + * Returns: the second represented by @datetime * * Since: 2.26 */ @@ -1836,7 +1848,7 @@ g_date_time_get_second (GDateTime *datetime) * * Retrieves the microsecond of the date represented by @datetime * - * Return value: the microsecond of the second + * Returns: the microsecond of the second * * Since: 2.26 */ @@ -2079,18 +2091,71 @@ g_date_time_to_utc (GDateTime *datetime) /* Format {{{1 */ +static gboolean +format_z (GString *outstr, + gint offset, + guint colons) +{ + gint hours; + gint minutes; + gint seconds; + + hours = offset / 3600; + minutes = ABS (offset) / 60 % 60; + seconds = ABS (offset) % 60; + + switch (colons) + { + case 0: + g_string_append_printf (outstr, "%+03d%02d", + hours, + minutes); + break; + + case 1: + g_string_append_printf (outstr, "%+03d:%02d", + hours, + minutes); + break; + + case 2: + g_string_append_printf (outstr, "%+03d:%02d:%02d", + hours, + minutes, + seconds); + break; + + case 3: + g_string_append_printf (outstr, "%+03d", hours); + + if (minutes != 0 || seconds != 0) + { + g_string_append_printf (outstr, ":%02d", minutes); + + if (seconds != 0) + g_string_append_printf (outstr, ":%02d", seconds); + } + break; + + default: + return FALSE; + } + + return TRUE; +} + static void format_number (GString *str, gboolean use_alt_digits, - gchar pad, + gchar *pad, gint width, guint32 number) { - const gunichar ascii_digits[10] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + const gchar *ascii_digits[10] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - const gunichar *digits = ascii_digits; - gunichar tmp[10]; + const gchar **digits = ascii_digits; + const gchar *tmp[10]; gint i = 0; g_return_if_fail (width <= 10); @@ -2098,18 +2163,14 @@ format_number (GString *str, #ifdef HAVE_LANGINFO_OUTDIGIT if (use_alt_digits) { - static gunichar alt_digits[10]; + static const gchar *alt_digits[10]; static gsize initialised; /* 2^32 has 10 digits */ if G_UNLIKELY (g_once_init_enter (&initialised)) { #define DO_DIGIT(n) \ - { \ - union { guint integer; char *pointer; } val; \ - val.pointer = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_WC); \ - alt_digits[n] = val.integer; \ - } + alt_digits[n] = nl_langinfo (_NL_CTYPE_OUTDIGIT## n ##_MB) DO_DIGIT(0); DO_DIGIT(1); DO_DIGIT(2); DO_DIGIT(3); DO_DIGIT(4); DO_DIGIT(5); DO_DIGIT(6); DO_DIGIT(7); DO_DIGIT(8); DO_DIGIT(9); #undef DO_DIGIT @@ -2128,13 +2189,336 @@ format_number (GString *str, while (number); while (pad && i < width) - tmp[i++] = pad == '0' ? digits[0] : pad; + tmp[i++] = *pad == '0' ? digits[0] : pad; /* should really be impossible */ g_assert (i <= 10); while (i) - g_string_append_unichar (str, tmp[--i]); + g_string_append (str, tmp[--i]); +} + +static gboolean g_date_time_format_locale (GDateTime *datetime, + const gchar *format, + GString *outstr, + gboolean locale_is_utf8); + +/* g_date_time_format() subroutine that takes a locale-encoded format + * string and produces a locale-encoded date/time string. + */ +static gboolean +g_date_time_locale_format_locale (GDateTime *datetime, + const gchar *format, + GString *outstr, + gboolean locale_is_utf8) +{ + gchar *utf8_format; + gboolean success; + + if (locale_is_utf8) + return g_date_time_format_locale (datetime, format, outstr, + locale_is_utf8); + + utf8_format = g_locale_to_utf8 (format, -1, NULL, NULL, NULL); + if (!utf8_format) + return FALSE; + + success = g_date_time_format_locale (datetime, utf8_format, outstr, + locale_is_utf8); + g_free (utf8_format); + return success; +} + +/* g_date_time_format() subroutine that takes a UTF-8 format + * string and produces a locale-encoded date/time string. + */ +static gboolean +g_date_time_format_locale (GDateTime *datetime, + const gchar *format, + GString *outstr, + gboolean locale_is_utf8) +{ + guint len; + guint colons; + gchar *tmp; + gunichar c; + gboolean alt_digits = FALSE; + gboolean pad_set = FALSE; + gchar *pad = ""; + gchar *ampm; + const gchar *tz; + + while (*format) + { + len = strcspn (format, "%"); + if (len) + { + if (locale_is_utf8) + g_string_append_len (outstr, format, len); + else + { + tmp = g_locale_from_utf8 (format, len, NULL, NULL, NULL); + if (!tmp) + return FALSE; + g_string_append (outstr, tmp); + g_free (tmp); + } + } + + format += len; + if (!*format) + break; + + g_assert (*format == '%'); + format++; + if (!*format) + break; + + colons = 0; + alt_digits = FALSE; + pad_set = FALSE; + + next_mod: + c = g_utf8_get_char (format); + format = g_utf8_next_char (format); + switch (c) + { + case 'a': + g_string_append (outstr, WEEKDAY_ABBR (datetime)); + break; + case 'A': + g_string_append (outstr, WEEKDAY_FULL (datetime)); + break; + case 'b': + g_string_append (outstr, MONTH_ABBR (datetime)); + break; + case 'B': + g_string_append (outstr, MONTH_FULL (datetime)); + break; + case 'c': + { + if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_TIME_FMT, + outstr, locale_is_utf8)) + return FALSE; + } + break; + case 'C': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_year (datetime) / 100); + break; + case 'd': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_day_of_month (datetime)); + break; + case 'e': + format_number (outstr, alt_digits, pad_set ? pad : " ", 2, + g_date_time_get_day_of_month (datetime)); + break; + case 'F': + g_string_append_printf (outstr, "%d-%02d-%02d", + g_date_time_get_year (datetime), + g_date_time_get_month (datetime), + g_date_time_get_day_of_month (datetime)); + break; + case 'g': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_week_numbering_year (datetime) % 100); + break; + case 'G': + format_number (outstr, alt_digits, pad_set ? pad : 0, 0, + g_date_time_get_week_numbering_year (datetime)); + break; + case 'h': + g_string_append (outstr, MONTH_ABBR (datetime)); + break; + case 'H': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_hour (datetime)); + break; + case 'I': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + (g_date_time_get_hour (datetime) + 11) % 12 + 1); + break; + case 'j': + format_number (outstr, alt_digits, pad_set ? pad : "0", 3, + g_date_time_get_day_of_year (datetime)); + break; + case 'k': + format_number (outstr, alt_digits, pad_set ? pad : " ", 2, + g_date_time_get_hour (datetime)); + break; + case 'l': + format_number (outstr, alt_digits, pad_set ? pad : " ", 2, + (g_date_time_get_hour (datetime) + 11) % 12 + 1); + break; + case 'n': + g_string_append_c (outstr, '\n'); + break; + case 'm': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_month (datetime)); + break; + case 'M': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_minute (datetime)); + break; + case 'O': + alt_digits = TRUE; + goto next_mod; + case 'p': + ampm = (gchar *) GET_AMPM (datetime); + if (!locale_is_utf8) + { + ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL); + if (!tmp) + return FALSE; + } + ampm = g_utf8_strup (ampm, -1); + if (!locale_is_utf8) + { + g_free (tmp); + tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL); + g_free (ampm); + if (!tmp) + return FALSE; + ampm = tmp; + } + g_string_append (outstr, ampm); + g_free (ampm); + break; + case 'P': + ampm = (gchar *) GET_AMPM (datetime); + if (!locale_is_utf8) + { + ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL); + if (!tmp) + return FALSE; + } + ampm = g_utf8_strdown (ampm, -1); + if (!locale_is_utf8) + { + g_free (tmp); + tmp = g_locale_from_utf8 (ampm, -1, NULL, NULL, NULL); + g_free (ampm); + if (!tmp) + return FALSE; + ampm = tmp; + } + g_string_append (outstr, ampm); + g_free (ampm); + break; + case 'r': + { + if (!g_date_time_locale_format_locale (datetime, PREFERRED_12HR_TIME_FMT, + outstr, locale_is_utf8)) + return FALSE; + } + break; + case 'R': + g_string_append_printf (outstr, "%02d:%02d", + g_date_time_get_hour (datetime), + g_date_time_get_minute (datetime)); + break; + case 's': + g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime)); + break; + case 'S': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_second (datetime)); + break; + case 't': + g_string_append_c (outstr, '\t'); + break; + case 'T': + g_string_append_printf (outstr, "%02d:%02d:%02d", + g_date_time_get_hour (datetime), + g_date_time_get_minute (datetime), + g_date_time_get_second (datetime)); + break; + case 'u': + format_number (outstr, alt_digits, 0, 0, + g_date_time_get_day_of_week (datetime)); + break; + case 'V': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_week_of_year (datetime)); + break; + case 'w': + format_number (outstr, alt_digits, 0, 0, + g_date_time_get_day_of_week (datetime) % 7); + break; + case 'x': + { + if (!g_date_time_locale_format_locale (datetime, PREFERRED_DATE_FMT, + outstr, locale_is_utf8)) + return FALSE; + } + break; + case 'X': + { + if (!g_date_time_locale_format_locale (datetime, PREFERRED_TIME_FMT, + outstr, locale_is_utf8)) + return FALSE; + } + break; + case 'y': + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_year (datetime) % 100); + break; + case 'Y': + format_number (outstr, alt_digits, 0, 0, + g_date_time_get_year (datetime)); + break; + case 'z': + { + gint64 offset; + if (datetime->tz != NULL) + offset = g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND; + else + offset = 0; + if (!format_z (outstr, (int) offset, colons)) + return FALSE; + } + break; + case 'Z': + tz = g_date_time_get_timezone_abbreviation (datetime); + if (!locale_is_utf8) + { + tz = tmp = g_locale_from_utf8 (tz, -1, NULL, NULL, NULL); + if (!tmp) + return FALSE; + } + g_string_append (outstr, tz); + if (!locale_is_utf8) + g_free (tmp); + break; + case '%': + g_string_append_c (outstr, '%'); + break; + case '-': + pad_set = TRUE; + pad = ""; + goto next_mod; + case '_': + pad_set = TRUE; + pad = " "; + goto next_mod; + case '0': + pad_set = TRUE; + pad = "0"; + goto next_mod; + case ':': + /* Colons are only allowed before 'z' */ + if (*format && *format != 'z' && *format != ':') + return FALSE; + colons++; + goto next_mod; + default: + return FALSE; + } + } + + return TRUE; } /** @@ -2158,250 +2542,81 @@ format_number (GString *str, * * The following format specifiers are supported: * - * - * - * \%a: - * - * the abbreviated weekday name according to the current locale - * - * - * \%A: - * - * the full weekday name according to the current locale - * - * - * \%b: - * - * the abbreviated month name according to the current locale - * - * - * \%B: - * - * the full month name according to the current locale - * - * - * \%c: - * - * the preferred date and time representation for the current locale - * - * - * \%C: - * - * The century number (year/100) as a 2-digit integer (00-99) - * - * - * \%d: - * - * the day of the month as a decimal number (range 01 to 31) - * - * - * \%e: - * - * the day of the month as a decimal number (range 1 to 31) - * - * - * \%F: - * - * equivalent to \%Y-\%m-\%d (the ISO 8601 date - * format) - * - * - * \%g: - * - * the last two digits of the ISO 8601 week-based year as a decimal - * number (00-99). This works well with \%V and \%u. - * - * - * \%G: - * - * the ISO 8601 week-based year as a decimal number. This works well - * with \%V and \%u. - * - * - * \%h: - * - * equivalent to \%b - * - * - * \%H: - * - * the hour as a decimal number using a 24-hour clock (range 00 to - * 23) - * - * - * \%I: - * - * the hour as a decimal number using a 12-hour clock (range 01 to - * 12) - * - * - * \%j: - * - * the day of the year as a decimal number (range 001 to 366) - * - * - * \%k: - * - * the hour (24-hour clock) as a decimal number (range 0 to 23); - * single digits are preceded by a blank - * - * - * \%l: - * - * the hour (12-hour clock) as a decimal number (range 1 to 12); - * single digits are preceded by a blank - * - * - * \%m: - * - * the month as a decimal number (range 01 to 12) - * - * - * \%M: - * - * the minute as a decimal number (range 00 to 59) - * - * - * \%p: - * - * either "AM" or "PM" according to the given time value, or the - * corresponding strings for the current locale. Noon is treated as - * "PM" and midnight as "AM". - * - * - * \%P: - * - * like \%p but lowercase: "am" or "pm" or a corresponding string for - * the current locale - * - * - * \%r: - * - * the time in a.m. or p.m. notation - * - * - * \%R: - * - * the time in 24-hour notation (\%H:\%M) - * - * - * \%s: - * - * the number of seconds since the Epoch, that is, since 1970-01-01 - * 00:00:00 UTC - * - * - * \%S: - * - * the second as a decimal number (range 00 to 60) - * - * - * \%t: - * - * a tab character - * - * - * \%T: - * - * the time in 24-hour notation with seconds (\%H:\%M:\%S) - * - * - * \%u: - * - * the ISO 8601 standard day of the week as a decimal, range 1 to 7, - * Monday being 1. This works well with \%G and \%V. - * - * - * \%V: - * - * the ISO 8601 standard week number of the current year as a decimal - * number, range 01 to 53, where week 1 is the first week that has at - * least 4 days in the new year. See g_date_time_get_week_of_year(). - * This works well with \%G and \%u. - * - * - * \%w: - * - * the day of the week as a decimal, range 0 to 6, Sunday being 0. - * This is not the ISO 8601 standard format -- use \%u instead. - * - * - * \%x: - * - * the preferred date representation for the current locale without - * the time - * - * - * \%X: - * - * the preferred time representation for the current locale without - * the date - * - * - * \%y: - * - * the year as a decimal number without the century - * - * - * \%Y: - * - * the year as a decimal number including the century - * - * - * \%z: - * - * the time-zone as hour offset from UTC - * - * - * \%Z: - * - * the time zone or name or abbreviation - * - * - * \%\%: - * - * a literal \% character - * - * + * - \%a: the abbreviated weekday name according to the current locale + * - \%A: the full weekday name according to the current locale + * - \%b: the abbreviated month name according to the current locale + * - \%B: the full month name according to the current locale + * - \%c: the preferred date and time rpresentation for the current locale + * - \%C: the century number (year/100) as a 2-digit integer (00-99) + * - \%d: the day of the month as a decimal number (range 01 to 31) + * - \%e: the day of the month as a decimal number (range 1 to 31) + * - \%F: equivalent to `%Y-%m-%d` (the ISO 8601 date format) + * - \%g: the last two digits of the ISO 8601 week-based year as a + * decimal number (00-99). This works well with \%V and \%u. + * - \%G: the ISO 8601 week-based year as a decimal number. This works + * well with \%V and \%u. + * - \%h: equivalent to \%b + * - \%H: the hour as a decimal number using a 24-hour clock (range 00 to 23) + * - \%I: the hour as a decimal number using a 12-hour clock (range 01 to 12) + * - \%j: the day of the year as a decimal number (range 001 to 366) + * - \%k: the hour (24-hour clock) as a decimal number (range 0 to 23); + * single digits are preceded by a blank + * - \%l: the hour (12-hour clock) as a decimal number (range 1 to 12); + * single digits are preceded by a blank + * - \%m: the month as a decimal number (range 01 to 12) + * - \%M: the minute as a decimal number (range 00 to 59) + * - \%p: either "AM" or "PM" according to the given time value, or the + * corresponding strings for the current locale. Noon is treated as + * "PM" and midnight as "AM". + * - \%P: like \%p but lowercase: "am" or "pm" or a corresponding string for + * the current locale + * - \%r: the time in a.m. or p.m. notation + * - \%R: the time in 24-hour notation (\%H:\%M) + * - \%s: the number of seconds since the Epoch, that is, since 1970-01-01 + * 00:00:00 UTC + * - \%S: the second as a decimal number (range 00 to 60) + * - \%t: a tab character + * - \%T: the time in 24-hour notation with seconds (\%H:\%M:\%S) + * - \%u: the ISO 8601 standard day of the week as a decimal, range 1 to 7, + * Monday being 1. This works well with \%G and \%V. + * - \%V: the ISO 8601 standard week number of the current year as a decimal + * number, range 01 to 53, where week 1 is the first week that has at + * least 4 days in the new year. See g_date_time_get_week_of_year(). + * This works well with \%G and \%u. + * - \%w: the day of the week as a decimal, range 0 to 6, Sunday being 0. + * This is not the ISO 8601 standard format -- use \%u instead. + * - \%x: the preferred date representation for the current locale without + * the time + * - \%X: the preferred time representation for the current locale without + * the date + * - \%y: the year as a decimal number without the century + * - \%Y: the year as a decimal number including the century + * - \%z: the time zone as an offset from UTC (+hhmm) + * - \%:z: the time zone as an offset from UTC (+hh:mm). + * This is a gnulib strftime() extension. Since: 2.38 + * - \%::z: the time zone as an offset from UTC (+hh:mm:ss). This is a + * gnulib strftime() extension. Since: 2.38 + * - \%:::z: the time zone as an offset from UTC, with : to necessary + * precision (e.g., -04, +05:30). This is a gnulib strftime() extension. Since: 2.38 + * - \%Z: the time zone or name or abbreviation + * - \%\%: a literal \% character * * Some conversion specifications can be modified by preceding the * conversion specifier by one or more modifier characters. The * following modifiers are supported for many of the numeric * conversions: - * - * - * O - * - * Use alternative numeric symbols, if the current locale - * supports those. - * - * - * - * _ - * - * Pad a numeric result with spaces. - * This overrides the default padding for the specifier. - * - * - * - * - - * - * Do not pad a numeric result. - * This overrides the default padding for the specifier. - * - * - * - * 0 - * - * Pad a numeric result with zeros. - * This overrides the default padding for the specifier. - * - * - * + * + * - O: Use alternative numeric symbols, if the current locale supports those. + * - _: Pad a numeric result with spaces. This overrides the default padding + * for the specifier. + * - -: Do not pad a numeric result. This overrides the default padding + * for the specifier. + * - 0: Pad a numeric result with zeros. This overrides the default padding + * for the specifier. * * Returns: a newly allocated string formatted to the requested format - * or %NULL in the case that there was an error. The string - * should be freed with g_free(). + * or %NULL in the case that there was an error. The string + * should be freed with g_free(). * * Since: 2.26 */ @@ -2410,242 +2625,27 @@ g_date_time_format (GDateTime *datetime, const gchar *format) { GString *outstr; - gchar *tmp; - gunichar c; - gboolean in_mod = FALSE; - gboolean alt_digits = FALSE; - gboolean pad_set = FALSE; - gchar pad = '\0'; - gchar *ampm; + gchar *utf8; + gboolean locale_is_utf8 = g_get_charset (NULL); g_return_val_if_fail (datetime != NULL, NULL); g_return_val_if_fail (format != NULL, NULL); g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL); outstr = g_string_sized_new (strlen (format) * 2); - in_mod = FALSE; - for (; *format; format = g_utf8_next_char (format)) + if (!g_date_time_format_locale (datetime, format, outstr, locale_is_utf8)) { - c = g_utf8_get_char (format); - - switch (c) - { - case '%': - if (!in_mod) - { - in_mod = TRUE; - alt_digits = FALSE; - pad_set = FALSE; - break; - } - /* Fall through */ - default: - if (in_mod) - { - switch (c) - { - case 'a': - g_string_append (outstr, WEEKDAY_ABBR (datetime)); - break; - case 'A': - g_string_append (outstr, WEEKDAY_FULL (datetime)); - break; - case 'b': - g_string_append (outstr, MONTH_ABBR (datetime)); - break; - case 'B': - g_string_append (outstr, MONTH_FULL (datetime)); - break; - case 'c': - { - tmp = g_date_time_format (datetime, PREFERRED_DATE_TIME_FMT); - g_string_append (outstr, tmp); - g_free (tmp); - } - break; - case 'C': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_year (datetime) / 100); - break; - case 'd': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_day_of_month (datetime)); - break; - case 'e': - format_number (outstr, alt_digits, pad_set ? pad : ' ', 2, - g_date_time_get_day_of_month (datetime)); - break; - case 'F': - g_string_append_printf (outstr, "%d-%02d-%02d", - g_date_time_get_year (datetime), - g_date_time_get_month (datetime), - g_date_time_get_day_of_month (datetime)); - break; - case 'g': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_week_numbering_year (datetime) % 100); - break; - case 'G': - format_number (outstr, alt_digits, pad_set ? pad : 0, 0, - g_date_time_get_week_numbering_year (datetime)); - break; - case 'h': - g_string_append (outstr, MONTH_ABBR (datetime)); - break; - case 'H': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_hour (datetime)); - break; - case 'I': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - (g_date_time_get_hour (datetime) + 11) % 12 + 1); - break; - case 'j': - format_number (outstr, alt_digits, pad_set ? pad : '0', 3, - g_date_time_get_day_of_year (datetime)); - break; - case 'k': - format_number (outstr, alt_digits, pad_set ? pad : ' ', 2, - g_date_time_get_hour (datetime)); - break; - case 'l': - format_number (outstr, alt_digits, pad_set ? pad : ' ', 2, - (g_date_time_get_hour (datetime) + 11) % 12 + 1); - break; - case 'n': - g_string_append_c (outstr, '\n'); - break; - case 'm': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_month (datetime)); - break; - case 'M': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_minute (datetime)); - break; - case 'O': - alt_digits = TRUE; - goto next_mod; - case 'p': - ampm = g_utf8_strup (GET_AMPM (datetime), -1); - g_string_append (outstr, ampm); - g_free (ampm); - break; - case 'P': - ampm = g_utf8_strdown (GET_AMPM (datetime), -1); - g_string_append (outstr, ampm); - g_free (ampm); - break; - case 'r': - { - tmp = g_date_time_format (datetime, PREFERRED_12HR_TIME_FMT); - g_string_append (outstr, tmp); - g_free (tmp); - } - break; - case 'R': - g_string_append_printf (outstr, "%02d:%02d", - g_date_time_get_hour (datetime), - g_date_time_get_minute (datetime)); - break; - case 's': - g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime)); - break; - case 'S': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_second (datetime)); - break; - case 't': - g_string_append_c (outstr, '\t'); - break; - case 'T': - g_string_append_printf (outstr, "%02d:%02d:%02d", - g_date_time_get_hour (datetime), - g_date_time_get_minute (datetime), - g_date_time_get_second (datetime)); - break; - case 'u': - format_number (outstr, alt_digits, 0, 0, - g_date_time_get_day_of_week (datetime)); - break; - case 'V': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_week_of_year (datetime)); - break; - case 'w': - format_number (outstr, alt_digits, 0, 0, - g_date_time_get_day_of_week (datetime) % 7); - break; - case 'x': - { - tmp = g_date_time_format (datetime, PREFERRED_DATE_FMT); - g_string_append (outstr, tmp); - g_free (tmp); - } - break; - case 'X': - { - tmp = g_date_time_format (datetime, PREFERRED_TIME_FMT); - g_string_append (outstr, tmp); - g_free (tmp); - } - break; - case 'y': - format_number (outstr, alt_digits, pad_set ? pad : '0', 2, - g_date_time_get_year (datetime) % 100); - break; - case 'Y': - format_number (outstr, alt_digits, 0, 0, - g_date_time_get_year (datetime)); - break; - case 'z': - if (datetime->tz != NULL) - { - gint64 offset = g_date_time_get_utc_offset (datetime) - / USEC_PER_SECOND; - - g_string_append_printf (outstr, "%+03d%02d", - (int) offset / 3600, - (int) abs(offset) / 60 % 60); - } - else - g_string_append (outstr, "+0000"); - break; - case 'Z': - g_string_append (outstr, g_date_time_get_timezone_abbreviation (datetime)); - break; - case '%': - g_string_append_c (outstr, '%'); - break; - case '-': - pad_set = TRUE; - pad = 0; - goto next_mod; - case '_': - pad_set = TRUE; - pad = ' '; - goto next_mod; - case '0': - pad_set = TRUE; - pad = '0'; - goto next_mod; - default: - goto bad_format; - } - in_mod = FALSE; - } - else - g_string_append_unichar (outstr, c); - } -next_mod: ; + g_string_free (outstr, TRUE); + return NULL; } - return g_string_free (outstr, FALSE); + if (locale_is_utf8) + return g_string_free (outstr, FALSE); -bad_format: + utf8 = g_locale_to_utf8 (outstr->str, outstr->len, NULL, NULL, NULL); g_string_free (outstr, TRUE); - return NULL; + return utf8; }