mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-05 17:06:18 +01:00
gdatetime: Add support for %E modifier to g_date_time_format()
The `%E` modifier causes dates to be formatted using an alternative era representation for years. This doesn’t do anything for most dates, but in locales such as Thai and Japanese it causes years to be printed using era names. In Thai, this means the Thai solar calendar (https://en.wikipedia.org/wiki/Thai_solar_calendar). In Japanese, this means Japanese era names (https://en.wikipedia.org/wiki/Japanese_era_name). The `%E` modifier syntax follows what’s supported in glibc — see nl_langinfo(3). Supporting this is quite involved, as it means loading the `ERA` description from libc and parsing it. Unit tests are included. Signed-off-by: Philip Withnall <philip@tecnocode.co.uk> Fixes: #3119
This commit is contained in:
parent
ded4976337
commit
df4aea7620
@ -11,11 +11,11 @@ cache:
|
||||
- _ccache/
|
||||
|
||||
variables:
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v22"
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v23"
|
||||
COVERITY_IMAGE: "registry.gitlab.gnome.org/gnome/glib/coverity:v7"
|
||||
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v16"
|
||||
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v17"
|
||||
ALPINE_IMAGE: "registry.gitlab.gnome.org/gnome/glib/alpine:v0"
|
||||
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v12"
|
||||
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v13"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 4
|
||||
G_MESSAGES_DEBUG: all
|
||||
MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings"
|
||||
|
@ -64,6 +64,7 @@ RUN locale-gen de_DE.UTF-8 \
|
||||
&& locale-gen lt_LT.UTF-8 \
|
||||
&& locale-gen pl_PL.UTF-8 \
|
||||
&& locale-gen ru_RU.UTF-8 \
|
||||
&& locale-gen th_TH.UTF-8 \
|
||||
&& locale-gen tr_TR.UTF-8
|
||||
|
||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
||||
|
@ -32,6 +32,7 @@ RUN dnf -y update \
|
||||
glibc-langpack-lt \
|
||||
glibc-langpack-pl \
|
||||
glibc-langpack-ru \
|
||||
glibc-langpack-th \
|
||||
glibc-langpack-tr \
|
||||
"gnome-desktop-testing >= 2018.1" \
|
||||
gtk-doc \
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM registry.gitlab.gnome.org/gnome/glib/fedora:v22
|
||||
FROM registry.gitlab.gnome.org/gnome/glib/fedora:v23
|
||||
|
||||
USER root
|
||||
|
||||
|
254
glib/gdatetime-private.c
Normal file
254
glib/gdatetime-private.c
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2023 Philip Withnall
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "glib.h"
|
||||
#include "gdatetime-private.h"
|
||||
|
||||
/**
|
||||
* _g_era_date_compare:
|
||||
* @date1: first date
|
||||
* @date2: second date
|
||||
*
|
||||
* Compare two #GEraDates for ordering, taking into account negative and
|
||||
* positive infinity.
|
||||
*
|
||||
* Returns: strcmp()-style integer, `<0` indicates `date1 < date2`, `0`
|
||||
* indicates `date1 == date2`, `>0` indicates `date1 > date2`
|
||||
* Since: 2.80
|
||||
*/
|
||||
int
|
||||
_g_era_date_compare (const GEraDate *date1,
|
||||
const GEraDate *date2)
|
||||
{
|
||||
if (date1->type == G_ERA_DATE_SET &&
|
||||
date2->type == G_ERA_DATE_SET)
|
||||
{
|
||||
if (date1->year != date2->year)
|
||||
return date1->year - date2->year;
|
||||
if (date1->month != date2->month)
|
||||
return date1->month - date2->month;
|
||||
return date1->day - date2->day;
|
||||
}
|
||||
|
||||
if (date1->type == date2->type)
|
||||
return 0;
|
||||
|
||||
if (date1->type == G_ERA_DATE_MINUS_INFINITY || date2->type == G_ERA_DATE_PLUS_INFINITY)
|
||||
return -1;
|
||||
if (date1->type == G_ERA_DATE_PLUS_INFINITY || date2->type == G_ERA_DATE_MINUS_INFINITY)
|
||||
return 1;
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_era_date (const char *str,
|
||||
const char *endptr,
|
||||
GEraDate *out_date)
|
||||
{
|
||||
const char *str_endptr = NULL;
|
||||
int year_multiplier;
|
||||
guint64 year, month, day;
|
||||
|
||||
year_multiplier = (str[0] == '-') ? -1 : 1;
|
||||
if (str[0] == '-' || str[0] == '+')
|
||||
str++;
|
||||
|
||||
year = g_ascii_strtoull (str, (gchar **) &str_endptr, 10);
|
||||
g_assert (str_endptr <= endptr);
|
||||
if (str_endptr == endptr || *str_endptr != '/' || year > G_MAXINT)
|
||||
return FALSE;
|
||||
str = str_endptr + 1;
|
||||
|
||||
month = g_ascii_strtoull (str, (gchar **) &str_endptr, 10);
|
||||
g_assert (str_endptr <= endptr);
|
||||
if (str_endptr == endptr || *str_endptr != '/' || month < 1 || month > 12)
|
||||
return FALSE;
|
||||
str = str_endptr + 1;
|
||||
|
||||
day = g_ascii_strtoull (str, (gchar **) &str_endptr, 10);
|
||||
g_assert (str_endptr <= endptr);
|
||||
if (str_endptr != endptr || day < 1 || day > 31)
|
||||
return FALSE;
|
||||
|
||||
/* Success */
|
||||
out_date->type = G_ERA_DATE_SET;
|
||||
out_date->year = year_multiplier * year;
|
||||
out_date->month = month;
|
||||
out_date->day = day;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* _g_era_description_segment_ref:
|
||||
* @segment: a #GEraDescriptionSegment
|
||||
*
|
||||
* Increase the ref count of @segment.
|
||||
*
|
||||
* Returns: (transfer full): @segment
|
||||
* Since: 2.80
|
||||
*/
|
||||
GEraDescriptionSegment *
|
||||
_g_era_description_segment_ref (GEraDescriptionSegment *segment)
|
||||
{
|
||||
g_atomic_ref_count_inc (&segment->ref_count);
|
||||
return segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* _g_era_description_segment_unref:
|
||||
* @segment: (transfer full): a #GEraDescriptionSegment to unref
|
||||
*
|
||||
* Decreases the ref count of @segment.
|
||||
*
|
||||
* Since: 2.80
|
||||
*/
|
||||
void
|
||||
_g_era_description_segment_unref (GEraDescriptionSegment *segment)
|
||||
{
|
||||
if (g_atomic_ref_count_dec (&segment->ref_count))
|
||||
{
|
||||
g_free (segment->era_format);
|
||||
g_free (segment->era_name);
|
||||
g_free (segment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _g_era_description_parse:
|
||||
* @desc: an `ERA` description string from `nl_langinfo()`
|
||||
*
|
||||
* Parse an ERA description string. See [`nl_langinfo(3)`](man:nl_langinfo(3)).
|
||||
*
|
||||
* Example description string for th_TR.UTF-8:
|
||||
* ```
|
||||
* +:1:-543/01/01:+*:พ.ศ.:%EC %Ey
|
||||
* ```
|
||||
*
|
||||
* @desc must be in UTF-8, so all conversion from the locale encoding must
|
||||
* happen before this function is called. The resulting `era_name` and
|
||||
* `era_format` in the returned segments will be in UTF-8.
|
||||
*
|
||||
* Returns: (transfer full) (nullable) (element-type GEraDescriptionSegment):
|
||||
* array of one or more parsed era segments, or %NULL if parsing failed
|
||||
* Since: 2.80
|
||||
*/
|
||||
GPtrArray *
|
||||
_g_era_description_parse (const char *desc)
|
||||
{
|
||||
GPtrArray *segments = g_ptr_array_new_with_free_func ((GDestroyNotify) _g_era_description_segment_unref);
|
||||
|
||||
for (const char *p = desc; *p != '\0';)
|
||||
{
|
||||
const char *next_colon, *endptr = NULL;
|
||||
GEraDescriptionSegment *segment = NULL;
|
||||
char direction;
|
||||
guint64 offset;
|
||||
GEraDate start_date, end_date;
|
||||
char *era_name = NULL, *era_format = NULL;
|
||||
|
||||
/* direction */
|
||||
direction = *p++;
|
||||
if (direction != '+' && direction != '-')
|
||||
goto error;
|
||||
|
||||
if (*p++ != ':')
|
||||
goto error;
|
||||
|
||||
/* offset */
|
||||
next_colon = strchr (p, ':');
|
||||
if (next_colon == NULL)
|
||||
goto error;
|
||||
|
||||
offset = g_ascii_strtoull (p, (gchar **) &endptr, 10);
|
||||
if (endptr != next_colon)
|
||||
goto error;
|
||||
p = next_colon + 1;
|
||||
|
||||
/* start_date */
|
||||
next_colon = strchr (p, ':');
|
||||
if (next_colon == NULL)
|
||||
goto error;
|
||||
|
||||
if (!parse_era_date (p, next_colon, &start_date))
|
||||
goto error;
|
||||
p = next_colon + 1;
|
||||
|
||||
/* end_date */
|
||||
next_colon = strchr (p, ':');
|
||||
if (next_colon == NULL)
|
||||
goto error;
|
||||
|
||||
if (strncmp (p, "-*", 2) == 0)
|
||||
end_date.type = G_ERA_DATE_MINUS_INFINITY;
|
||||
else if (strncmp (p, "+*", 2) == 0)
|
||||
end_date.type = G_ERA_DATE_PLUS_INFINITY;
|
||||
else if (!parse_era_date (p, next_colon, &end_date))
|
||||
goto error;
|
||||
p = next_colon + 1;
|
||||
|
||||
/* era_name */
|
||||
next_colon = strchr (p, ':');
|
||||
if (next_colon == NULL)
|
||||
goto error;
|
||||
|
||||
if (next_colon - p == 0)
|
||||
goto error;
|
||||
era_name = g_strndup (p, next_colon - p);
|
||||
p = next_colon + 1;
|
||||
|
||||
/* era_format; either the final field in the segment (followed by a
|
||||
* semicolon) or the description (followed by nul) */
|
||||
next_colon = strchr (p, ';');
|
||||
if (next_colon == NULL)
|
||||
next_colon = p + strlen (p);
|
||||
|
||||
if (next_colon - p == 0)
|
||||
{
|
||||
g_free (era_name);
|
||||
goto error;
|
||||
}
|
||||
era_format = g_strndup (p, next_colon - p);
|
||||
if (*next_colon == ';')
|
||||
p = next_colon + 1;
|
||||
else
|
||||
p = next_colon;
|
||||
|
||||
/* Successfully parsed that segment. */
|
||||
segment = g_new0 (GEraDescriptionSegment, 1);
|
||||
g_atomic_ref_count_init (&segment->ref_count);
|
||||
segment->offset = offset;
|
||||
segment->start_date = start_date;
|
||||
segment->end_date = end_date;
|
||||
segment->direction_multiplier =
|
||||
((_g_era_date_compare (&segment->start_date, &segment->end_date) <= 0) ? 1 : -1) *
|
||||
((direction == '-') ? -1 : 1);
|
||||
segment->era_name = g_steal_pointer (&era_name);
|
||||
segment->era_format = g_steal_pointer (&era_format);
|
||||
|
||||
g_ptr_array_add (segments, g_steal_pointer (&segment));
|
||||
}
|
||||
|
||||
return g_steal_pointer (&segments);
|
||||
|
||||
error:
|
||||
g_ptr_array_unref (segments);
|
||||
return NULL;
|
||||
}
|
85
glib/gdatetime-private.h
Normal file
85
glib/gdatetime-private.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2023 Philip Withnall
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "glib.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GEraDate:
|
||||
* @type: the type of date
|
||||
* @year: year of the date, in the Gregorian calendar
|
||||
* @month: month of the date, in the Gregorian calendar
|
||||
* @day: day of the date, in the Gregorian calendar
|
||||
*
|
||||
* A date from a #GEraDescriptionSegment.
|
||||
*
|
||||
* If @type is %G_ERA_DATE_SET, @year, @month and @day are valid. Otherwise,
|
||||
* they are undefined.
|
||||
*
|
||||
* Since: 2.80
|
||||
*/
|
||||
typedef struct {
|
||||
enum {
|
||||
G_ERA_DATE_SET,
|
||||
G_ERA_DATE_PLUS_INFINITY,
|
||||
G_ERA_DATE_MINUS_INFINITY,
|
||||
} type;
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
} GEraDate;
|
||||
|
||||
int _g_era_date_compare (const GEraDate *date1,
|
||||
const GEraDate *date2);
|
||||
|
||||
/**
|
||||
* GEraDescriptionSegment:
|
||||
* @ref_count: reference count
|
||||
* @direction_multiplier: `-1` or `1` depending on the order of @start_date and
|
||||
* @end_date
|
||||
* @offset: offset of the first year in the era
|
||||
* @start_date: start date (in the Gregorian calendar) of the era
|
||||
* @end_date: end date (in the Gregorian calendar) of the era
|
||||
* @era_name: (not nullable): name of the era
|
||||
* @era_format: (not nullable): format string to use for `%EY`
|
||||
*
|
||||
* A segment of an `ERA` description string, describing a single era. See
|
||||
* [`nl_langinfo(3)`](man:nl_langinfo(3)).
|
||||
*
|
||||
* Since: 2.80
|
||||
*/
|
||||
typedef struct {
|
||||
gatomicrefcount ref_count;
|
||||
int direction_multiplier;
|
||||
guint64 offset;
|
||||
GEraDate start_date; /* inclusive */
|
||||
GEraDate end_date; /* inclusive */
|
||||
char *era_name; /* UTF-8 encoded */
|
||||
char *era_format; /* UTF-8 encoded */
|
||||
} GEraDescriptionSegment;
|
||||
|
||||
GPtrArray *_g_era_description_parse (const char *desc);
|
||||
|
||||
GEraDescriptionSegment *_g_era_description_segment_ref (GEraDescriptionSegment *segment);
|
||||
void _g_era_description_segment_unref (GEraDescriptionSegment *segment);
|
||||
|
||||
G_END_DECLS
|
247
glib/gdatetime.c
247
glib/gdatetime.c
@ -69,6 +69,7 @@
|
||||
#include "gconvert.h"
|
||||
#include "gconvertprivate.h"
|
||||
#include "gdatetime.h"
|
||||
#include "gdatetime-private.h"
|
||||
#include "gfileutils.h"
|
||||
#include "ghash.h"
|
||||
#include "glibintl.h"
|
||||
@ -162,8 +163,11 @@ static const guint16 days_in_year[2][13] =
|
||||
#define GET_AMPM_IS_LOCALE TRUE
|
||||
|
||||
#define PREFERRED_DATE_TIME_FMT nl_langinfo (D_T_FMT)
|
||||
#define PREFERRED_ERA_DATE_TIME_FMT nl_langinfo (ERA_D_T_FMT)
|
||||
#define PREFERRED_DATE_FMT nl_langinfo (D_FMT)
|
||||
#define PREFERRED_ERA_DATE_FMT nl_langinfo (ERA_D_FMT)
|
||||
#define PREFERRED_TIME_FMT nl_langinfo (T_FMT)
|
||||
#define PREFERRED_ERA_TIME_FMT nl_langinfo (ERA_T_FMT)
|
||||
#define PREFERRED_12HR_TIME_FMT nl_langinfo (T_FMT_AMPM)
|
||||
|
||||
static const gint weekday_item[2][7] =
|
||||
@ -187,6 +191,10 @@ static const gint month_item[2][12] =
|
||||
#define MONTH_FULL(d) nl_langinfo (month_item[1][g_date_time_get_month (d) - 1])
|
||||
#define MONTH_FULL_IS_LOCALE TRUE
|
||||
|
||||
#define ERA_DESCRIPTION nl_langinfo (ERA)
|
||||
#define ERA_DESCRIPTION_IS_LOCALE TRUE
|
||||
#define ERA_DESCRIPTION_N_SEGMENTS (int) (gintptr) nl_langinfo (_NL_TIME_ERA_NUM_ENTRIES)
|
||||
|
||||
#else
|
||||
|
||||
#define GET_AMPM(d) (get_fallback_ampm (g_date_time_get_hour (d)))
|
||||
@ -194,12 +202,15 @@ static const gint month_item[2][12] =
|
||||
|
||||
/* Translators: this is the preferred format for expressing the date and the time */
|
||||
#define PREFERRED_DATE_TIME_FMT C_("GDateTime", "%a %b %e %H:%M:%S %Y")
|
||||
#define PREFERRED_ERA_DATE_TIME_FMT PREFERRED_DATE_TIME_FMT
|
||||
|
||||
/* Translators: this is the preferred format for expressing the date */
|
||||
#define PREFERRED_DATE_FMT C_("GDateTime", "%m/%d/%y")
|
||||
#define PREFERRED_ERA_DATE_FMT PREFERRED_DATE_FMT
|
||||
|
||||
/* Translators: this is the preferred format for expressing the time */
|
||||
#define PREFERRED_TIME_FMT C_("GDateTime", "%H:%M:%S")
|
||||
#define PREFERRED_ERA_TIME_FMT PREFERRED_TIME_FMT
|
||||
|
||||
/* Translators: this is the preferred format for expressing 12 hour time */
|
||||
#define PREFERRED_12HR_TIME_FMT C_("GDateTime", "%I:%M:%S %p")
|
||||
@ -219,6 +230,10 @@ static const gint month_item[2][12] =
|
||||
#define MONTH_FULL(d) (get_month_name_standalone (g_date_time_get_month (d)))
|
||||
#define MONTH_FULL_IS_LOCALE FALSE
|
||||
|
||||
#define ERA_DESCRIPTION NULL
|
||||
#define ERA_DESCRIPTION_IS_LOCALE FALSE
|
||||
#define ERA_DESCRIPTION_N_SEGMENTS 0
|
||||
|
||||
static const gchar *
|
||||
get_month_name_standalone (gint month)
|
||||
{
|
||||
@ -2865,6 +2880,131 @@ initialize_alt_digits (void)
|
||||
}
|
||||
#endif /* HAVE_LANGINFO_OUTDIGIT */
|
||||
|
||||
/* Look up the era which contains @datetime, in the ERA description from libc
|
||||
* which corresponds to the currently set LC_TIME locale. The ERA is parsed and
|
||||
* cached the first time this function is called (or when LC_TIME changes).
|
||||
* See nl_langinfo(3).
|
||||
*
|
||||
* The return value is (transfer full). */
|
||||
static GEraDescriptionSegment *
|
||||
date_time_lookup_era (GDateTime *datetime,
|
||||
gboolean locale_is_utf8)
|
||||
{
|
||||
static GMutex era_mutex;
|
||||
static GPtrArray *static_era_description = NULL; /* (mutex era_mutex) (element-type GEraDescriptionSegment) */
|
||||
static const char *static_era_description_locale = NULL; /* (mutex era_mutex) */
|
||||
const char *current_lc_time = setlocale (LC_TIME, NULL);
|
||||
GPtrArray *local_era_description; /* (element-type GEraDescriptionSegment) */
|
||||
GEraDate datetime_date;
|
||||
|
||||
g_mutex_lock (&era_mutex);
|
||||
|
||||
if (static_era_description_locale != current_lc_time)
|
||||
{
|
||||
const char *era_description_str;
|
||||
size_t era_description_str_len;
|
||||
char *tmp = NULL;
|
||||
|
||||
era_description_str = ERA_DESCRIPTION;
|
||||
if (era_description_str != NULL)
|
||||
{
|
||||
/* FIXME: glibc 2.37 seems to return the era segments nul-separated rather
|
||||
* than semicolon-separated (which is what nl_langinfo(3) specifies).
|
||||
* Fix that up before sending it to the parsing code.
|
||||
* See https://sourceware.org/bugzilla/show_bug.cgi?id=31030*/
|
||||
{
|
||||
/* Work out the length of the whole description string, regardless
|
||||
* of whether it uses nuls or semicolons as separators. */
|
||||
int n_entries = ERA_DESCRIPTION_N_SEGMENTS;
|
||||
const char *s = era_description_str;
|
||||
|
||||
for (int i = 1; i < n_entries; i++)
|
||||
{
|
||||
const char *next_semicolon = strchr (s, ';');
|
||||
const char *next_nul = strchr (s, '\0');
|
||||
|
||||
if (next_semicolon != NULL && next_semicolon < next_nul)
|
||||
s = next_semicolon + 1;
|
||||
else
|
||||
s = next_nul + 1;
|
||||
}
|
||||
|
||||
era_description_str_len = strlen (s) + (s - era_description_str);
|
||||
|
||||
/* Replace all the nuls with semicolons. */
|
||||
era_description_str = tmp = g_memdup2 (era_description_str, era_description_str_len + 1);
|
||||
s = era_description_str;
|
||||
|
||||
for (int i = 1; i < n_entries; i++)
|
||||
{
|
||||
char *next_nul = strchr (s, '\0');
|
||||
|
||||
if ((size_t) (next_nul - era_description_str) >= era_description_str_len)
|
||||
break;
|
||||
|
||||
*next_nul = ';';
|
||||
s = next_nul + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert from the LC_TIME encoding to UTF-8 if needed. */
|
||||
if (!locale_is_utf8 && ERA_DESCRIPTION_IS_LOCALE)
|
||||
{
|
||||
char *tmp2 = NULL;
|
||||
era_description_str = tmp2 = g_locale_to_utf8 (era_description_str, -1, NULL, NULL, NULL);
|
||||
g_free (tmp);
|
||||
tmp = g_steal_pointer (&tmp2);
|
||||
}
|
||||
|
||||
g_clear_pointer (&static_era_description, g_ptr_array_unref);
|
||||
|
||||
if (era_description_str != NULL)
|
||||
static_era_description = _g_era_description_parse (era_description_str);
|
||||
}
|
||||
|
||||
if (static_era_description == NULL)
|
||||
g_warning ("Could not parse ERA description: %s", era_description_str);
|
||||
|
||||
g_free (tmp);
|
||||
|
||||
static_era_description_locale = current_lc_time;
|
||||
}
|
||||
|
||||
if (static_era_description == NULL)
|
||||
{
|
||||
g_mutex_unlock (&era_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
local_era_description = g_ptr_array_ref (static_era_description);
|
||||
g_mutex_unlock (&era_mutex);
|
||||
|
||||
/* Search through the eras and see if one matches. */
|
||||
datetime_date.type = G_ERA_DATE_SET;
|
||||
datetime_date.year = g_date_time_get_year (datetime);
|
||||
datetime_date.month = g_date_time_get_month (datetime);
|
||||
datetime_date.day = g_date_time_get_day_of_month (datetime);
|
||||
|
||||
for (unsigned int i = 0; i < local_era_description->len; i++)
|
||||
{
|
||||
GEraDescriptionSegment *segment = g_ptr_array_index (local_era_description, i);
|
||||
|
||||
if ((_g_era_date_compare (&segment->start_date, &datetime_date) <= 0 &&
|
||||
_g_era_date_compare (&datetime_date, &segment->end_date) <= 0) ||
|
||||
(_g_era_date_compare (&segment->end_date, &datetime_date) <= 0 &&
|
||||
_g_era_date_compare (&datetime_date, &segment->start_date) <= 0))
|
||||
{
|
||||
/* @datetime is within this era segment. */
|
||||
g_ptr_array_unref (local_era_description);
|
||||
return _g_era_description_segment_ref (segment);
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_unref (local_era_description);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
format_number (GString *str,
|
||||
gboolean use_alt_digits,
|
||||
@ -3043,6 +3183,7 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
guint colons;
|
||||
gunichar c;
|
||||
gboolean alt_digits = FALSE;
|
||||
gboolean alt_era = FALSE;
|
||||
gboolean pad_set = FALSE;
|
||||
gboolean mod_case = FALSE;
|
||||
gboolean name_is_utf8;
|
||||
@ -3069,6 +3210,7 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
|
||||
colons = 0;
|
||||
alt_digits = FALSE;
|
||||
alt_era = FALSE;
|
||||
pad_set = FALSE;
|
||||
mod_case = FALSE;
|
||||
|
||||
@ -3129,14 +3271,31 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
if (g_strcmp0 (PREFERRED_DATE_TIME_FMT, "") == 0)
|
||||
const char *subformat = alt_era ? PREFERRED_ERA_DATE_TIME_FMT : PREFERRED_DATE_TIME_FMT;
|
||||
|
||||
/* Fallback */
|
||||
if (alt_era && g_strcmp0 (subformat, "") == 0)
|
||||
subformat = PREFERRED_DATE_TIME_FMT;
|
||||
|
||||
if (g_strcmp0 (subformat, "") == 0)
|
||||
return FALSE;
|
||||
if (!g_date_time_format_locale (datetime, PREFERRED_DATE_TIME_FMT,
|
||||
if (!g_date_time_format_locale (datetime, subformat,
|
||||
outstr, locale_is_utf8))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (alt_era)
|
||||
{
|
||||
GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
|
||||
if (era != NULL)
|
||||
{
|
||||
g_string_append (outstr, era->era_name);
|
||||
_g_era_description_segment_unref (era);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
|
||||
g_date_time_get_year (datetime) / 100);
|
||||
break;
|
||||
@ -3214,6 +3373,9 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
case 'O':
|
||||
alt_digits = TRUE;
|
||||
goto next_mod;
|
||||
case 'E':
|
||||
alt_era = TRUE;
|
||||
goto next_mod;
|
||||
case 'p':
|
||||
if (!format_ampm (datetime, outstr, locale_is_utf8,
|
||||
mod_case && g_strcmp0 (mod, "#") == 0 ? FALSE
|
||||
@ -3270,29 +3432,78 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
break;
|
||||
case 'x':
|
||||
{
|
||||
if (g_strcmp0 (PREFERRED_DATE_FMT, "") == 0)
|
||||
const char *subformat = alt_era ? PREFERRED_ERA_DATE_FMT : PREFERRED_DATE_FMT;
|
||||
|
||||
/* Fallback */
|
||||
if (alt_era && g_strcmp0 (subformat, "") == 0)
|
||||
subformat = PREFERRED_DATE_FMT;
|
||||
|
||||
if (g_strcmp0 (subformat, "") == 0)
|
||||
return FALSE;
|
||||
if (!g_date_time_format_locale (datetime, PREFERRED_DATE_FMT,
|
||||
if (!g_date_time_format_locale (datetime, subformat,
|
||||
outstr, locale_is_utf8))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
{
|
||||
if (g_strcmp0 (PREFERRED_TIME_FMT, "") == 0)
|
||||
const char *subformat = alt_era ? PREFERRED_ERA_TIME_FMT : PREFERRED_TIME_FMT;
|
||||
|
||||
/* Fallback */
|
||||
if (alt_era && g_strcmp0 (subformat, "") == 0)
|
||||
subformat = PREFERRED_TIME_FMT;
|
||||
|
||||
if (g_strcmp0 (subformat, "") == 0)
|
||||
return FALSE;
|
||||
if (!g_date_time_format_locale (datetime, PREFERRED_TIME_FMT,
|
||||
if (!g_date_time_format_locale (datetime, subformat,
|
||||
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);
|
||||
if (alt_era)
|
||||
{
|
||||
GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
|
||||
if (era != NULL)
|
||||
{
|
||||
int delta = g_date_time_get_year (datetime) - era->start_date.year;
|
||||
|
||||
/* Both these years are in the Gregorian calendar (CE/BCE),
|
||||
* which has no year zero. So take one from the delta if they
|
||||
* cross across where year zero would be. */
|
||||
if ((g_date_time_get_year (datetime) < 0) != (era->start_date.year < 0))
|
||||
delta -= 1;
|
||||
|
||||
format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
|
||||
era->offset + delta * era->direction_multiplier);
|
||||
_g_era_description_segment_unref (era);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
if (alt_era)
|
||||
{
|
||||
GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
|
||||
if (era != NULL)
|
||||
{
|
||||
if (!g_date_time_format_utf8 (datetime, era->era_format,
|
||||
outstr, locale_is_utf8))
|
||||
{
|
||||
_g_era_description_segment_unref (era);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_g_era_description_segment_unref (era);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
format_number (outstr, alt_digits, 0, 0,
|
||||
g_date_time_get_year (datetime));
|
||||
break;
|
||||
case 'z':
|
||||
{
|
||||
@ -3461,6 +3672,22 @@ g_date_time_format_utf8 (GDateTime *datetime,
|
||||
* `strftime()` extension expected to be added to the future POSIX specification,
|
||||
* `%Ob` and `%Oh` are GNU `strftime()` extensions. Since: 2.56
|
||||
*
|
||||
* Since GLib 2.80, when `E` is used with `%c`, `%C`, `%x`, `%X`, `%y` or `%Y`,
|
||||
* the date is formatted using an alternate era representation specific to the
|
||||
* locale. This is typically used for the Thai solar calendar or Japanese era
|
||||
* names, for example.
|
||||
*
|
||||
* - `%Ec`: the preferred date and time representation for the current locale,
|
||||
* using the alternate era representation
|
||||
* - `%EC`: the name of the era
|
||||
* - `%Ex`: the preferred date representation for the current locale without
|
||||
* the time, using the alternate era representation
|
||||
* - `%EX`: the preferred time representation for the current locale without
|
||||
* the date, using the alternate era representation
|
||||
* - `%Ey`: the year since the beginning of the era denoted by the `%EC`
|
||||
* specifier
|
||||
* - `%EY`: the full alternative year representation
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a newly allocated string formatted to
|
||||
* the requested format or %NULL in the case that there was an error (such
|
||||
* as a format specifier not being supported in the current locale). The
|
||||
|
@ -277,6 +277,7 @@ glib_sources += files(
|
||||
'gdataset.c',
|
||||
'gdate.c',
|
||||
'gdatetime.c',
|
||||
'gdatetime-private.c',
|
||||
'gdir.c',
|
||||
'genviron.c',
|
||||
'gerror.c',
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* gdatetime-tests.c
|
||||
*
|
||||
* Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
|
||||
* Copyright 2023 Philip Withnall
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
@ -28,6 +29,8 @@
|
||||
#include <glib/gstdio.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "gdatetime-private.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
@ -1718,6 +1721,12 @@ test_non_utf8_printf (void)
|
||||
TEST_PRINTF ("%%", "%");
|
||||
TEST_PRINTF ("%", "");
|
||||
TEST_PRINTF ("%9", NULL);
|
||||
TEST_PRINTF ("%Ec", "平成21年10月24日 00時00分00秒");
|
||||
TEST_PRINTF ("%EC", "平成");
|
||||
TEST_PRINTF ("%Ex", "平成21年10月24日");
|
||||
TEST_PRINTF ("%EX", "00時00分00秒");
|
||||
TEST_PRINTF ("%Ey", "21");
|
||||
TEST_PRINTF ("%EY", "平成21年");
|
||||
|
||||
setlocale (LC_ALL, oldlocale);
|
||||
g_free (oldlocale);
|
||||
@ -1873,6 +1882,30 @@ test_modifiers (void)
|
||||
g_test_skip ("langinfo not available, skipping O modifier tests");
|
||||
#endif
|
||||
|
||||
setlocale (LC_ALL, "en_GB.utf-8");
|
||||
if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
|
||||
{
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%c", "thu 01 jan 2009 00:00:00 utc");
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%Ec", "thu 01 jan 2009 00:00:00 utc");
|
||||
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%C", "20");
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%EC", "20");
|
||||
|
||||
TEST_PRINTF_DATE (2009, 1, 2, "%x", "02/01/09");
|
||||
TEST_PRINTF_DATE (2009, 1, 2, "%Ex", "02/01/09");
|
||||
|
||||
TEST_PRINTF_TIME (1, 2, 3, "%X", "01:02:03");
|
||||
TEST_PRINTF_TIME (1, 2, 3, "%EX", "01:02:03");
|
||||
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%y", "09");
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%Ey", "09");
|
||||
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%Y", "2009");
|
||||
TEST_PRINTF_DATE (2009, 1, 1, "%EY", "2009");
|
||||
}
|
||||
else
|
||||
g_test_skip ("locale en_GB not available, skipping E modifier tests");
|
||||
|
||||
setlocale (LC_ALL, oldlocale);
|
||||
g_free (oldlocale);
|
||||
}
|
||||
@ -2212,6 +2245,164 @@ test_all_dates (void)
|
||||
g_time_zone_unref (timezone);
|
||||
}
|
||||
|
||||
static void
|
||||
test_date_time_eras_japan (void)
|
||||
{
|
||||
gchar *oldlocale;
|
||||
|
||||
oldlocale = g_strdup (setlocale (LC_ALL, NULL));
|
||||
setlocale (LC_ALL, "ja_JP.utf-8");
|
||||
if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL)
|
||||
{
|
||||
g_test_skip ("locale ja_JP.utf-8 not available, skipping Japanese era tests");
|
||||
g_free (oldlocale);
|
||||
return;
|
||||
}
|
||||
|
||||
/* See https://en.wikipedia.org/wiki/Japanese_era_name
|
||||
* First test the Reiwa era (令和) */
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "令和05年06月01日 00時00分00秒");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EC", "令和");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ex", "令和05年06月01日");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00時00分00秒");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "05");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EY", "令和05年");
|
||||
|
||||
/* Heisei era (平成) */
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%Ec", "平成31年04月30日 00時00分00秒");
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%EC", "平成");
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%Ex", "平成31年04月30日");
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%EX", "00時00分00秒");
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%Ey", "31");
|
||||
TEST_PRINTF_DATE (2019, 04, 30, "%EY", "平成31年");
|
||||
|
||||
/* Shōwa era (昭和) */
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%Ec", "昭和元年12月25日 00時00分00秒");
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%EC", "昭和");
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%Ex", "昭和元年12月25日");
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%EX", "00時00分00秒");
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%Ey", "01");
|
||||
TEST_PRINTF_DATE (1926, 12, 25, "%EY", "昭和元年");
|
||||
|
||||
setlocale (LC_ALL, oldlocale);
|
||||
g_free (oldlocale);
|
||||
}
|
||||
|
||||
static void
|
||||
test_date_time_eras_thailand (void)
|
||||
{
|
||||
gchar *oldlocale;
|
||||
|
||||
oldlocale = g_strdup (setlocale (LC_ALL, NULL));
|
||||
setlocale (LC_ALL, "th_TH.utf-8");
|
||||
if (strstr (setlocale (LC_ALL, NULL), "th_TH") == NULL)
|
||||
{
|
||||
g_test_skip ("locale th_TH.utf-8 not available, skipping Thai era tests");
|
||||
g_free (oldlocale);
|
||||
return;
|
||||
}
|
||||
|
||||
/* See https://en.wikipedia.org/wiki/Thai_solar_calendar */
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "วันพฤหัสบดีที่ 1 มิถุนายน พ.ศ. 2566, 00.00.00 น.");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EC", "พ.ศ.");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ex", " 1 มิ.ย. 2566");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00.00.00 น.");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "2566");
|
||||
TEST_PRINTF_DATE (2023, 06, 01, "%EY", "พ.ศ. 2566");
|
||||
|
||||
TEST_PRINTF_DATE (01, 06, 01, "%Ex", " 1 มิ.ย. 544");
|
||||
|
||||
setlocale (LC_ALL, oldlocale);
|
||||
g_free (oldlocale);
|
||||
}
|
||||
|
||||
static void
|
||||
test_date_time_eras_parsing (void)
|
||||
{
|
||||
struct
|
||||
{
|
||||
const char *desc;
|
||||
gboolean expected_success;
|
||||
size_t expected_n_segments;
|
||||
}
|
||||
vectors[] =
|
||||
{
|
||||
/* Some successful parsing: */
|
||||
{ "", TRUE, 0 },
|
||||
/* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/th_TH#L233: */
|
||||
{ "+:1:-543/01/01:+*:พ.ศ.:%EC %Ey", TRUE, 1 },
|
||||
/* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/ja_JP#L14967C5-L14977C60: */
|
||||
{ "+:2:2020/01/01:+*:令和:%EC%Ey年;"
|
||||
"+:1:2019/05/01:2019/12/31:令和:%EC元年;"
|
||||
"+:2:1990/01/01:2019/04/30:平成:%EC%Ey年;"
|
||||
"+:1:1989/01/08:1989/12/31:平成:%EC元年;"
|
||||
"+:2:1927/01/01:1989/01/07:昭和:%EC%Ey年;"
|
||||
"+:1:1926/12/25:1926/12/31:昭和:%EC元年;"
|
||||
"+:2:1913/01/01:1926/12/24:大正:%EC%Ey年;"
|
||||
"+:1:1912/07/30:1912/12/31:大正:%EC元年;"
|
||||
"+:6:1873/01/01:1912/07/29:明治:%EC%Ey年;"
|
||||
"+:1:0001/01/01:1872/12/31:西暦:%EC%Ey年;"
|
||||
"+:1:-0001/12/31:-*:紀元前:%EC%Ey年", TRUE, 11 },
|
||||
{ "-:2:2020/01/01:-*:令和:%EC%Ey年", TRUE, 1 },
|
||||
{ "+:2:2020/01/01:2020/01/01:令和:%EC%Ey年", TRUE, 1 },
|
||||
{ "+:2:+2020/01/01:+*:令和:%EC%Ey年", TRUE, 1 },
|
||||
/* Some errors: */
|
||||
{ ".:2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+.2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+", FALSE, 0 },
|
||||
{ "+:", FALSE, 0 },
|
||||
{ "+::", FALSE, 0 },
|
||||
{ "+:200", FALSE, 0 },
|
||||
{ "+:2nonsense", FALSE, 0 },
|
||||
{ "+:2nonsense:", FALSE, 0 },
|
||||
{ "+:2:", FALSE, 0 },
|
||||
{ "+:2::", FALSE, 0 },
|
||||
{ "+:2:2020-01/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020nonsense/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:18446744073709551615/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01-01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01nonsense/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/00/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/13/01:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01/00:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01/32:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01/01nonsense:+*:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01/01", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:", FALSE, 0 },
|
||||
{ "+:2:2020/01/01::", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:2021-01-01:令和:%EC%Ey年", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*:", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*::", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*:令和", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*:令和:", FALSE, 0 },
|
||||
{ "+:2:2020/01/01:+*:令和:;", FALSE, 0 },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < G_N_ELEMENTS (vectors); i++)
|
||||
{
|
||||
GPtrArray *segments = NULL;
|
||||
|
||||
g_test_message ("Vector %" G_GSIZE_FORMAT ": %s", i, vectors[i].desc);
|
||||
|
||||
segments = _g_era_description_parse (vectors[i].desc);
|
||||
|
||||
if (vectors[i].expected_success)
|
||||
{
|
||||
g_assert_nonnull (segments);
|
||||
g_assert_cmpuint (segments->len, ==, vectors[i].expected_n_segments);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_null (segments);
|
||||
}
|
||||
|
||||
g_clear_pointer (&segments, g_ptr_array_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_z (void)
|
||||
{
|
||||
@ -3249,6 +3440,10 @@ main (gint argc,
|
||||
g_test_add_func ("/GDateTime/dst", test_GDateTime_dst);
|
||||
g_test_add_func ("/GDateTime/test_z", test_z);
|
||||
g_test_add_func ("/GDateTime/test-all-dates", test_all_dates);
|
||||
g_test_add_func ("/GDateTime/eras/japan", test_date_time_eras_japan);
|
||||
g_test_add_func ("/GDateTime/eras/thailand", test_date_time_eras_thailand);
|
||||
g_test_add_func ("/GDateTime/eras/parsing", test_date_time_eras_parsing);
|
||||
|
||||
g_test_add_func ("/GTimeZone/find-interval", test_find_interval);
|
||||
g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time);
|
||||
g_test_add_func ("/GTimeZone/no-header", test_no_header);
|
||||
|
@ -40,6 +40,7 @@ glib_tests = {
|
||||
'error' : {},
|
||||
'fileutils' : {},
|
||||
'gdatetime' : {
|
||||
'source' : ['gdatetime.c', '../gdatetime-private.c'],
|
||||
'suite' : ['slow'],
|
||||
# musl: GDateTime/format_mixed/non_utf8_time_non_utf8_messages should be
|
||||
# skipped but it's not. The fix should be on musl side:
|
||||
|
@ -1311,6 +1311,11 @@ if cc.links('''#include <langinfo.h>
|
||||
str = nl_langinfo (ABMON_12);
|
||||
str = nl_langinfo (DAY_1);
|
||||
str = nl_langinfo (ABDAY_7);
|
||||
str = nl_langinfo (ERA);
|
||||
str = nl_langinfo (ERA_D_T_FMT);
|
||||
str = nl_langinfo (ERA_D_FMT);
|
||||
str = nl_langinfo (ERA_T_FMT);
|
||||
str = nl_langinfo (_NL_TIME_ERA_NUM_ENTRIES);
|
||||
return 0;
|
||||
}''', name : 'nl_langinfo (PM_STR)')
|
||||
glib_conf.set('HAVE_LANGINFO_TIME', 1)
|
||||
|
Loading…
Reference in New Issue
Block a user