connectivity/source/drivers/dbase/DTable.cxx   |    9 -
 i18npool/CppunitTest_i18npool_test_calendar.mk |   43 ++++++++
 i18npool/Module_i18npool.mk                    |    1 
 i18npool/inc/calendar_hijri.hxx                |   12 +-
 i18npool/qa/cppunit/test_calendar.cxx          |  130 +++++++++++++++++++++++++
 i18npool/source/calendar/calendar_hijri.cxx    |    8 -
 include/i18nutil/calendar.hxx                  |   23 ++++
 7 files changed, 212 insertions(+), 14 deletions(-)

New commits:
commit 0308e48e46cee2f56a6239c8479d26185146d74a
Author:     Hossein <hoss...@libreoffice.org>
AuthorDate: Fri Feb 25 00:22:11 2022 +0100
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Fri Feb 25 19:12:41 2022 +0100

    tdf#145759 30.6001 -> monthDaysWithoutJanFeb
    
    30.6001 shows month days without Jan and Feb.
    According to the below link, it is calcuated as (365-31-28)/10 = 30.6
    but because of a floating point bug, it was used as 30.6001 as a
    workaround.
    
    "30.6001, 25 year old hack?"
    https://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/archv011.cgi?read=31650
    
    The value 30.6 is used as i18nutil::monthDaysWithoutJanFeb here
    instead of 30.6001. The new value is ~30.60000038 which is > 30.6, so
    the calculations should be correct. In order to make sure, a unit test
    is added, and part of the values are checked against the values
    calculated by this website:
    
    Julian Day and Civil Date Calculator
    https://core2.gsfc.nasa.gov/time/julian.html
    
    Change-Id: I8cc7e046514dc3de652a1c37399e351cb2b614dc
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125813
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <er...@redhat.com>

diff --git a/connectivity/source/drivers/dbase/DTable.cxx 
b/connectivity/source/drivers/dbase/DTable.cxx
index 0f8f72328a0b..d7a5b1c458a6 100644
--- a/connectivity/source/drivers/dbase/DTable.cxx
+++ b/connectivity/source/drivers/dbase/DTable.cxx
@@ -54,6 +54,7 @@
 #include <rtl/strbuf.hxx>
 #include <sal/log.hxx>
 #include <tools/date.hxx>
+#include <i18nutil/calendar.hxx>
 
 #include <algorithm>
 #include <cassert>
@@ -132,13 +133,13 @@ void lcl_CalcJulDate(sal_Int32& _nJulianDate,sal_Int32& 
_nJulianTime, const css:
     if ( aDateTime.Year <= 0 )
     {
         _nJulianDate = static_cast<sal_Int32>((365.25 * iy0) - 0.75)
-            + static_cast<sal_Int32>(30.6001 * (im0 + 1) )
+            + static_cast<sal_Int32>(i18nutil::monthDaysWithoutJanFeb * (im0 + 
1) )
             + aDateTime.Day + 1720994;
     } // if ( rDateTime.Year <= 0 )
     else
     {
         _nJulianDate = static_cast<sal_Int32>(365.25 * iy0)
-            + static_cast<sal_Int32>(30.6001 * (im0 + 1))
+            + static_cast<sal_Int32>(i18nutil::monthDaysWithoutJanFeb * (im0 + 
1))
             + aDateTime.Day + 1720994;
     }
     double JD = _nJulianDate + 0.5;
@@ -164,8 +165,8 @@ void lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 
_nJulianTime,css::util::DateTi
         sal_Int64 kb = ka + 1524;
         sal_Int64 kc = static_cast<sal_Int64>((static_cast<double>(kb) - 
122.1) / 365.25);
         sal_Int64 kd = static_cast<sal_Int64>(static_cast<double>(kc) * 
365.25);
-        sal_Int64 ke = static_cast<sal_Int64>(static_cast<double>(kb - kd) / 
30.6001);
-        _rDateTime.Day = static_cast<sal_uInt16>(kb - kd - 
static_cast<sal_Int64>( static_cast<double>(ke) * 30.6001 ));
+        sal_Int64 ke = static_cast<sal_Int64>(static_cast<double>(kb - kd) / 
i18nutil::monthDaysWithoutJanFeb);
+        _rDateTime.Day = static_cast<sal_uInt16>(kb - kd - 
static_cast<sal_Int64>( static_cast<double>(ke) * 
i18nutil::monthDaysWithoutJanFeb ));
         if ( ke > 13 )
             _rDateTime.Month = static_cast<sal_uInt16>(ke - 13);
         else
diff --git a/i18npool/CppunitTest_i18npool_test_calendar.mk 
b/i18npool/CppunitTest_i18npool_test_calendar.mk
new file mode 100644
index 000000000000..85a3b2fbb576
--- /dev/null
+++ b/i18npool/CppunitTest_i18npool_test_calendar.mk
@@ -0,0 +1,43 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,i18npool_test_calendar))
+
+$(eval $(call gb_CppunitTest_set_include,i18npool_test_calendar,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/i18npool/inc \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,i18npool_test_calendar))
+
+$(eval $(call gb_CppunitTest_use_libraries,i18npool_test_calendar,\
+       cppu \
+       cppuhelper \
+       sal \
+       unotest \
+    i18npool \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,i18npool_test_calendar,\
+    icui18n \
+    icuuc \
+    icu_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,i18npool_test_calendar,\
+    i18npool/qa/cppunit/test_calendar \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,i18npool_test_calendar))
+
+$(eval $(call gb_CppunitTest_use_components,i18npool_test_calendar,\
+       i18npool/util/i18npool \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/i18npool/Module_i18npool.mk b/i18npool/Module_i18npool.mk
index 271c751081da..1926fdd70d82 100644
--- a/i18npool/Module_i18npool.mk
+++ b/i18npool/Module_i18npool.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Module_add_check_targets,i18npool,\
        CppunitTest_i18npool_test_characterclassification \
        CppunitTest_i18npool_test_ordinalsuffix \
        CppunitTest_i18npool_test_textsearch \
+       CppunitTest_i18npool_test_calendar \
        CppunitTest_i18npool_defaultnumberingprovider \
 ))
 
diff --git a/i18npool/inc/calendar_hijri.hxx b/i18npool/inc/calendar_hijri.hxx
index b25c4cb0b44f..c02fa31e5d94 100644
--- a/i18npool/inc/calendar_hijri.hxx
+++ b/i18npool/inc/calendar_hijri.hxx
@@ -36,12 +36,12 @@ private:
     void mapToGregorian() override;
     void mapFromGregorian() override;
 
-private:
-    static double NewMoon(sal_Int32 n);
-    static void getHijri(sal_Int32 *day, sal_Int32 *month, sal_Int32 *year);
-    static void ToGregorian(sal_Int32 *day, sal_Int32 *month, sal_Int32 *year);
-    static void getGregorianDay(sal_Int32 jd, sal_Int32 *pnDay, sal_Int32 
*pnMonth, sal_Int32 *pnYear);
-    static sal_Int32 getJulianDay(sal_Int32 day, sal_Int32 month, sal_Int32 
year);
+public:
+    static double SAL_DLLPUBLIC_EXPORT NewMoon(sal_Int32 n);
+    static void SAL_DLLPUBLIC_EXPORT getHijri(sal_Int32 *day, sal_Int32 
*month, sal_Int32 *year);
+    static void SAL_DLLPUBLIC_EXPORT ToGregorian(sal_Int32 *day, sal_Int32 
*month, sal_Int32 *year);
+    static void SAL_DLLPUBLIC_EXPORT getGregorianDay(sal_Int32 jd, sal_Int32 
*pnDay, sal_Int32 *pnMonth, sal_Int32 *pnYear);
+    static sal_Int32 SAL_DLLPUBLIC_EXPORT getJulianDay(sal_Int32 day, 
sal_Int32 month, sal_Int32 year);
 };
 
 }
diff --git a/i18npool/qa/cppunit/test_calendar.cxx 
b/i18npool/qa/cppunit/test_calendar.cxx
new file mode 100644
index 000000000000..a522a4a74236
--- /dev/null
+++ b/i18npool/qa/cppunit/test_calendar.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include <calendar_hijri.hxx>
+#include <unotest/bootstrapfixturebase.hxx>
+
+using namespace com::sun::star;
+
+class TestCalendar : public test::BootstrapFixtureBase
+{
+public:
+    void testHijriGregorian();
+    void testGetGregorianJulianDay();
+
+    CPPUNIT_TEST_SUITE(TestCalendar);
+    CPPUNIT_TEST(testHijriGregorian);
+    CPPUNIT_TEST(testGetGregorianJulianDay);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+void TestCalendar::testHijriGregorian()
+{
+    // 21-7-1443 (Hijri) == 22-2-2022 (Gregorian)
+    sal_Int32 day = 22, month = 2, year = 2022;
+    i18npool::Calendar_hijri::getHijri(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(21), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(7), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1443), year);
+
+    i18npool::Calendar_hijri::ToGregorian(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(22), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2022), year);
+
+    // 1-1-1 (Hijri) == 15-7-622 (Gregorian)
+    // NOTE: The calculated date is 15-7-622, as it was with the
+    // previous version of i18npool::Calendar_hijri::ToGregorian()
+    // but in some articles, 15-7-622 is considered the equivalent date
+    // https://en.wikipedia.org/wiki/622
+    // This article states that 15-7-622 is correct:
+    // "On the Origins of the Hijrī Calendar: A Multi-Faceted Perspective
+    // Based on the Covenants of the Prophet and Specific Date Verification"
+    // https://www.mdpi.com/2077-1444/12/1/42/htm
+    day = 15;
+    month = 7;
+    year = 622;
+    i18npool::Calendar_hijri::getHijri(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), year);
+
+    i18npool::Calendar_hijri::ToGregorian(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(15), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(7), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(622), year);
+
+    // 1-1-100 (Hijri) == 2-8-718 (Gregorian)
+    // https://habibur.com/hijri/100/
+    day = 2;
+    month = 8;
+    year = 718;
+    i18npool::Calendar_hijri::getHijri(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(100), year);
+
+    i18npool::Calendar_hijri::ToGregorian(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(8), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(718), year);
+
+    // 1-1-1000 (Hijri) == 19-10-1591 (Gregorian)
+    // NOTE: The calculated date is 18-10-1591, but there is inconsistency
+    // with this website, as it states it should be 19-10-1591
+    // https://habibur.com/hijri/1000/
+    day = 18;
+    month = 10;
+    year = 1591;
+    i18npool::Calendar_hijri::getHijri(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), year);
+
+    i18npool::Calendar_hijri::ToGregorian(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(18), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(10), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1591), year);
+
+    // 1-1-2000 (Hijri) == 7-1-2562 (Gregorian)
+    // NOTE: The calculated date is 7-1-2562, but there is inconsistency
+    // with this website, as it states it should be 8-1-2562
+    // https://habibur.com/hijri/2000/
+    day = 7;
+    month = 1;
+    year = 2562;
+    i18npool::Calendar_hijri::getHijri(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), year);
+
+    i18npool::Calendar_hijri::ToGregorian(&day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(7), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2562), year);
+}
+
+void TestCalendar::testGetGregorianJulianDay()
+{
+    // Julian day for 22-2-2022 (Gregorian) == 2459633
+    // https://core2.gsfc.nasa.gov/time/julian.html
+    sal_Int32 lJulianDay, day = 22, month = 2, year = 2022;
+    lJulianDay = i18npool::Calendar_hijri::getJulianDay(day, month, year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2459633), lJulianDay);
+
+    i18npool::Calendar_hijri::getGregorianDay(lJulianDay, &day, &month, &year);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(22), day);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), month);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2022), year);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestCalendar);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/i18npool/source/calendar/calendar_hijri.cxx 
b/i18npool/source/calendar/calendar_hijri.cxx
index 3d24150f8bf8..ed64c80db68c 100644
--- a/i18npool/source/calendar/calendar_hijri.cxx
+++ b/i18npool/source/calendar/calendar_hijri.cxx
@@ -18,7 +18,7 @@
  */
 
 #include <sal/config.h>
-
+#include <i18nutil/calendar.hxx>
 #include <cmath>
 #include <stdlib.h>
 
@@ -257,10 +257,10 @@ Calendar_hijri::getGregorianDay(sal_Int32 lJulianDay, 
sal_Int32 *pnDay, sal_Int3
     lFactorB = lFactorA + 1524;
     lFactorC = static_cast<tools::Long>(6680.0 + (static_cast<float>(lFactorB 
- 2439870) - 122.1) / 365.25);
     lFactorD = static_cast<tools::Long>(365 * lFactorC + (0.25 * lFactorC));
-    lFactorE = static_cast<tools::Long>((lFactorB - lFactorD) / 30.6001);
+    lFactorE = static_cast<tools::Long>((lFactorB - lFactorD) / 
i18nutil::monthDaysWithoutJanFeb);
 
     /* now, pull out the day number */
-    *pnDay = lFactorB - lFactorD - static_cast<tools::Long>(30.6001 * 
lFactorE);
+    *pnDay = lFactorB - lFactorD - 
static_cast<tools::Long>(i18nutil::monthDaysWithoutJanFeb * lFactorE);
 
     /* ...and the month, adjusting it if necessary */
     *pnMonth = lFactorE - 1;
@@ -298,7 +298,7 @@ Calendar_hijri::getJulianDay(sal_Int32 day, sal_Int32 
month, sal_Int32 year)
     jm = month + 13;
     }
 
-    sal_Int32 intgr = static_cast<sal_Int32>(static_cast<sal_Int32>(365.25 * 
jy) + static_cast<sal_Int32>(30.6001 * jm) + day + 1720995 );
+    sal_Int32 intgr = static_cast<sal_Int32>(static_cast<sal_Int32>(365.25 * 
jy) + static_cast<sal_Int32>(i18nutil::monthDaysWithoutJanFeb * jm) + day + 
1720995 );
 
     //check for switch to Gregorian calendar
     double const gregcal = 15 + 31 * ( 10 + 12 * 1582 );
diff --git a/include/i18nutil/calendar.hxx b/include/i18nutil/calendar.hxx
new file mode 100644
index 000000000000..26c7d72d1822
--- /dev/null
+++ b/include/i18nutil/calendar.hxx
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace i18nutil
+{
+/** This number shows month days without Jan and Feb.
+ *  According to the article, it is calcuated as (365-31-28)/10 = 30.6, but 
because
+ *  of a floating point bug, it was used as 30.6001 as a workaround.
+ *
+ *  "30.6001, 25 year old hack?"
+ *  https://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/archv011.cgi?read=31650 
*/
+constexpr double monthDaysWithoutJanFeb = (365 - 31 - 28) / 10.0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to