From 47938d1a2cc7f3abb74b08c3c14c08c2786f58a3 Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Wed, 11 Feb 2026 18:43:21 +0800 Subject: [PATCH] [gnc-date.cpp] gnc_date_interval_format localisable with ICU --- bindings/engine.i | 3 ++ libgnucash/engine/gnc-date.cpp | 67 ++++++++++++++++++++++++++++++++++ libgnucash/engine/gnc-date.h | 2 + 3 files changed, 72 insertions(+) diff --git a/bindings/engine.i b/bindings/engine.i index 5b1d5b587c..8e9bce0d6e 100644 --- a/bindings/engine.i +++ b/bindings/engine.i @@ -116,6 +116,9 @@ engine-common.i */ %newobject xaccTransGetPaymentAcctSplitList; %newobject xaccAccountGetSplitList; +%newobject gnc_date_interval_format; +gchar* gnc_date_interval_format (time64 from_date, time64 to_date); + %include "engine-common.i" #if defined(SWIGGUILE) diff --git a/libgnucash/engine/gnc-date.cpp b/libgnucash/engine/gnc-date.cpp index 0f46cfcf87..cd5e64ba3f 100644 --- a/libgnucash/engine/gnc-date.cpp +++ b/libgnucash/engine/gnc-date.cpp @@ -45,6 +45,8 @@ #include #include +#include "unicode/dtitvfmt.h" +#include "unicode/smpdtfmt.h" #include "gnc-date.h" #include "gnc-date-p.h" @@ -613,6 +615,71 @@ qof_print_date (time64 t) return g_strdup (buff); } +static icu::DateIntervalFormat* +get_icu_date_interval_formatter () +{ + static std::unique_ptr difmt; + if (!difmt) + { + auto locale = icu::Locale::getDefault(); + UErrorCode status = U_ZERO_ERROR; + difmt.reset(icu::DateIntervalFormat::createInstance(UDAT_YEAR_NUM_MONTH_DAY, locale, status)); + if (U_FAILURE(status)) + { + PWARN ("icu::DateIntervalFormat::createInstance error %d", status); + return nullptr; + } + } + return difmt.get(); +} + +static gchar* +icu_date_interval_format (time64 from_date, time64 to_date) +{ + auto difmt = get_icu_date_interval_formatter(); + if (!difmt) + return nullptr; + + if (from_date > to_date) + std::swap(from_date, to_date); + + icu::DateInterval interval (from_date * 1000.0, to_date * 1000.0); + icu::UnicodeString result; + icu::FieldPosition fp; + UErrorCode status = U_ZERO_ERROR; + difmt->format (&interval, result, fp, status); + if (U_FAILURE(status)) + { + PWARN("Error formatting interval: %d", status); + return nullptr; + } + + std::string interval_string; + result.toUTF8String(interval_string); + + return g_strdup (interval_string.c_str()); +} + +gchar* +gnc_date_interval_format (time64 from_date, time64 to_date) +{ + gchar* rv = nullptr; + + if (qof_date_format_get() == QOF_DATE_FORMAT_LOCALE) + rv = icu_date_interval_format (from_date, to_date); + + // not using locale, or icu failure + if (!rv) + { + gchar from_buff[MAX_DATE_LENGTH+1], to_buff[MAX_DATE_LENGTH+1]; + qof_print_date_buff (from_buff, MAX_DATE_LENGTH, from_date); + qof_print_date_buff (to_buff, MAX_DATE_LENGTH, to_date); + rv = g_strdup_printf (gettext("%s to %s"), from_buff, to_buff); + } + + return rv; +} + /* ============================================================== */ /* return the greatest integer <= a/b; works for b > 0 and positive or diff --git a/libgnucash/engine/gnc-date.h b/libgnucash/engine/gnc-date.h index d44bc2b289..3b4a50825e 100644 --- a/libgnucash/engine/gnc-date.h +++ b/libgnucash/engine/gnc-date.h @@ -482,6 +482,8 @@ size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd); char * qof_print_date (time64 secs); +gchar* gnc_date_interval_format (time64 from_date, time64 to_date); + /* ------------------------------------------------------------------ */ /* time printing utilities */