summaryrefslogtreecommitdiff
path: root/unotools
diff options
context:
space:
mode:
authorJacobo Aragunde Pérez <jaragunde@igalia.com>2014-03-07 13:01:09 +0100
committerJacobo Aragunde Pérez <jaragunde@igalia.com>2014-03-08 17:50:58 +0100
commit066dcba00659d2f81e4ba67edd14c44ed9ec3ea2 (patch)
tree5cdc7dff439f6b5ccb4acaf1ae677ad84b0c905a /unotools
parent3ce5fecea7d1dc3350db15c54bce584b83038e5f (diff)
unotools: improve date parser to support timezones
ISO8601 defines timezones with formats like 'Z', '+01', '-08:30' or '+0830' at the end of the datetime string, but our parser was failing when the string contained any timezone information. I have modified the parser so it doesn't fail in case of the string contains a timezone. Moreover, I check that the timezone definition is correct according to the standard [1] and I extract it to the string tokTz. Unfortunately UNO Time class doesn't contain any field to store the timezone, only the boolean field IsUTC, which I fill accordingly. TODO: add a timezone field to UNO and fill it from the parser. [1] https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators Change-Id: I9d33b19efbc6d41a74b02ece2dfa12fa12fac5eb
Diffstat (limited to 'unotools')
-rw-r--r--unotools/source/misc/datetime.cxx58
1 files changed, 49 insertions, 9 deletions
diff --git a/unotools/source/misc/datetime.cxx b/unotools/source/misc/datetime.cxx
index bd89bde2ee00..068209489d6d 100644
--- a/unotools/source/misc/datetime.cxx
+++ b/unotools/source/misc/datetime.cxx
@@ -108,6 +108,11 @@ namespace
for (; nPos < i_str.getLength(); ++nPos)
{
const sal_Unicode c = i_str[nPos];
+ if (c == 'Z' || c == '+' || c == '-')
+ {
+ --nPos; // we don't want to skip the tz separator
+ return true;
+ }
if (c == sep)
// fractional part allowed only in *last* token
return false;
@@ -118,6 +123,11 @@ namespace
OSL_ENSURE(nPos == i_str.getLength(), "impl_getISO8601TimeToken internal error; expected to be at end of string");
return true;
}
+ if (i_str[nPos] == 'Z' || i_str[nPos] == '+' || i_str[nPos] == '-')
+ {
+ --nPos; // we don't want to skip the tz separator
+ return true;
+ }
else
return false;
}
@@ -138,6 +148,33 @@ namespace
return true;
}
}
+ inline bool getISO8601TimeZoneToken(const OUString &i_str, sal_Int32 &io_index, OUString &o_strInt)
+ {
+ const sal_Unicode c0 = '0';
+ const sal_Unicode c9 = '9';
+ const sal_Unicode sep = ':';
+ if (i_str[io_index] == 'Z') // UTC timezone indicator
+ {
+ ++io_index;
+ o_strInt = "Z";
+ return true;
+ }
+ else if (i_str[io_index] == '+' || i_str[io_index] == '-') // other timezones indicator
+ {
+ ++io_index;
+ o_strInt = "";
+ for (; io_index < i_str.getLength(); ++io_index)
+ {
+ const sal_Unicode c = i_str[io_index];
+ if ((c < c0 || c > c9) && c != sep)
+ return false;
+ o_strInt += OUString(c);
+ }
+ return true;
+ }
+ else
+ return false;
+ }
}
@@ -313,14 +350,15 @@ bool ISO8601parseTime(const OUString &aTimeStr, starutil::Time& rTime)
sal_Int32 n = 0;
OUString tokInt;
OUString tokFrac;
+ OUString tokTz;
bool bFrac = false;
// hours
if (bSuccess && (bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac)))
{
if ( bFrac && n < aTimeStr.getLength())
- // junk after ISO time
- bSuccess = false;
- else if ( (bSuccess = convertNumber<sal_Int32>( nHour, tokInt, 0, 23 )) )
+ // is it junk or the timezone?
+ bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz);
+ if (bSuccess && (bSuccess = convertNumber<sal_Int32>( nHour, tokInt, 0, 23 )) )
{
if (bFrac)
{
@@ -354,9 +392,9 @@ bool ISO8601parseTime(const OUString &aTimeStr, starutil::Time& rTime)
if (bSuccess && (bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac)))
{
if ( bFrac && n < aTimeStr.getLength())
- // junk after ISO time
- bSuccess = false;
- else if ( (bSuccess = convertNumber<sal_Int32>( nMin, tokInt, 0, 59 )) )
+ // is it junk or the timezone?
+ bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz);
+ if (bSuccess && (bSuccess = convertNumber<sal_Int32>( nMin, tokInt, 0, 59 )) )
{
if (bFrac)
{
@@ -384,10 +422,10 @@ bool ISO8601parseTime(const OUString &aTimeStr, starutil::Time& rTime)
if (bSuccess && (bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac)))
{
if (n < aTimeStr.getLength())
- // junk after ISO time
- bSuccess = false;
+ // is it junk or the timezone?
+ bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz);
// max 60 for leap seconds
- else if ( (bSuccess = convertNumber<sal_Int32>( nSec, tokInt, 0, 60 )) )
+ if (bSuccess && (bSuccess = convertNumber<sal_Int32>( nSec, tokInt, 0, 60 )) )
{
if (bFrac)
{
@@ -425,6 +463,8 @@ bool ISO8601parseTime(const OUString &aTimeStr, starutil::Time& rTime)
nMin = 0;
++nHour;
}
+ if(!tokTz.isEmpty())
+ rTime.IsUTC = (tokTz == "Z");
rTime.Hours = (sal_uInt16)nHour;
rTime.Minutes = (sal_uInt16)nMin;