summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--include/unotools/calendarwrapper.hxx26
-rw-r--r--offapi/com/sun/star/i18n/XCalendar4.idl24
-rw-r--r--unotools/source/i18n/calendarwrapper.cxx8
7 files changed, 110 insertions, 14 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()
diff --git a/include/unotools/calendarwrapper.hxx b/include/unotools/calendarwrapper.hxx
index 149393bb7e84..a81186ae4ba5 100644
--- a/include/unotools/calendarwrapper.hxx
+++ b/include/unotools/calendarwrapper.hxx
@@ -54,8 +54,30 @@ public:
// wrapper implementations of XCalendar
- void loadDefaultCalendar( const css::lang::Locale& rLocale );
- void loadCalendar( const OUString& rUniqueID, const css::lang::Locale& rLocale );
+ /** Load the default calendar of a locale.
+
+ This adds a bool bTimeZoneUTC parameter which is not part of the UNO API to
+ facilitate handling of non time zone aware data.
+
+ @param bTimeZoneUTC
+ Default <TRUE/>. If <FALSE/>, the system's timezone is assigned
+ to the calendar, including all DST quirks like not existing
+ times on DST transition dates when switching to/from DST. As
+ current implementations and number parser/formatter don't store
+ or convert or calculate with time zones it is safer to use UTC,
+ which is not DST afflicted, otherwise surprises are lurking
+ (for example tdf#92503).
+ */
+ void loadDefaultCalendar( const css::lang::Locale& rLocale, bool bTimeZoneUTC = true );
+ /// This adds a bTimeZoneUTC parameter which is not part of the API.
+ void loadCalendar( const OUString& rUniqueID, const css::lang::Locale& rLocale, bool bTimeZoneUTC = true );
+
+ /* XXX NOTE: the time zone taking UNO API functions are not implemented as
+ * wrapper interface as they are not necessary/used so far. These are:
+ void loadDefaultCalendarTZ( const css::lang::Locale& rLocale, const OUString& rTimeZone );
+ void loadCalendarTZ( const OUString& rUniqueID, const css::lang::Locale& rLocale, const OUString& rTimeZone );
+ */
+
css::uno::Sequence< OUString > getAllCalendars( const css::lang::Locale& rLocale ) const;
OUString getUniqueID() const;
/// set UTC date/time
diff --git a/offapi/com/sun/star/i18n/XCalendar4.idl b/offapi/com/sun/star/i18n/XCalendar4.idl
index 1303dc0aed11..94686b4a0031 100644
--- a/offapi/com/sun/star/i18n/XCalendar4.idl
+++ b/offapi/com/sun/star/i18n/XCalendar4.idl
@@ -49,6 +49,30 @@ interface XCalendar4 : com::sun::star::i18n::XCalendar3
*/
double getLocalDateTime();
+ /** Load the default calendar for the given locale with a given time zone.
+
+ @param TimeZone
+ If empty, the system's time zone is used.
+ Else specified as "Region/City" name like "Europe/Berlin",
+ or a custom time zone ID such as "UTC" or "GMT-8:00".
+
+ @since LibreOffice 6.3
+ */
+ void loadDefaultCalendarTZ( [in] ::com::sun::star::lang::Locale rLocale, [in] string TimeZone );
+
+ /** Load a specific calendar for the given locale with a given time zone.
+
+ @param TimeZone
+ If empty, the system's time zone is used.
+ Else specified as "Region/City" name like "Europe/Berlin",
+ or a custom time zone ID such as "UTC" or "GMT-8:00".
+
+ @since LibreOffice 6.3
+ */
+ void loadCalendarTZ( [in] string uniqueID,
+ [in] ::com::sun::star::lang::Locale rLocale,
+ [in] string TimeZone );
+
};
}; }; }; };
diff --git a/unotools/source/i18n/calendarwrapper.cxx b/unotools/source/i18n/calendarwrapper.cxx
index 6e755be3bd36..5f4a1669bccf 100644
--- a/unotools/source/i18n/calendarwrapper.cxx
+++ b/unotools/source/i18n/calendarwrapper.cxx
@@ -39,12 +39,12 @@ CalendarWrapper::~CalendarWrapper()
{
}
-void CalendarWrapper::loadDefaultCalendar( const css::lang::Locale& rLocale )
+void CalendarWrapper::loadDefaultCalendar( const css::lang::Locale& rLocale, bool bTimeZoneUTC )
{
try
{
if ( xC.is() )
- xC->loadDefaultCalendar( rLocale );
+ xC->loadDefaultCalendarTZ( rLocale, (bTimeZoneUTC ? "UTC" : OUString()));
}
catch (const Exception&)
{
@@ -52,12 +52,12 @@ void CalendarWrapper::loadDefaultCalendar( const css::lang::Locale& rLocale )
}
}
-void CalendarWrapper::loadCalendar( const OUString& rUniqueID, const css::lang::Locale& rLocale )
+void CalendarWrapper::loadCalendar( const OUString& rUniqueID, const css::lang::Locale& rLocale, bool bTimeZoneUTC )
{
try
{
if ( xC.is() )
- xC->loadCalendar( rUniqueID, rLocale );
+ xC->loadCalendarTZ( rUniqueID, rLocale, (bTimeZoneUTC ? "UTC" : OUString()));
}
catch (const Exception&)
{