diff options
author | Michael Stahl <mstahl@redhat.com> | 2013-06-28 00:43:19 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2013-07-15 11:46:41 +0000 |
commit | 652ccbdf3111766fadc379a8cf4650b744e1e19c (patch) | |
tree | 5efdab367c4da4ac6c62ad1e228b77648cc62aed /sax/source/tools | |
parent | a8e8d46020702c64ff314adbe87e6f21e73e1999 (diff) |
i#108348 API CHANGE: add IsUTC to css.util.DateTime etc.
Add IsUTC member to:
com.sun.star.util.DateTime
com.sun.star.util.DateTimeRange
com.sun.star.util.Time
Add new stucts with explicit time zones:
com.sun.star.util.DateTimeWithTimezone
com.sun.star.util.DateWithTimezone
com.sun.star.util.TimeWithTimezone
Adapt the sax::Converter to read/write timezones, and fix the unit test.
Everything else just uses default (no time zone), this commit is just
to fix the API.
STRUCT: /UCR/com/sun/star/util/DateTime
nFields1 = 7 != nFields2 = 8
Registry2 contains 1 more fields
STRUCT: /UCR/com/sun/star/util/DateTimeRange
nFields1 = 14 != nFields2 = 15
Registry2 contains 1 more fields
STRUCT: /UCR/com/sun/star/util/Time
nFields1 = 4 != nFields2 = 5
Registry2 contains 1 more fields
Conflicts:
sc/source/filter/oox/unitconverter.cxx
Change-Id: I01f7a6d082a6b090c8efe71d2de137474c495c18
Reviewed-on: https://gerrit.libreoffice.org/4833
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Eike Rathke <erack@redhat.com>
Diffstat (limited to 'sax/source/tools')
-rw-r--r-- | sax/source/tools/converter.cxx | 204 |
1 files changed, 180 insertions, 24 deletions
diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx index 690c3e581c51..e99690e91546 100644 --- a/sax/source/tools/converter.cxx +++ b/sax/source/tools/converter.cxx @@ -28,6 +28,7 @@ #include <rtl/ustrbuf.hxx> #include <rtl/math.hxx> +#include <osl/time.h> #include <algorithm> @@ -1185,13 +1186,48 @@ bool Converter::convertDuration(util::Duration& rDuration, } +static void +lcl_AppendTimezone(OUStringBuffer & i_rBuffer, sal_Int16 const nOffset) +{ + if (0 == nOffset) + { + i_rBuffer.append(sal_Unicode('Z')); + } + else + { + if (0 < nOffset) + { + i_rBuffer.append(sal_Unicode('+')); + } + else + { + i_rBuffer.append(sal_Unicode('-')); + } + const sal_Int32 nHours (abs(nOffset) / 60); + const sal_Int32 nMinutes(abs(nOffset) % 60); + SAL_WARN_IF(nHours > 14 || (nHours == 14 && nMinutes > 0), + "sax", "convertDateTime: timezone overflow"); + if (nHours < 10) + { + i_rBuffer.append('0'); + } + i_rBuffer.append(nHours); + i_rBuffer.append(':'); + if (nMinutes < 10) + { + i_rBuffer.append('0'); + } + i_rBuffer.append(nMinutes); + } +} + /** convert util::Date to ISO "date" string */ void Converter::convertDate( OUStringBuffer& i_rBuffer, const util::Date& i_rDate) { - const util::DateTime dt( - 0, 0, 0, 0, i_rDate.Day, i_rDate.Month, i_rDate.Year); + const util::DateTime dt(0, 0, 0, 0, + i_rDate.Day, i_rDate.Month, i_rDate.Year, false); convertDateTime(i_rBuffer, dt, false); } @@ -1260,6 +1296,17 @@ void Converter::convertDateTime( i_rBuffer.append(OUString::createFromAscii(ostr.str().c_str())); } } + + sal_uInt16 * pTimezone(0); // FIXME pass this as parameter + if (pTimezone) + { + lcl_AppendTimezone(i_rBuffer, *pTimezone); + } + else if (i_rDateTime.IsUTC) + { + // append local time + lcl_AppendTimezone(i_rBuffer, 0); + } } /** convert ISO "date" or "dateTime" string to util::DateTime */ @@ -1279,6 +1326,10 @@ bool Converter::convertDateTime( util::DateTime& rDateTime, rDateTime.Minutes = 0; rDateTime.Seconds = 0; rDateTime.NanoSeconds = 0; + // FIXME +#if 0 + rDateTime.IsUTC = date.IsUTC; +#endif } return true; } @@ -1288,6 +1339,99 @@ bool Converter::convertDateTime( util::DateTime& rDateTime, } } +static bool lcl_isLeapYear(const sal_uInt32 nYear) +{ + return ((nYear % 4) == 0) + && (((nYear % 100) != 0) || ((nYear % 400) == 0)); +} + +static sal_uInt16 +lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear) +{ + static sal_uInt16 s_MaxDaysPerMonth[12] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + OSL_ASSERT(0 < nMonth && nMonth <= 12); + if ((2 == nMonth) && lcl_isLeapYear(nYear)) + { + return 29; + } + return s_MaxDaysPerMonth[nMonth - 1]; +} + +static void lcl_ConvertToUTC( + sal_Int16 & o_rYear, sal_uInt16 & o_rMonth, sal_uInt16 & o_rDay, + sal_uInt16 & o_rHours, sal_uInt16 & o_rMinutes, + sal_Int16 const nSourceOffset) +{ + sal_Int16 nOffsetHours(abs(nSourceOffset) / 60); + sal_Int16 const nOffsetMinutes(abs(nSourceOffset) % 60); + o_rMinutes += nOffsetMinutes; + if (nSourceOffset < 0) + { + o_rMinutes += nOffsetMinutes; + if (60 <= o_rMinutes) + { + o_rMinutes -= 60; + ++nOffsetHours; + } + o_rHours += nOffsetHours; + if (o_rHours < 24) + { + return; + } + while (24 <= o_rHours) + { + o_rHours -= 24; + ++o_rDay; + } + sal_Int16 const nDaysInMonth(lcl_MaxDaysPerMonth(o_rMonth, o_rYear)); + if (o_rDay <= nDaysInMonth) + { + return; + } + o_rDay -= nDaysInMonth; + ++o_rMonth; + if (o_rMonth <= 12) + { + return; + } + o_rMonth = 1; + ++o_rYear; // works for negative year too + } + else if (0 < nSourceOffset) + { + // argh everything is unsigned + if (o_rMinutes < nOffsetMinutes) + { + o_rMinutes += 60; + ++nOffsetHours; + } + o_rMinutes -= nOffsetMinutes; + sal_Int16 nDaySubtract(0); + while (o_rHours < nOffsetHours) + { + o_rHours += 24; + ++nDaySubtract; + } + o_rHours -= nOffsetHours; + if (nDaySubtract < o_rDay) + { + o_rDay -= nDaySubtract; + return; + } + sal_Int16 const nPrevMonth((o_rMonth == 1) ? 12 : o_rMonth - 1); + sal_Int16 const nDaysInMonth(lcl_MaxDaysPerMonth(nPrevMonth, o_rYear)); + o_rDay += nDaysInMonth; + --o_rMonth; + if (0 == o_rMonth) + { + o_rMonth = 12; + --o_rYear; // works for negative year too + } + o_rDay -= nDaySubtract; + } +} + static bool readDateTimeComponent(const OUString & rString, sal_Int32 & io_rnPos, sal_Int32 & o_rnTarget, @@ -1309,24 +1453,7 @@ readDateTimeComponent(const OUString & rString, return true; } -static bool lcl_isLeapYear(const sal_uInt32 nYear) -{ - return ((nYear % 4) == 0) - && (((nYear % 100) != 0) || ((nYear % 400) == 0)); -} -static sal_uInt16 -lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear) -{ - static sal_uInt16 s_MaxDaysPerMonth[12] = - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - OSL_ASSERT(0 < nMonth && nMonth <= 12); - if ((2 == nMonth) && lcl_isLeapYear(nYear)) - { - return 29; - } - return s_MaxDaysPerMonth[nMonth - 1]; -} /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */ bool Converter::convertDateOrDateTime( @@ -1526,13 +1653,11 @@ bool Converter::convertDateOrDateTime( bSuccess &= (nPos == string.getLength()); // trailing junk? - if (bSuccess && bHaveTimezone) - { - // util::DateTime does not support timezones! - } - if (bSuccess) { + sal_uInt16 * pTimezone(0); // FIXME pass this as parameter + sal_Int16 const nTimezoneOffset = ((bHaveTimezoneMinus) ? (-1) : (+1)) + * ((nTimezoneHours * 60) + nTimezoneMinutes); if (bHaveTime) // time is optional { rDateTime.Year = @@ -1543,6 +1668,25 @@ bool Converter::convertDateOrDateTime( rDateTime.Minutes = static_cast<sal_uInt16>(nMinutes); rDateTime.Seconds = static_cast<sal_uInt16>(nSeconds); rDateTime.NanoSeconds = static_cast<sal_uInt32>(nNanoSeconds); + if (bHaveTimezone) + { + if (pTimezone) + { + *pTimezone = nTimezoneOffset; + rDateTime.IsUTC = (0 == nTimezoneOffset); + } + else + { + lcl_ConvertToUTC(rDateTime.Year, rDateTime.Month, + rDateTime.Day, rDateTime.Hours, rDateTime.Minutes, + nTimezoneOffset); + rDateTime.IsUTC = true; + } + } + else + { + rDateTime.IsUTC = false; + } rbDateTime = true; } else @@ -1551,6 +1695,18 @@ bool Converter::convertDateOrDateTime( ((isNegative) ? (-1) : (+1)) * static_cast<sal_Int16>(nYear); rDate.Month = static_cast<sal_uInt16>(nMonth); rDate.Day = static_cast<sal_uInt16>(nDay); + if (bHaveTimezone) + { + if (pTimezone) + { + *pTimezone = nTimezoneOffset; + } + else + { + // a Date cannot be adjusted + SAL_INFO("sax", "dropping timezone"); + } + } rbDateTime = false; } } |