/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: */ |