summaryrefslogtreecommitdiff
path: root/i18npool
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2019-06-19 23:03:49 +0200
committerEike Rathke <erack@redhat.com>2019-06-20 01:57:20 +0200
commit942de6a01ba990e5f3bc55ce4ab3737a03f67f39 (patch)
treeba95c764124c7075fa8511a2788c8897ade95cc2 /i18npool
parent36fe1461c5ae7a7db175c77688aaff1a1d12551a (diff)
Resolves: tdf#92503 introduce TimeZone to calendar loading and default to UTC
Without that, the system's time zone was used which on DST transition dates leads to non-existent times when switching to/from DST. As the calendar use and number parser/formatter nor conversions or calculations are time zone aware, using not DST afflicted UTC is the better choice. Change-Id: I3303c6620d8c4b9d081555c8293954fb1bd67895 Reviewed-on: https://gerrit.libreoffice.org/74386 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Jenkins
Diffstat (limited to 'i18npool')
-rw-r--r--i18npool/inc/calendarImpl.hxx8
-rw-r--r--i18npool/inc/calendar_gregorian.hxx1
-rw-r--r--i18npool/source/calendar/calendarImpl.cxx36
-rw-r--r--i18npool/source/calendar/calendar_gregorian.cxx21
4 files changed, 58 insertions, 8 deletions
diff --git a/i18npool/inc/calendarImpl.hxx b/i18npool/inc/calendarImpl.hxx
index b35decb0f750..299bfe79bae2 100644
--- a/i18npool/inc/calendarImpl.hxx
+++ b/i18npool/inc/calendarImpl.hxx
@@ -84,6 +84,8 @@ public:
// XCalendar4
virtual void SAL_CALL setLocalDateTime(double TimeInDays) override;
virtual double SAL_CALL getLocalDateTime() override;
+ virtual void SAL_CALL loadDefaultCalendarTZ(const css::lang::Locale& rLocale, const OUString& rTimeZone) override;
+ virtual void SAL_CALL loadCalendarTZ(const OUString& uniqueID, const css::lang::Locale& rLocale, const OUString& rTimeZone) override;
//XServiceInfo
virtual OUString SAL_CALL getImplementationName() override;
@@ -92,9 +94,9 @@ public:
private:
struct lookupTableItem {
- lookupTableItem(const OUString& _uniqueID, css::uno::Reference < css::i18n::XCalendar4 > const & _xCalendar)
- : uniqueID(_uniqueID), xCalendar(_xCalendar) {}
- OUString uniqueID;
+ lookupTableItem(const OUString& rCacheID, css::uno::Reference < css::i18n::XCalendar4 > const & _xCalendar)
+ : m_aCacheID(rCacheID), xCalendar(_xCalendar) {}
+ OUString m_aCacheID;
css::uno::Reference < css::i18n::XCalendar4 > xCalendar;
};
std::vector<lookupTableItem> lookupTable;
diff --git a/i18npool/inc/calendar_gregorian.hxx b/i18npool/inc/calendar_gregorian.hxx
index 894f2246e30b..aa9a02965d79 100644
--- a/i18npool/inc/calendar_gregorian.hxx
+++ b/i18npool/inc/calendar_gregorian.hxx
@@ -54,6 +54,7 @@ public:
Calendar_gregorian();
Calendar_gregorian(const Era *_eraArray);
void init(const Era *_eraArray);
+ bool setTimeZone( const OUString& rTimeZone );
/**
* Destructor
diff --git a/i18npool/source/calendar/calendarImpl.cxx b/i18npool/source/calendar/calendarImpl.cxx
index 93ff9b16fa0b..f0962104a4b0 100644
--- a/i18npool/source/calendar/calendarImpl.cxx
+++ b/i18npool/source/calendar/calendarImpl.cxx
@@ -18,6 +18,7 @@
*/
#include <calendarImpl.hxx>
+#include <calendar_gregorian.hxx>
#include <localedata.hxx>
#include <cppuhelper/supportsservice.hxx>
@@ -40,12 +41,12 @@ CalendarImpl::~CalendarImpl()
}
void SAL_CALL
-CalendarImpl::loadDefaultCalendar( const Locale& rLocale )
+CalendarImpl::loadDefaultCalendarTZ( const Locale& rLocale, const OUString& rTimeZone )
{
Sequence< Calendar2 > xC = LocaleDataImpl::get()->getAllCalendars2(rLocale);
for (sal_Int32 i = 0; i < xC.getLength(); i++) {
if (xC[i].Default) {
- loadCalendar(xC[i].Name, rLocale);
+ loadCalendarTZ(xC[i].Name, rLocale, rTimeZone);
return;
}
}
@@ -53,14 +54,16 @@ CalendarImpl::loadDefaultCalendar( const Locale& rLocale )
}
void SAL_CALL
-CalendarImpl::loadCalendar(const OUString& uniqueID, const Locale& rLocale )
+CalendarImpl::loadCalendarTZ( const OUString& uniqueID, const Locale& rLocale, const OUString& rTimeZone )
{
Reference < XCalendar4 > xOldCalendar( xCalendar ); // backup
+ const OUString aCacheID( uniqueID + "_" + rTimeZone);
+ bool bTimeZone = true;
sal_Int32 i;
for (i = 0; i < sal::static_int_cast<sal_Int32>(lookupTable.size()); i++) {
lookupTableItem &listItem = lookupTable[i];
- if (uniqueID == listItem.uniqueID) {
+ if (aCacheID == listItem.m_aCacheID) {
xCalendar = listItem.xCalendar;
break;
}
@@ -85,7 +88,16 @@ CalendarImpl::loadCalendar(const OUString& uniqueID, const Locale& rLocale )
throw ERROR;
xCalendar.set(xI, UNO_QUERY);
- lookupTable.emplace_back( uniqueID, xCalendar );
+ if (!rTimeZone.isEmpty())
+ {
+ /* XXX NOTE: currently (2019-06-19) calendar implementations derive
+ * from Calendar_gregorian, even Hijri and Jewish. If that should
+ * change in future this should be adapted. */
+ Calendar_gregorian* pCal = dynamic_cast<Calendar_gregorian*>(xCalendar.get());
+ bTimeZone = (pCal && pCal->setTimeZone(rTimeZone));
+ }
+
+ lookupTable.emplace_back( aCacheID, xCalendar );
}
if ( !xCalendar.is() )
@@ -103,6 +115,10 @@ CalendarImpl::loadCalendar(const OUString& uniqueID, const Locale& rLocale )
xCalendar = xOldCalendar;
throw;
}
+
+ if (!bTimeZone)
+ // The calendar is usable but is not in the expected time zone.
+ throw ERROR;
}
Calendar2 SAL_CALL
@@ -164,6 +180,16 @@ CalendarImpl::getLocalDateTime()
return xCalendar->getLocalDateTime();
}
+void SAL_CALL CalendarImpl::loadDefaultCalendar( const css::lang::Locale& rLocale )
+{
+ loadDefaultCalendarTZ( rLocale, OUString());
+}
+
+void SAL_CALL CalendarImpl::loadCalendar( const OUString& uniqueID, const css::lang::Locale& rLocale )
+{
+ loadCalendarTZ( uniqueID, rLocale, OUString());
+}
+
OUString SAL_CALL
CalendarImpl::getUniqueID()
{
diff --git a/i18npool/source/calendar/calendar_gregorian.cxx b/i18npool/source/calendar/calendar_gregorian.cxx
index 18676361027a..f3b228efc04e 100644
--- a/i18npool/source/calendar/calendar_gregorian.cxx
+++ b/i18npool/source/calendar/calendar_gregorian.cxx
@@ -167,6 +167,11 @@ Calendar_gregorian::init(const Era *_eraArray)
* */
icu::Locale aIcuLocale( "", nullptr, nullptr, "calendar=gregorian");
+ /* XXX: not specifying a timezone when creating a calendar assigns the
+ * system's timezone with all DST quirks, invalid times when switching
+ * to/from DST and so on. The XCalendar* interfaces are defined to support
+ * local time and UTC time so we can not override that here.
+ */
UErrorCode status = U_ZERO_ERROR;
body.reset( icu::Calendar::createInstance( aIcuLocale, status) );
if (!body || !U_SUCCESS(status)) throw ERROR;
@@ -369,6 +374,22 @@ Calendar_gregorian::getLocalDateTime()
return (fTime + (nZoneOffset + nDSTOffset)) / U_MILLIS_PER_DAY;
}
+bool Calendar_gregorian::setTimeZone( const OUString& rTimeZone )
+{
+ if (fieldSet)
+ {
+ setValue();
+ getValue();
+ }
+ const icu::UnicodeString aID( reinterpret_cast<const UChar*>(rTimeZone.getStr()), rTimeZone.getLength());
+ const std::unique_ptr<const icu::TimeZone> pTZ( icu::TimeZone::createTimeZone(aID));
+ if (!pTZ)
+ return false;
+
+ body->setTimeZone(*pTZ);
+ return true;
+}
+
// map field value from gregorian calendar to other calendar, it can be overwritten by derived class.
// By using eraArray, it can take care Japanese and Taiwan ROC calendar.
void Calendar_gregorian::mapFromGregorian()