Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/tools/source/datetime/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
#include <tools/datetime.hxx>
20
#include <tools/duration.hxx>
21
#include <rtl/math.hxx>
22
#include <sal/log.hxx>
23
#include <compare>
24
25
#include <systemdatetime.hxx>
26
27
DateTime::DateTime(DateTimeInitSystem)
28
6.67M
    : Date( Date::EMPTY )
29
6.67M
    , Time( Time::EMPTY )
30
6.67M
{
31
6.67M
    sal_Int32 nD = 0;
32
6.67M
    sal_Int64 nT = 0;
33
6.67M
    if ( GetSystemDateTime( &nD, &nT ) )
34
6.67M
    {
35
6.67M
        Date::operator=( Date( nD ) );
36
6.67M
        SetTime( nT );
37
6.67M
    }
38
0
    else
39
0
        Date::operator=( Date( 1, 1, 1900 ) ); // Time::nTime is already 0
40
6.67M
}
41
42
DateTime::DateTime( const css::util::DateTime& rDateTime )
43
64.7k
  : Date( rDateTime.Day, rDateTime.Month, rDateTime.Year ),
44
64.7k
    Time( rDateTime.Hours, rDateTime.Minutes, rDateTime.Seconds, rDateTime.NanoSeconds )
45
64.7k
{
46
64.7k
}
47
48
DateTime& DateTime::operator =( const css::util::DateTime& rUDateTime )
49
469
{
50
469
    Date::operator=( Date( rUDateTime.Day, rUDateTime.Month, rUDateTime.Year));
51
469
    Time::operator=( Time( rUDateTime));
52
469
    return *this;
53
469
}
54
55
bool DateTime::IsBetween( const DateTime& rFrom, const DateTime& rTo ) const
56
0
{
57
0
    return (*this >= rFrom) && (*this <= rTo);
58
0
}
59
60
sal_Int64 DateTime::GetSecFromDateTime( const Date& rDate ) const
61
0
{
62
0
    if (*this < rDate)
63
0
        return 0;
64
0
    else
65
0
    {
66
0
        sal_Int64 nSec = Date( *this ) - rDate;
67
0
        nSec *= 24UL*60*60;
68
0
        sal_Int64 nHour = GetHour();
69
0
        sal_Int64 nMin  = GetMin();
70
0
        nSec += (nHour*3600)+(nMin*60)+GetSec();
71
0
        return nSec;
72
0
    }
73
0
}
74
75
void DateTime::NormalizeTimeRemainderAndApply( tools::Time& rTime )
76
6.15M
{
77
6.15M
    sal_uInt16 nHours = rTime.GetHour();
78
6.15M
    if ( rTime.GetTime() > 0 )
79
6.15M
    {
80
6.15M
        if (nHours >= 24)
81
1.12k
        {
82
1.12k
            AddDays( nHours / 24 );
83
1.12k
            nHours %= 24;
84
1.12k
            rTime.SetHour( nHours );
85
1.12k
        }
86
6.15M
    }
87
57
    else if ( rTime.GetTime() != 0 )
88
0
    {
89
0
        if (nHours >= 24)
90
0
        {
91
0
            AddDays( -static_cast<sal_Int32>(nHours) / 24 );
92
0
            nHours %= 24;
93
0
            rTime.SetHour( nHours );
94
0
        }
95
0
        Date::operator--();
96
0
        rTime = Time( 24, 0, 0 ) + rTime;
97
0
    }
98
6.15M
    tools::Time::operator=( rTime );
99
6.15M
}
100
101
DateTime& DateTime::operator +=( const tools::Time& rTime )
102
164k
{
103
164k
    tools::Time aTime = *this;
104
164k
    aTime += rTime;
105
164k
    NormalizeTimeRemainderAndApply(aTime);
106
164k
    return *this;
107
164k
}
108
109
DateTime& DateTime::operator -=( const tools::Time& rTime )
110
5.99M
{
111
5.99M
    tools::Time aTime = *this;
112
5.99M
    aTime -= rTime;
113
5.99M
    NormalizeTimeRemainderAndApply(aTime);
114
5.99M
    return *this;
115
5.99M
}
116
117
DateTime& DateTime::operator +=( const tools::Duration& rDuration )
118
0
{
119
0
    AddDays(rDuration.GetDays());
120
0
    operator+=(rDuration.GetTime());
121
0
    return *this;
122
0
}
123
124
DateTime operator +( const DateTime& rDateTime, sal_Int32 nDays )
125
246k
{
126
246k
    DateTime aDateTime( rDateTime );
127
246k
    aDateTime.AddDays( nDays );
128
246k
    return aDateTime;
129
246k
}
130
131
DateTime operator -( const DateTime& rDateTime, sal_Int32 nDays )
132
0
{
133
0
    DateTime aDateTime( rDateTime );
134
0
    aDateTime.AddDays( -nDays );
135
0
    return aDateTime;
136
0
}
137
138
DateTime operator +( const DateTime& rDateTime, const tools::Time& rTime )
139
150k
{
140
150k
    DateTime aDateTime( rDateTime );
141
150k
    aDateTime += rTime;
142
150k
    return aDateTime;
143
150k
}
144
145
DateTime operator -( const DateTime& rDateTime, const tools::Time& rTime )
146
0
{
147
0
    DateTime aDateTime( rDateTime );
148
0
    aDateTime -= rTime;
149
0
    return aDateTime;
150
0
}
151
152
DateTime operator +( const DateTime& rDateTime, const tools::Duration& rDuration )
153
0
{
154
0
    DateTime aDateTime(rDateTime);
155
0
    aDateTime.AddDays( rDuration.GetDays());
156
0
    aDateTime += rDuration.GetTime();
157
0
    return aDateTime;
158
0
}
159
160
void DateTime::AddTime( double fTimeInDays )
161
0
{
162
    // Use Duration to diminish floating point accuracy errors.
163
0
    tools::Duration aDuration(fTimeInDays);
164
0
    operator+=(aDuration);
165
0
}
166
167
DateTime operator +( const DateTime& rDateTime, double fTimeInDays )
168
0
{
169
0
    DateTime aDateTime( rDateTime );
170
0
    aDateTime.AddTime( fTimeInDays );
171
0
    return aDateTime;
172
0
}
173
174
tools::Duration operator -( const DateTime& rDateTime1, const DateTime& rDateTime2 )
175
0
{
176
0
    return tools::Duration( rDateTime2, rDateTime1);
177
0
}
178
179
// static
180
double DateTime::Sub( const DateTime& rDateTime1, const DateTime& rDateTime2 )
181
711k
{
182
711k
    if (static_cast<const tools::Time&>(rDateTime1) != static_cast<const tools::Time&>(rDateTime2))
183
39.1k
    {
184
        // Use Duration to diminish floating point accuracy errors.
185
39.1k
        const tools::Duration aDuration( rDateTime2, rDateTime1);
186
39.1k
        return aDuration.GetInDays();
187
39.1k
    }
188
672k
    return static_cast<const Date&>(rDateTime1) - static_cast<const Date&>(rDateTime2);
189
711k
}
190
191
void DateTime::GetWin32FileDateTime( sal_uInt32 & rLower, sal_uInt32 & rUpper ) const
192
0
{
193
0
    const sal_Int64 a100nPerSecond = SAL_CONST_INT64( 10000000 );
194
0
    const sal_Int64 a100nPerDay = a100nPerSecond * sal_Int64( 60 * 60 * 24 );
195
196
    // FILETIME is indirectly documented as uint64, see
197
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
198
    // mentioning the ULARGE_INTEGER structure.
199
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724280.aspx
200
    // mentions that if FILETIME is not less than 0x8000000000000000 then the
201
    // FileTimeToSystemTime function fails, which is another indicator.
202
    // Unless there's evidence that FILETIME can represent a signed offset from
203
    // 1601-01-01 truncate at 0. (reading part below in
204
    // CreateFromWin32FileDateTime() would had to be adapted to signed as
205
    // well).
206
0
    sal_Int16 nYear = GetYear();
207
0
    SAL_WARN_IF( nYear < 1601, "tools.datetime", "DateTime::GetWin32FileDateTime - year < 1601: " << nYear);
208
209
0
    sal_Int64 aTime = (nYear < 1601 ? 0 : (
210
0
        a100nPerDay * (*this - Date(1,1,1601)) +
211
0
        GetNSFromTime()/100));
212
213
0
    rLower = sal_uInt32( aTime % SAL_CONST_UINT64( 0x100000000 ) );
214
0
    rUpper = sal_uInt32( aTime / SAL_CONST_UINT64( 0x100000000 ) );
215
0
}
216
217
DateTime DateTime::CreateFromWin32FileDateTime( sal_uInt32 rLower, sal_uInt32 rUpper )
218
23.4k
{
219
    // (rUpper|rLower) = 100-nanosecond intervals since 1601-01-01 00:00
220
23.4k
    const sal_uInt64 a100nPerSecond = SAL_CONST_UINT64( 10000000 );
221
23.4k
    const sal_uInt64 a100nPerDay = a100nPerSecond * sal_uInt64( 60 * 60 * 24 );
222
223
23.4k
    sal_uInt64 aTime =
224
23.4k
            sal_uInt64( rUpper ) * SAL_CONST_UINT64( 0x100000000 ) +
225
23.4k
            sal_uInt64( rLower );
226
227
23.4k
    SAL_WARN_IF( static_cast<sal_Int64>(aTime) < 0, "tools.datetime",
228
23.4k
            "DateTime::CreateFromWin32FileDateTime - absurdly high value expected?");
229
230
23.4k
    sal_uInt64 nDays = aTime / a100nPerDay;
231
232
23.4k
    Date aDate(1,1,1601);
233
    // (0xffffffffffffffff / a100nPerDay = 21350398) fits into sal_Int32
234
    // (0x7fffffff = 2147483647)
235
23.4k
    aDate.AddDays(nDays);
236
237
23.4k
    SAL_WARN_IF( aDate - Date(1,1,1601) != static_cast<sal_Int32>(nDays), "tools.datetime",
238
23.4k
            "DateTime::CreateFromWin32FileDateTime - date truncated to max");
239
240
23.4k
    sal_uInt64 nNanos = (aTime - (nDays * a100nPerDay)) * 100;
241
23.4k
    return DateTime( aDate, tools::Time(
242
23.4k
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerHour)   % sal_uInt64( 24 )),
243
23.4k
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerMinute) % sal_uInt64( 60 )),
244
23.4k
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerSec)    % sal_uInt64( 60 )),
245
23.4k
                static_cast<sal_uInt64>( nNanos % tools::Time::nanoSecPerSec)));
246
23.4k
}
247
248
DateTime DateTime::CreateFromUnixTime(const double fSecondsSinceEpoch)
249
0
{
250
0
    double fValue = fSecondsSinceEpoch / Time::secondPerDay;
251
0
    const sal_Int32 nDays = static_cast <sal_Int32>(::rtl::math::approxFloor(fValue));
252
253
0
    Date aDate (1, 1, 1970);
254
0
    aDate.AddDays(nDays);
255
0
    SAL_WARN_IF(aDate - Date(1, 1, 1970) != nDays, "tools.datetime",
256
0
                "DateTime::CreateFromUnixTime - date truncated to max");
257
258
0
    fValue -= nDays;
259
260
0
    const sal_uInt64 nNanos = fValue * tools::Time::nanoSecPerDay;
261
0
    return DateTime( aDate, tools::Time(
262
0
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerHour)   % sal_uInt64( 24 )),
263
0
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerMinute) % sal_uInt64( 60 )),
264
0
                static_cast<sal_uInt32>((nNanos / tools::Time::nanoSecPerSec)    % sal_uInt64( 60 )),
265
0
                static_cast<sal_uInt64>( nNanos % tools::Time::nanoSecPerSec)));
266
0
}
267
268
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */