forms/source/component/DatabaseForm.cxx |   94 +++++++++++++++++++++++++++-----
 forms/source/component/DatabaseForm.hxx |    4 +
 2 files changed, 86 insertions(+), 12 deletions(-)

New commits:
commit 3b22e7c3aa0e601e5fae4716e4e354f07e07b05f
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Jul 20 23:34:03 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Mon Jul 21 08:18:23 2025 +0200

    tdf#167591: Convert date string to date early
    
    To insert a default value, ODatabaseForm gets its value from column
    properties, and passes to XColumnUpdate. The problem appeared when
    the default was a localized date string, like "20/07/25".
    
    The string was set as the value of a ORowSetValue; then, when its
    value was requested, its getDate() called DBTypeConversion::toDate,
    which only handles ISO date strings. But for correct conversion, not
    only the string is needed, but also its format key. This information
    is already lost at that point. The conversion failed, and the result
    date was invalid, somewhere in the beginning of CE.
    
    Try to overcome this problem by converting the default value from
    date string to date(time) where all the information is available.
    
    Change-Id: I73e96e433895da18cbf6145ffc26b16fa4844452
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188093
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/forms/source/component/DatabaseForm.cxx 
b/forms/source/component/DatabaseForm.cxx
index 18d0d854da57..2ebab406beac 100644
--- a/forms/source/component/DatabaseForm.cxx
+++ b/forms/source/component/DatabaseForm.cxx
@@ -53,11 +53,13 @@
 #include <com/sun/star/sdbc/XRowSet.hpp>
 #include <com/sun/star/sdbcx/Privilege.hpp>
 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
 #include <com/sun/star/util/URLTransformer.hpp>
 #include <com/sun/star/util/XURLTransformer.hpp>
 #include <com/sun/star/util/XModifiable2.hpp>
 
 #include <comphelper/basicio.hxx>
+#include <comphelper/numbers.hxx>
 #include <comphelper/property.hxx>
 #include <comphelper/seqstream.hxx>
 #include <comphelper/sequence.hxx>
@@ -68,6 +70,7 @@
 #include <rtl/math.hxx>
 #include <rtl/tencinfo.h>
 #include <svl/inettype.hxx>
+#include <svl/numformat.hxx>
 #include <tools/datetime.hxx>
 #include <tools/debug.hxx>
 #include <comphelper/diagnose_ex.hxx>
@@ -1923,6 +1926,70 @@ void SAL_CALL ODatabaseForm::reset()
     }
 }
 
+Reference<XNumberFormatter> ODatabaseForm::getFormatter()
+{
+    if (auto xSupplier = dbtools::getNumberFormats(getConnection(), true, 
m_xContext))
+    {
+        auto result = NumberFormatter::create(m_xContext);
+        result->attachNumberFormatsSupplier(xSupplier);
+        return result;
+    }
+    return {};
+}
+
+static void maybeConvertDefaultStringToDate(Any& def, const auto& 
getFieldPropOrDefault,
+                                            const auto& getFormatter)
+{
+    OUString sDefault;
+    if (!(def >>= sDefault))
+        return;
+
+    sal_Int32 dataType = getFieldPropOrDefault(PROPERTY_FIELDTYPE, 
sal_Int32());
+    if (dataType != css::sdbc::DataType::DATE && dataType != 
css::sdbc::DataType::TIMESTAMP)
+        return;
+
+    Reference<XNumberFormatter> xFormatter = getFormatter();
+    if (!xFormatter)
+        return;
+
+    // Convert to a date
+    sal_uInt32 nFormatKey = xFormatter->detectNumberFormat(
+        getFieldPropOrDefault(PROPERTY_FORMATKEY, sal_uInt32()), sDefault);
+    sal_Int16 nType = comphelper::getNumberFormatType(xFormatter, nFormatKey);
+    if ((nType & css::util::NumberFormat::DATE) == 0)
+        return;
+
+    Reference<XNumberFormatsSupplier> xSupplier = 
xFormatter->getNumberFormatsSupplier();
+    css::util::Date aNull;
+    try
+    {
+        if 
(!(xSupplier->getNumberFormatSettings()->getPropertyValue(u"NullDate"_ustr) >>= 
aNull))
+            return;
+    }
+    catch (const Exception&)
+    {
+        return;
+    }
+    ::Date d(aNull);
+
+    double value = xFormatter->convertStringToNumber(nFormatKey, sDefault);
+    switch (dataType)
+    {
+        case css::sdbc::DataType::DATE:
+        {
+            d.AddDays(value);
+            def <<= d.GetUNODate();
+            break;
+        }
+        case css::sdbc::DataType::TIMESTAMP:
+        {
+            ::DateTime dt(d);
+            dt.AddTime(value);
+            def <<= dt.GetUNODateTime();
+            break;
+        }
+    }
+}
 
 void ODatabaseForm::reset_impl(bool _bApproveByListeners)
 {
@@ -1956,24 +2023,27 @@ void ODatabaseForm::reset_impl(bool 
_bApproveByListeners)
                 if ( !xColUpdate.is() )
                     continue;
 
-                Reference< XPropertySetInfo > xPSI;
-                if ( xColProps.is() )
-                    xPSI = xColProps->getPropertySetInfo( );
-
-                static constexpr OUString PROPERTY_CONTROLDEFAULT = 
u"ControlDefault"_ustr;
-                if (!xPSI || !xPSI->hasPropertyByName(PROPERTY_CONTROLDEFAULT))
-                    continue;
+                auto getPropValOrDefault = [&xColProps, xPSI = 
xColProps->getPropertySetInfo()](
+                                               const OUString& propname, auto 
default_value)
+                {
+                    if (xPSI && xPSI->hasPropertyByName(propname))
+                        fromAny(xColProps->getPropertyValue(propname), 
&default_value);
+                    return default_value;
+                };
 
-                Any aDefault = xColProps->getPropertyValue( 
PROPERTY_CONTROLDEFAULT );
+                Any aDefault = getPropValOrDefault(u"ControlDefault"_ustr, 
Any());
                 if (!aDefault.hasValue())
                     continue;
 
-                bool bReadOnly = false;
-                if ( xPSI->hasPropertyByName( PROPERTY_ISREADONLY ) )
-                    xColProps->getPropertyValue( PROPERTY_ISREADONLY ) >>= 
bReadOnly;
-                if (bReadOnly)
+                if (getPropValOrDefault(PROPERTY_ISREADONLY, false))
                     continue;
 
+                // If the column is a date, and the default is a string, it 
may be
+                // impossible to convert the string to date at a later stage 
(namely, in
+                // DBTypeConversion::getValue, where the column formatting is 
unknown).
+                maybeConvertDefaultStringToDate(aDefault, getPropValOrDefault,
+                                                [this]() { return 
getFormatter(); });
+
                 try
                 {
                     xColUpdate->updateObject( aDefault );
diff --git a/forms/source/component/DatabaseForm.hxx 
b/forms/source/component/DatabaseForm.hxx
index 73831a9c67ba..a9c4badb6545 100644
--- a/forms/source/component/DatabaseForm.hxx
+++ b/forms/source/component/DatabaseForm.hxx
@@ -54,6 +54,7 @@
 #include <com/sun/star/beans/XPropertyContainer.hpp>
 #include <com/sun/star/beans/XPropertyAccess.hpp>
 #include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
 
 
 #include <tools/link.hxx>
@@ -518,6 +519,9 @@ private:
     void    impl_construct();
 
     DECL_LINK( OnTimeout, Timer*, void );
+
+    css::uno::Reference<css::util::XNumberFormatter> getFormatter();
+
 protected:
     using OPropertySetHelper::getPropertyValues;
 };

Reply via email to