Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */