/src/libreoffice/unotools/source/misc/datetime.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <unotools/datetime.hxx> |
21 | | #include <unotools/localedatawrapper.hxx> |
22 | | #include <unotools/syslocale.hxx> |
23 | | #include <tools/date.hxx> |
24 | | #include <tools/time.hxx> |
25 | | #include <tools/datetime.hxx> |
26 | | #include <rtl/ustrbuf.hxx> |
27 | | #include <rtl/math.hxx> |
28 | | #include <osl/diagnose.h> |
29 | | #include <comphelper/string.hxx> |
30 | | #include <o3tl/string_view.hxx> |
31 | | #include <cstddef> |
32 | | #include <sstream> |
33 | | |
34 | | namespace |
35 | | { |
36 | | bool checkAllNumber(std::u16string_view rString) |
37 | 40.0k | { |
38 | 40.0k | sal_Int32 nPos = 0; |
39 | 40.0k | sal_Int32 nLen = rString.size(); |
40 | | |
41 | | // skip white space |
42 | 40.0k | while( nPos < nLen && ' ' == rString[nPos] ) |
43 | 1 | nPos++; |
44 | | |
45 | 40.0k | if( nPos < nLen && '-' == rString[nPos] ) |
46 | 0 | nPos++; |
47 | | |
48 | | // get number |
49 | 137k | while( nPos < nLen && |
50 | 99.4k | '0' <= rString[nPos] && |
51 | 99.4k | '9' >= rString[nPos] ) |
52 | 97.6k | { |
53 | 97.6k | nPos++; |
54 | 97.6k | } |
55 | | |
56 | 40.0k | return nPos == nLen; |
57 | 40.0k | } |
58 | | |
59 | | /** convert string to number with optional min and max values */ |
60 | | bool convertNumber32(sal_Int32& rValue, |
61 | | std::u16string_view rString, |
62 | | sal_Int32 /*nMin*/ = -1, sal_Int32 /*nMax*/ = -1) |
63 | 35.1k | { |
64 | 35.1k | if (!checkAllNumber(rString)) |
65 | 1.83k | { |
66 | 1.83k | rValue = 0; |
67 | 1.83k | return false; |
68 | 1.83k | } |
69 | | |
70 | 33.2k | rValue = o3tl::toInt32(rString); |
71 | 33.2k | return true; |
72 | 35.1k | } |
73 | | |
74 | | bool convertNumber64(sal_Int64& rValue, |
75 | | std::u16string_view rString, |
76 | | sal_Int64 /*nMin*/ = -1, sal_Int64 /*nMax*/ = -1) |
77 | 4.94k | { |
78 | 4.94k | if (!checkAllNumber(rString)) |
79 | 0 | { |
80 | 0 | rValue = 0; |
81 | 0 | return false; |
82 | 0 | } |
83 | | |
84 | 4.94k | rValue = o3tl::toInt64(rString); |
85 | 4.94k | return true; |
86 | 4.94k | } |
87 | | |
88 | | // although the standard calls for fixed-length (zero-padded) tokens |
89 | | // (in their integer part), we are here liberal and allow shorter tokens |
90 | | // (when there are separators, else it is ambiguous). |
91 | | // Note that: |
92 | | // the token separator is OPTIONAL |
93 | | // empty string is a valid token! (to recognise hh or hhmm or hh:mm formats) |
94 | | // returns: success / failure |
95 | | // in case of failure, no reference argument is changed |
96 | | // arguments: |
97 | | // i_str: string to extract token from |
98 | | // index: index in i_str where to start tokenizing |
99 | | // after return, start of *next* token (if any) |
100 | | // if this was the last token, then the value is UNDEFINED |
101 | | // o_strInt: output; integer part of token |
102 | | // o_bFraction: output; was there a fractional part? |
103 | | // o_strFrac: output; fractional part of token |
104 | | bool impl_getISO8601TimeToken(std::u16string_view i_str, std::size_t &nPos, OUString &resInt, bool &bFraction, OUString &resFrac) |
105 | 30.2k | { |
106 | 30.2k | bFraction = false; |
107 | | // all tokens are of length 2 |
108 | 30.2k | const std::size_t nEndPos = nPos + 2; |
109 | 30.2k | const sal_Unicode c0 = '0'; |
110 | 30.2k | const sal_Unicode c9 = '9'; |
111 | 30.2k | const sal_Unicode sep = ':'; |
112 | 73.1k | for (;nPos < nEndPos && nPos < i_str.size(); ++nPos) |
113 | 54.0k | { |
114 | 54.0k | const sal_Unicode c = i_str[nPos]; |
115 | 54.0k | if (c == sep) |
116 | 7.22k | return true; |
117 | 46.7k | if (c < c0 || c > c9) |
118 | 3.86k | return false; |
119 | 42.9k | resInt += OUStringChar(c); |
120 | 42.9k | } |
121 | 19.1k | if (nPos == 0) |
122 | 115 | return false; |
123 | 19.0k | if (nPos == i_str.size() || i_str[nPos] == sep) |
124 | 9.32k | return true; |
125 | 9.69k | if (i_str[nPos] == ',' || i_str[nPos] == '.') |
126 | 6.78k | { |
127 | 6.78k | bFraction = true; |
128 | 6.78k | ++nPos; |
129 | 42.3k | for (; nPos < i_str.size(); ++nPos) |
130 | 38.2k | { |
131 | 38.2k | const sal_Unicode c = i_str[nPos]; |
132 | 38.2k | if (c == 'Z' || c == '+' || c == '-') |
133 | 1.84k | { |
134 | 1.84k | --nPos; // we don't want to skip the tz separator |
135 | 1.84k | return true; |
136 | 1.84k | } |
137 | 36.3k | if (c == sep) |
138 | | // fractional part allowed only in *last* token |
139 | 171 | return false; |
140 | 36.1k | if (c < c0 || c > c9) |
141 | 608 | return false; |
142 | 35.5k | resFrac += OUStringChar(c); |
143 | 35.5k | } |
144 | 4.15k | OSL_ENSURE(nPos == i_str.size(), "impl_getISO8601TimeToken internal error; expected to be at end of string"); |
145 | 4.15k | return true; |
146 | 6.78k | } |
147 | 2.91k | if (i_str[nPos] == 'Z' || i_str[nPos] == '+' || i_str[nPos] == '-') |
148 | 402 | { |
149 | 402 | --nPos; // we don't want to skip the tz separator |
150 | 402 | return true; |
151 | 402 | } |
152 | 2.51k | else |
153 | 2.51k | return false; |
154 | 2.91k | } |
155 | | bool getISO8601TimeToken(std::u16string_view i_str, std::size_t &io_index, OUString &o_strInt, bool &o_bFraction, OUString &o_strFrac) |
156 | 30.2k | { |
157 | 30.2k | OUString resInt; |
158 | 30.2k | OUString resFrac; |
159 | 30.2k | bool bFraction = false; |
160 | 30.2k | std::size_t index = io_index; |
161 | 30.2k | if(!impl_getISO8601TimeToken(i_str, index, resInt, bFraction, resFrac)) |
162 | 7.27k | return false; |
163 | 22.9k | else |
164 | 22.9k | { |
165 | 22.9k | io_index = index+1; |
166 | 22.9k | o_strInt = resInt; |
167 | 22.9k | o_strFrac = resFrac; |
168 | 22.9k | o_bFraction = bFraction; |
169 | 22.9k | return true; |
170 | 22.9k | } |
171 | 30.2k | } |
172 | | bool getISO8601TimeZoneToken(std::u16string_view i_str, std::size_t &io_index, OUString &o_strInt) |
173 | 2.11k | { |
174 | 2.11k | const sal_Unicode c0 = '0'; |
175 | 2.11k | const sal_Unicode c9 = '9'; |
176 | 2.11k | const sal_Unicode sep = ':'; |
177 | 2.11k | if (i_str[io_index] == 'Z') // UTC timezone indicator |
178 | 68 | { |
179 | 68 | ++io_index; |
180 | 68 | o_strInt = "Z"; |
181 | 68 | return true; |
182 | 68 | } |
183 | 2.04k | else if (i_str[io_index] == '+' || i_str[io_index] == '-') // other timezones indicator |
184 | 1.81k | { |
185 | 1.81k | ++io_index; |
186 | 1.81k | o_strInt.clear(); |
187 | 29.8k | for (; io_index < i_str.size(); ++io_index) |
188 | 29.1k | { |
189 | 29.1k | const sal_Unicode c = i_str[io_index]; |
190 | 29.1k | if ((c < c0 || c > c9) && c != sep) |
191 | 1.09k | return false; |
192 | 28.0k | o_strInt += OUStringChar(c); |
193 | 28.0k | } |
194 | 722 | return true; |
195 | 1.81k | } |
196 | 230 | else |
197 | 230 | return false; |
198 | 2.11k | } |
199 | | } |
200 | | |
201 | | namespace utl |
202 | | { |
203 | | const LocaleDataWrapper& GetLocaleData() |
204 | 0 | { |
205 | 0 | static SvtSysLocale ourSysLocale; |
206 | 0 | return ourSysLocale.GetLocaleData(); |
207 | 0 | } |
208 | | |
209 | 0 | DateTime GetDateTime(const css::util::DateTime& _rDT) { return DateTime(_rDT); } |
210 | | |
211 | | OUString GetDateTimeString(const css::util::DateTime& _rDT) |
212 | 0 | { |
213 | | // String with date and time information (#i20172#) |
214 | 0 | DateTime aDT(GetDateTime(_rDT)); |
215 | 0 | const LocaleDataWrapper& rLoDa = GetLocaleData(); |
216 | |
|
217 | 0 | return rLoDa.getDate(aDT) + " " + rLoDa.getTime(aDT); |
218 | 0 | } |
219 | | |
220 | | OUString GetDateTimeString(sal_Int32 _nDate, sal_Int32 _nTime) |
221 | 0 | { |
222 | 0 | const LocaleDataWrapper& rLoDa = GetLocaleData(); |
223 | |
|
224 | 0 | Date aDate(_nDate); |
225 | 0 | tools::Time aTime(tools::Time::fromEncodedTime(_nTime * tools::Time::nanoPerCenti)); |
226 | 0 | return rLoDa.getDate(aDate) + ", " + rLoDa.getTime(aTime); |
227 | 0 | } |
228 | | |
229 | | OUString GetDateString(const css::util::DateTime& _rDT) |
230 | 0 | { |
231 | 0 | return GetLocaleData().getDate(GetDateTime(_rDT)); |
232 | 0 | } |
233 | | |
234 | | void typeConvert(const Date& _rDate, css::util::Date& _rOut) |
235 | 0 | { |
236 | 0 | _rOut.Day = _rDate.GetDay(); |
237 | 0 | _rOut.Month = _rDate.GetMonth(); |
238 | 0 | _rOut.Year = _rDate.GetYear(); |
239 | 0 | } |
240 | | |
241 | | void typeConvert(const css::util::Date& _rDate, Date& _rOut) |
242 | 0 | { |
243 | 0 | _rOut = Date(_rDate.Day, _rDate.Month, _rDate.Year); |
244 | 0 | } |
245 | | |
246 | | void typeConvert(const DateTime& _rDateTime, css::util::DateTime& _rOut) |
247 | 0 | { |
248 | 0 | _rOut.Year = _rDateTime.GetYear(); |
249 | 0 | _rOut.Month = _rDateTime.GetMonth(); |
250 | 0 | _rOut.Day = _rDateTime.GetDay(); |
251 | 0 | _rOut.Hours = _rDateTime.GetHour(); |
252 | 0 | _rOut.Minutes = _rDateTime.GetMin(); |
253 | 0 | _rOut.Seconds = _rDateTime.GetSec(); |
254 | 0 | _rOut.NanoSeconds = _rDateTime.GetNanoSec(); |
255 | 0 | } |
256 | | |
257 | | void typeConvert(const css::util::DateTime& _rDateTime, DateTime& _rOut) |
258 | 0 | { |
259 | 0 | Date aDate(_rDateTime.Day, _rDateTime.Month, _rDateTime.Year); |
260 | 0 | tools::Time aTime(_rDateTime.Hours, _rDateTime.Minutes, _rDateTime.Seconds, _rDateTime.NanoSeconds); |
261 | 0 | _rOut = DateTime(aDate, aTime); |
262 | 0 | } |
263 | | |
264 | | OUString toISO8601(const css::util::DateTime& rDateTime) |
265 | 6.22k | { |
266 | 6.22k | OUStringBuffer rBuffer(32); |
267 | 6.22k | rBuffer.append(OUString::number(static_cast<sal_Int32>(rDateTime.Year)) + "-"); |
268 | 6.22k | if( rDateTime.Month < 10 ) |
269 | 6.22k | rBuffer.append('0'); |
270 | 6.22k | rBuffer.append(OUString::number(static_cast<sal_Int32>(rDateTime.Month)) + "-"); |
271 | 6.22k | if( rDateTime.Day < 10 ) |
272 | 0 | rBuffer.append('0'); |
273 | 6.22k | rBuffer.append(static_cast<sal_Int32>(rDateTime.Day)); |
274 | | |
275 | 6.22k | if( rDateTime.NanoSeconds != 0 || |
276 | 0 | rDateTime.Seconds != 0 || |
277 | 0 | rDateTime.Minutes != 0 || |
278 | 0 | rDateTime.Hours != 0 ) |
279 | 6.22k | { |
280 | 6.22k | rBuffer.append('T'); |
281 | 6.22k | if( rDateTime.Hours < 10 ) |
282 | 0 | rBuffer.append('0'); |
283 | 6.22k | rBuffer.append(OUString::number(static_cast<sal_Int32>(rDateTime.Hours)) + ":"); |
284 | 6.22k | if( rDateTime.Minutes < 10 ) |
285 | 0 | rBuffer.append('0'); |
286 | 6.22k | rBuffer.append(OUString::number(static_cast<sal_Int32>(rDateTime.Minutes)) + ":"); |
287 | 6.22k | if( rDateTime.Seconds < 10 ) |
288 | 3.16k | rBuffer.append('0'); |
289 | 6.22k | rBuffer.append(static_cast<sal_Int32>(rDateTime.Seconds)); |
290 | 6.22k | if ( rDateTime.NanoSeconds > 0) |
291 | 6.22k | { |
292 | 6.22k | OSL_ENSURE(rDateTime.NanoSeconds < 1000000000,"NanoSeconds cannot be more than 999 999 999"); |
293 | 6.22k | rBuffer.append(','); |
294 | 6.22k | std::ostringstream ostr; |
295 | 6.22k | ostr.fill('0'); |
296 | 6.22k | ostr.width(9); |
297 | 6.22k | ostr << rDateTime.NanoSeconds; |
298 | 6.22k | rBuffer.appendAscii(ostr.str().c_str()); |
299 | 6.22k | } |
300 | 6.22k | } |
301 | 6.22k | return rBuffer.makeStringAndClear(); |
302 | 6.22k | } |
303 | | |
304 | | /** convert ISO8601 DateTime String to util::DateTime */ |
305 | | bool ISO8601parseDateTime(std::u16string_view rString, css::util::DateTime& rDateTime) |
306 | 7.02k | { |
307 | 7.02k | bool bSuccess = true; |
308 | | |
309 | 7.02k | std::u16string_view aDateStr, aTimeStr; |
310 | 7.02k | css::util::Date aDate; |
311 | 7.02k | css::util::Time aTime; |
312 | 7.02k | size_t nPos = rString.find( 'T' ); |
313 | 7.02k | if ( nPos != std::u16string_view::npos ) |
314 | 5.18k | { |
315 | 5.18k | aDateStr = rString.substr( 0, nPos ); |
316 | 5.18k | aTimeStr = rString.substr( nPos + 1 ); |
317 | 5.18k | } |
318 | 1.83k | else |
319 | 1.83k | aDateStr = rString; // no separator: only date part |
320 | | |
321 | 7.02k | bSuccess = ISO8601parseDate(aDateStr, aDate); |
322 | | |
323 | 7.02k | if ( bSuccess && !aTimeStr.empty() ) // time is optional |
324 | 4.83k | { |
325 | 4.83k | bSuccess = ISO8601parseTime(aTimeStr, aTime); |
326 | 4.83k | } |
327 | | |
328 | 7.02k | if (bSuccess) |
329 | 3.65k | { |
330 | 3.65k | rDateTime = css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours, |
331 | 3.65k | aDate.Day, aDate.Month, aDate.Year, false); |
332 | 3.65k | } |
333 | | |
334 | 7.02k | return bSuccess; |
335 | 7.02k | } |
336 | | |
337 | | /** convert ISO8601 Date String to util::Date */ |
338 | | // TODO: supports only calendar dates YYYY-MM-DD |
339 | | // MISSING: calendar dates YYYYMMDD YYYY-MM |
340 | | // year, week date, ordinal date |
341 | | bool ISO8601parseDate(std::u16string_view aDateStr, css::util::Date& rDate) |
342 | 7.02k | { |
343 | 7.02k | const sal_Int32 nDateTokens {comphelper::string::getTokenCount(aDateStr, '-')}; |
344 | | |
345 | 7.02k | if (nDateTokens<1 || nDateTokens>3) |
346 | 211 | return false; |
347 | | |
348 | 6.81k | sal_Int32 nYear = 1899; |
349 | 6.81k | sal_Int32 nMonth = 12; |
350 | 6.81k | sal_Int32 nDay = 30; |
351 | | |
352 | 6.81k | sal_Int32 nIdx {0}; |
353 | 6.81k | auto strCurrentToken = o3tl::getToken(aDateStr, 0, '-', nIdx ); |
354 | 6.81k | if ( !convertNumber32( nYear, strCurrentToken, 0, 9999 ) ) |
355 | 1.77k | return false; |
356 | 5.03k | if ( nDateTokens >= 2 ) |
357 | 4.98k | { |
358 | 4.98k | strCurrentToken = o3tl::getToken(aDateStr, 0, '-', nIdx ); |
359 | 4.98k | if (strCurrentToken.size() > 2) |
360 | 78 | return false; |
361 | 4.91k | if ( !convertNumber32( nMonth, strCurrentToken, 0, 12 ) ) |
362 | 11 | return false; |
363 | 4.91k | } |
364 | 4.94k | if ( nDateTokens >= 3 ) |
365 | 1.79k | { |
366 | 1.79k | strCurrentToken = o3tl::getToken(aDateStr, 0, '-', nIdx ); |
367 | 1.79k | if (strCurrentToken.size() > 2) |
368 | 22 | return false; |
369 | 1.76k | if ( !convertNumber32( nDay, strCurrentToken, 0, 31 ) ) |
370 | 46 | return false; |
371 | 1.76k | } |
372 | | |
373 | 4.88k | rDate.Year = static_cast<sal_uInt16>(nYear); |
374 | 4.88k | rDate.Month = static_cast<sal_uInt16>(nMonth); |
375 | 4.88k | rDate.Day = static_cast<sal_uInt16>(nDay); |
376 | | |
377 | 4.88k | return true; |
378 | 4.94k | } |
379 | | |
380 | | /** convert ISO8601 Time String to util::Time */ |
381 | | bool ISO8601parseTime(std::u16string_view aTimeStr, css::util::Time& rTime) |
382 | 16.5k | { |
383 | 16.5k | sal_Int32 nHour = 0; |
384 | 16.5k | sal_Int32 nMin = 0; |
385 | 16.5k | sal_Int32 nSec = 0; |
386 | 16.5k | sal_Int32 nNanoSec = 0; |
387 | | |
388 | 16.5k | std::size_t n = 0; |
389 | 16.5k | OUString tokInt; |
390 | 16.5k | OUString tokFrac; |
391 | 16.5k | OUString tokTz; |
392 | 16.5k | bool bFrac = false; |
393 | | // hours |
394 | 16.5k | bool bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); |
395 | 16.5k | if (!bSuccess) |
396 | 5.42k | return false; |
397 | | |
398 | 11.1k | if ( bFrac && n < aTimeStr.size()) |
399 | 401 | { |
400 | | // is it junk or the timezone? |
401 | 401 | bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); |
402 | 401 | if (!bSuccess) |
403 | 177 | return false; |
404 | 401 | } |
405 | 10.9k | bSuccess = convertNumber32( nHour, tokInt, 0, 23 ); |
406 | 10.9k | if (!bSuccess) |
407 | 0 | return false; |
408 | | |
409 | 10.9k | if (bFrac) |
410 | 1.17k | { |
411 | 1.17k | sal_Int64 fracNumerator; |
412 | 1.17k | bSuccess = convertNumber64(fracNumerator, tokFrac); |
413 | 1.17k | if ( bSuccess ) |
414 | 1.17k | { |
415 | 1.17k | double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); |
416 | | // minutes |
417 | 1.17k | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac hours (of hours) not between 0 and 1"); |
418 | 1.17k | frac *= 60; |
419 | 1.17k | nMin = floor(frac); |
420 | 1.17k | frac -= nMin; |
421 | | // seconds |
422 | 1.17k | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac minutes (of hours) not between 0 and 1"); |
423 | 1.17k | frac *= 60; |
424 | 1.17k | nSec = floor(frac); |
425 | 1.17k | frac -= nSec; |
426 | | // nanoseconds |
427 | 1.17k | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of hours) not between 0 and 1"); |
428 | 1.17k | frac *= 1000000000; |
429 | 1.17k | nNanoSec = ::rtl::math::round(frac); |
430 | 1.17k | } |
431 | 1.17k | goto end; |
432 | 1.17k | } |
433 | 9.77k | if(n >= aTimeStr.size()) |
434 | 2.04k | goto end; |
435 | | |
436 | | // minutes |
437 | 7.72k | bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); |
438 | 7.72k | if (!bSuccess) |
439 | 763 | return false; |
440 | 6.96k | if ( bFrac && n < aTimeStr.size()) |
441 | 345 | { |
442 | | // is it junk or the timezone? |
443 | 345 | bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); |
444 | 345 | if (!bSuccess) |
445 | 218 | return false; |
446 | 345 | } |
447 | 6.74k | bSuccess = convertNumber32( nMin, tokInt, 0, 59 ); |
448 | 6.74k | if (!bSuccess) |
449 | 0 | return false; |
450 | 6.74k | if (bFrac) |
451 | 172 | { |
452 | 172 | sal_Int64 fracNumerator; |
453 | 172 | bSuccess = convertNumber64(fracNumerator, tokFrac); |
454 | 172 | if ( bSuccess ) |
455 | 172 | { |
456 | 172 | double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); |
457 | | // seconds |
458 | 172 | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac minutes (of minutes) not between 0 and 1"); |
459 | 172 | frac *= 60; |
460 | 172 | nSec = floor(frac); |
461 | 172 | frac -= nSec; |
462 | | // nanoseconds |
463 | 172 | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of minutes) not between 0 and 1"); |
464 | 172 | frac *= 1000000000; |
465 | 172 | nNanoSec = ::rtl::math::round(frac); |
466 | 172 | } |
467 | 172 | goto end; |
468 | 172 | } |
469 | 6.57k | if(n >= aTimeStr.size()) |
470 | 627 | goto end; |
471 | | |
472 | | // seconds |
473 | 5.94k | bSuccess = getISO8601TimeToken(aTimeStr, n, tokInt, bFrac, tokFrac); |
474 | 5.94k | if (!bSuccess) |
475 | 1.08k | return false; |
476 | 4.86k | if (n < aTimeStr.size()) |
477 | 1.36k | { |
478 | | // is it junk or the timezone? |
479 | 1.36k | bSuccess = getISO8601TimeZoneToken(aTimeStr, n, tokTz); |
480 | 1.36k | if (!bSuccess) |
481 | 930 | return false; |
482 | 1.36k | } |
483 | | // max 60 for leap seconds |
484 | 3.93k | bSuccess = convertNumber32( nSec, tokInt, 0, 60 ); |
485 | 3.93k | if (!bSuccess) |
486 | 0 | return false; |
487 | 3.93k | if (bFrac) |
488 | 3.59k | { |
489 | 3.59k | sal_Int64 fracNumerator; |
490 | 3.59k | bSuccess = convertNumber64(fracNumerator, tokFrac); |
491 | 3.59k | if ( bSuccess ) |
492 | 3.59k | { |
493 | 3.59k | double frac = static_cast<double>(fracNumerator) / pow(static_cast<double>(10), static_cast<double>(tokFrac.getLength())); |
494 | | // nanoseconds |
495 | 3.59k | OSL_ENSURE(frac < 1 && frac >= 0, "ISO8601parse internal error frac seconds (of seconds) not between 0 and 1"); |
496 | 3.59k | frac *= 1000000000; |
497 | 3.59k | nNanoSec = ::rtl::math::round(frac); |
498 | 3.59k | } |
499 | 3.59k | goto end; |
500 | 3.59k | } |
501 | | |
502 | 7.95k | end: |
503 | 7.95k | if (bSuccess) |
504 | 7.95k | { |
505 | | // normalise time |
506 | 7.95k | const int secondsOverflow = (nSec == 60) ? 61 : 60; |
507 | 7.95k | if (nNanoSec == 1000000000) |
508 | 218 | { |
509 | 218 | nNanoSec = 0; |
510 | 218 | ++nSec; |
511 | 218 | } |
512 | 7.95k | if(nSec == secondsOverflow) |
513 | 22 | { |
514 | 22 | nSec = 0; |
515 | 22 | ++nMin; |
516 | 22 | } |
517 | 7.95k | if(nMin == 60) |
518 | 26 | { |
519 | 26 | nMin = 0; |
520 | 26 | ++nHour; |
521 | 26 | } |
522 | 7.95k | if(!tokTz.isEmpty()) |
523 | 735 | rTime.IsUTC = (tokTz == "Z"); |
524 | | |
525 | 7.95k | rTime.Hours = static_cast<sal_uInt16>(nHour); |
526 | 7.95k | rTime.Minutes = static_cast<sal_uInt16>(nMin); |
527 | 7.95k | rTime.Seconds = static_cast<sal_uInt16>(nSec); |
528 | 7.95k | rTime.NanoSeconds = nNanoSec; |
529 | 7.95k | } |
530 | | |
531 | 7.95k | return bSuccess; |
532 | 3.93k | } |
533 | | |
534 | | } // namespace utl |
535 | | |
536 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |