diff options
author | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-03-07 13:01:09 +0100 |
---|---|---|
committer | Jacobo Aragunde Pérez <jaragunde@igalia.com> | 2014-03-08 17:50:58 +0100 |
commit | 066dcba00659d2f81e4ba67edd14c44ed9ec3ea2 (patch) | |
tree | 5cdc7dff439f6b5ccb4acaf1ae677ad84b0c905a | |
parent | 3ce5fecea7d1dc3350db15c54bce584b83038e5f (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
-rw-r--r-- | unotools/source/misc/datetime.cxx | 58 |
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; |