summaryrefslogtreecommitdiff
path: root/sax
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2013-06-28 00:43:19 +0200
committerMichael Stahl <mstahl@redhat.com>2013-07-15 16:54:56 +0200
commitdd780228cca25dc818ca7fdb628ff607c109618e (patch)
treecec08040b1cd42296773a557fc821951615e9c3b /sax
parenteb426753811befc69b3929146ac68cb97f92f7b0 (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 Reviewed-on: https://gerrit.libreoffice.org/4833 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Eike Rathke <erack@redhat.com> (cherry picked from commit 652ccbdf3111766fadc379a8cf4650b744e1e19c) i#108348: fix TimeZone -> Timezone in struct names (cherry picked from commit 604aae1fd240254fe851d93dc35b5408bd13296c) Signed-off-by: Michael Stahl <mstahl@redhat.com> Signed-off-by: Lionel Elie Mamane <lionel@mamane.lu> Signed-off-by: Michael Meeks <michael.meeks@suse.com> Conflicts: forms/source/xforms/convert.cxx offapi/type_reference/offapi.rdb reportdesign/source/core/sdr/RptObject.cxx sc/source/filter/oox/unitconverter.cxx
Diffstat (limited to 'sax')
-rw-r--r--sax/qa/cppunit/test_converter.cxx63
-rw-r--r--sax/source/tools/converter.cxx204
2 files changed, 212 insertions, 55 deletions
diff --git a/sax/qa/cppunit/test_converter.cxx b/sax/qa/cppunit/test_converter.cxx
index 8a5f72826a92..cfda248adf6c 100644
--- a/sax/qa/cppunit/test_converter.cxx
+++ b/sax/qa/cppunit/test_converter.cxx
@@ -157,7 +157,8 @@ static bool eqDateTime(util::DateTime a, util::DateTime b) {
return a.Year == b.Year && a.Month == b.Month && a.Day == b.Day
&& a.Hours == b.Hours && a.Minutes == b.Minutes
&& a.Seconds == b.Seconds
- && a.NanoSeconds == b.NanoSeconds;
+ && a.NanoSeconds == b.NanoSeconds
+ && a.IsUTC == b.IsUTC;
}
static void doTest(util::DateTime const & rdt, char const*const pis,
@@ -168,13 +169,14 @@ static void doTest(util::DateTime const & rdt, char const*const pis,
util::DateTime odt;
SAL_INFO("sax.cppunit","about to convert '" << is << "'");
bool bSuccess( Converter::convertDateTime(odt, is) );
- SAL_INFO("sax.cppunit","Y:" << odt.Year << " M:" << odt.Month << " D:" << odt.Day << " H:" << odt.Hours << " M:" << odt.Minutes << " S:" << odt.Seconds << " nS:" << odt.NanoSeconds);
+ SAL_INFO("sax.cppunit","Y:" << odt.Year << " M:" << odt.Month << " D:" << odt.Day << " H:" << odt.Hours << " M:" << odt.Minutes << " S:" << odt.Seconds << " nS:" << odt.NanoSeconds << " UTC: " << (bool)odt.IsUTC);
CPPUNIT_ASSERT(bSuccess);
CPPUNIT_ASSERT(eqDateTime(rdt, odt));
OUStringBuffer buf;
Converter::convertDateTime(buf, odt, true);
SAL_INFO("sax.cppunit","" << buf.getStr());
- CPPUNIT_ASSERT(buf.makeStringAndClear().equalsAscii(pos));
+ CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(pos),
+ buf.makeStringAndClear());
}
static void doTestDateTimeF(char const*const pis)
@@ -189,43 +191,42 @@ static void doTestDateTimeF(char const*const pis)
void ConverterTest::testDateTime()
{
SAL_INFO("sax.cppunit","\nSAX CONVERTER TEST BEGIN");
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1), "0001-01-01T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1),
- "0001-01-01T00:00:00Z", "0001-01-01T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, -1), "-0001-01-01T00:00:00");
-// doTest( util::DateTime(0, 0, 0, 0, 1, 1, -1), "-0001-01-01T00:00:00Z");
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, -324),
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1, false), "0001-01-01T00:00:00" );
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1, true), "0001-01-01T00:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, -1, false),
+ "-0001-01-01T00:00:00");
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, -1, true),
+ "-0001-01-01T01:00:00+01:00", "-0001-01-01T00:00:00Z");
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, -324, false),
"-0324-01-01T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1),
- "0001-01-01T00:00:00-00:00", "0001-01-01T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1),
- "0001-01-01T00:00:00+00:00", "0001-01-01T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 2, 1, 1)/*(0, 0, 12, 0, 2, 1, 1)*/,
- "0001-01-02T00:00:00-12:00", "0001-01-02T00:00:00" );
-// "0001-02-01T12:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 2, 1, 1)/*(0, 0, 12, 0, 1, 1, 1)*/,
- "0001-01-02T00:00:00+12:00", "0001-01-02T00:00:00" );
-// "0001-01-01T12:00:00" );
- doTest( util::DateTime(990000000, 59, 59, 23, 31, 12, 9999),
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1, true),
+ "0001-01-01T00:00:00-00:00", "0001-01-01T00:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1, true),
+ "0001-01-01T00:00:00+00:00", "0001-01-01T00:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 12, 2, 1, 1, true),
+ "0001-01-02T00:00:00-12:00", "0001-01-02T12:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 12, 1, 1, 1, true),
+ "0001-01-02T00:00:00+12:00", "0001-01-01T12:00:00Z" );
+ doTest( util::DateTime(990000000, 59, 59, 23, 31, 12, 9999, false),
"9999-12-31T23:59:59.99", "9999-12-31T23:59:59.990000000" );
- doTest( util::DateTime(990000000, 59, 59, 23, 31, 12, 9999),
- "9999-12-31T23:59:59.99Z", "9999-12-31T23:59:59.990000000" );
- doTest( util::DateTime(999999999, 59, 59, 23, 31, 12, 9999),
+ doTest( util::DateTime(990000000, 59, 59, 23, 31, 12, 9999, true),
+ "9999-12-31T23:59:59.99Z", "9999-12-31T23:59:59.990000000Z" );
+ doTest( util::DateTime(999999999, 59, 59, 23, 31, 12, 9999, false),
"9999-12-31T23:59:59.9999999999999999999999999999999999999",
"9999-12-31T23:59:59.999999999" );
- doTest( util::DateTime(999999999, 59, 59, 23, 31, 12, 9999),
+ doTest( util::DateTime(999999999, 59, 59, 23, 31, 12, 9999, true),
"9999-12-31T23:59:59.9999999999999999999999999999999999999Z",
- "9999-12-31T23:59:59.999999999" );
- doTest( util::DateTime(0, 0, 0, 0, 29, 2, 2000), // leap year
- "2000-02-29T00:00:00-00:00", "2000-02-29T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 0, 29, 2, 1600), // leap year
- "1600-02-29T00:00:00-00:00", "1600-02-29T00:00:00" );
- doTest( util::DateTime(0, 0, 0, 24, 1, 1, 333)
+ "9999-12-31T23:59:59.999999999Z" );
+ doTest( util::DateTime(0, 0, 0, 0, 29, 2, 2000, true), // leap year
+ "2000-02-29T00:00:00-00:00", "2000-02-29T00:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 0, 29, 2, 1600, true), // leap year
+ "1600-02-29T00:00:00-00:00", "1600-02-29T00:00:00Z" );
+ doTest( util::DateTime(0, 0, 0, 24, 1, 1, 333, false)
/*(0, 0, 0, 0, 2, 1, 333)*/,
"0333-01-01T24:00:00"/*, "0333-01-02T00:00:00"*/ );
// While W3C XMLSchema specifies a minimum of 4 year digits we are lenient
// in what we accept.
- doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1),
+ doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1, false),
"1-01-01T00:00:00", "0001-01-01T00:00:00" );
doTestDateTimeF( "+0001-01-01T00:00:00" ); // invalid: ^+
doTestDateTimeF( "0001-1-01T00:00:00" ); // invalid: < 2 M
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;
}
}