Line data Source code
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 : #if defined( WNT )
21 : #include <windows.h>
22 : #elif defined UNX
23 : #include <unistd.h>
24 : #include <limits.h>
25 : #include <math.h>
26 : #include <sys/time.h>
27 : #endif
28 :
29 : #include <time.h>
30 : #ifdef __MACH__
31 : #include <mach/clock.h>
32 : #include <mach/mach.h>
33 : #endif
34 : #include <tools/time.hxx>
35 :
36 : #include <osl/diagnose.h>
37 :
38 : #if defined(SOLARIS) && defined(__GNUC__)
39 : extern long altzone;
40 : #endif
41 :
42 : namespace {
43 :
44 : const sal_Int64 secMask = SAL_CONST_INT64(1000000000);
45 : const sal_Int64 minMask = SAL_CONST_INT64(100000000000);
46 : const sal_Int64 hourMask = SAL_CONST_INT64(10000000000000);
47 :
48 : const sal_Int64 nanoSecInSec = 1000000000;
49 : const sal_Int16 secInMin = 60;
50 : const sal_Int16 minInHour = 60;
51 :
52 2028 : sal_Int64 TimeToNanoSec( const tools::Time& rTime )
53 : {
54 2028 : short nSign = (rTime.GetTime() >= 0) ? +1 : -1;
55 2028 : sal_Int32 nHour = rTime.GetHour();
56 2028 : sal_Int32 nMin = rTime.GetMin();
57 2028 : sal_Int32 nSec = rTime.GetSec();
58 2028 : sal_Int32 nNanoSec = rTime.GetNanoSec();
59 :
60 2028 : sal_Int64 nRet = nNanoSec;
61 2028 : nRet += nSec * nanoSecInSec;
62 2028 : nRet += nMin * secInMin * nanoSecInSec;
63 2028 : nRet += nHour * minInHour * secInMin * nanoSecInSec;
64 :
65 2028 : return (nRet * nSign);
66 : }
67 :
68 1014 : tools::Time NanoSecToTime( sal_Int64 nNanoSec )
69 : {
70 : short nSign;
71 1014 : if ( nNanoSec < 0 )
72 : {
73 0 : nNanoSec *= -1;
74 0 : nSign = -1;
75 : }
76 : else
77 1014 : nSign = 1;
78 :
79 1014 : tools::Time aTime( 0, 0, 0, nNanoSec );
80 1014 : aTime.SetTime( aTime.GetTime() * nSign );
81 1014 : return aTime;
82 : }
83 :
84 : } // anonymous namespace
85 :
86 : namespace tools {
87 :
88 30082 : Time::Time( TimeInitSystem )
89 : {
90 : #if defined( WNT )
91 : SYSTEMTIME aDateTime;
92 : GetLocalTime( &aDateTime );
93 :
94 : // construct time
95 : nTime = aDateTime.wHour * hourMask +
96 : aDateTime.wMinute * minMask +
97 : aDateTime.wSecond * secMask +
98 : aDateTime.wMilliseconds * 1000000;
99 : #else
100 : // determine time
101 : struct timespec tsTime;
102 : #if defined( __MACH__ )
103 : // OS X does not have clock_gettime, use clock_get_time
104 : clock_serv_t cclock;
105 : mach_timespec_t mts;
106 : host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
107 : clock_get_time(cclock, &mts);
108 : mach_port_deallocate(mach_task_self(), cclock);
109 : tsTime.tv_sec = mts.tv_sec;
110 : tsTime.tv_nsec = mts.tv_nsec;
111 : #else
112 : // CLOCK_REALTIME should be supported
113 : // on any modern Unix, but be extra cautious
114 30082 : if (clock_gettime(CLOCK_REALTIME, &tsTime) != 0)
115 : {
116 : struct timeval tvTime;
117 0 : OSL_VERIFY( gettimeofday(&tvTime, NULL) != 0 );
118 0 : tsTime.tv_sec = tvTime.tv_sec;
119 0 : tsTime.tv_nsec = tvTime.tv_usec * 1000;
120 : }
121 : #endif // __MACH__
122 :
123 : // construct time
124 : struct tm aTime;
125 30082 : time_t nTmpTime = tsTime.tv_sec;
126 30082 : if ( localtime_r( &nTmpTime, &aTime ) )
127 : {
128 60164 : nTime = aTime.tm_hour * hourMask +
129 60164 : aTime.tm_min * minMask +
130 60164 : aTime.tm_sec * secMask +
131 30082 : tsTime.tv_nsec;
132 : }
133 : else
134 0 : nTime = 0;
135 : #endif // WNT
136 30082 : }
137 :
138 25644 : Time::Time( const tools::Time& rTime )
139 : {
140 25644 : nTime = rTime.nTime;
141 25644 : }
142 :
143 10038 : Time::Time( sal_uInt32 nHour, sal_uInt32 nMin, sal_uInt32 nSec, sal_uInt64 nNanoSec )
144 : {
145 10038 : init(nHour, nMin, nSec, nNanoSec);
146 10038 : }
147 210 : Time::Time( const ::com::sun::star::util::Time &_rTime )
148 : {
149 210 : init(_rTime.Hours, _rTime.Minutes, _rTime.Seconds, _rTime.NanoSeconds);
150 210 : }
151 10248 : void tools::Time::init( sal_uInt32 nHour, sal_uInt32 nMin, sal_uInt32 nSec, sal_uInt64 nNanoSec )
152 : {
153 : // normalize time
154 10248 : nSec += nNanoSec / nanoSecInSec;
155 10248 : nNanoSec %= nanoSecInSec;
156 10248 : nMin += nSec / secInMin;
157 10248 : nSec %= secInMin;
158 10248 : nHour += nMin / minInHour;
159 10248 : nMin %= minInHour;
160 :
161 : // construct time
162 : nTime = nNanoSec +
163 20496 : nSec * secMask +
164 20496 : nMin * minMask +
165 20496 : nHour * hourMask;
166 10248 : }
167 :
168 1094 : void tools::Time::SetHour( sal_uInt16 nNewHour )
169 : {
170 1094 : short nSign = (nTime >= 0) ? +1 : -1;
171 1094 : sal_Int32 nMin = GetMin();
172 1094 : sal_Int32 nSec = GetSec();
173 1094 : sal_Int32 nNanoSec = GetNanoSec();
174 :
175 2188 : nTime = nSign *
176 2188 : ( nNanoSec +
177 2188 : nSec * secMask +
178 2188 : nMin * minMask +
179 2188 : nNewHour * hourMask );
180 1094 : }
181 :
182 130 : void tools::Time::SetMin( sal_uInt16 nNewMin )
183 : {
184 130 : short nSign = (nTime >= 0) ? +1 : -1;
185 130 : sal_Int32 nHour = GetHour();
186 130 : sal_Int32 nSec = GetSec();
187 130 : sal_Int32 nNanoSec = GetNanoSec();
188 :
189 : // no overflow
190 130 : nNewMin = nNewMin % minInHour;
191 :
192 260 : nTime = nSign *
193 260 : ( nNanoSec +
194 260 : nSec * secMask +
195 260 : nNewMin * minMask +
196 260 : nHour * hourMask );
197 130 : }
198 :
199 5290 : void tools::Time::SetSec( sal_uInt16 nNewSec )
200 : {
201 5290 : short nSign = (nTime >= 0) ? +1 : -1;
202 5290 : sal_Int32 nHour = GetHour();
203 5290 : sal_Int32 nMin = GetMin();
204 5290 : sal_Int32 nNanoSec = GetNanoSec();
205 :
206 : // no overflow
207 5290 : nNewSec = nNewSec % secInMin;
208 :
209 10580 : nTime = nSign *
210 10580 : ( nNanoSec +
211 10580 : nNewSec * secMask +
212 10580 : nMin * minMask +
213 10580 : nHour * hourMask );
214 5290 : }
215 :
216 5194 : void tools::Time::SetNanoSec( sal_uInt32 nNewNanoSec )
217 : {
218 5194 : short nSign = (nTime >= 0) ? +1 : -1;
219 5194 : sal_Int32 nHour = GetHour();
220 5194 : sal_Int32 nMin = GetMin();
221 5194 : sal_Int32 nSec = GetSec();
222 :
223 : // no overflow
224 5194 : nNewNanoSec = nNewNanoSec % nanoSecInSec;
225 :
226 10388 : nTime = nSign *
227 10388 : ( nNewNanoSec +
228 10388 : nSec * secMask +
229 10388 : nMin * minMask +
230 10388 : nHour * hourMask );
231 5194 : }
232 :
233 6768 : sal_Int64 tools::Time::GetNSFromTime() const
234 : {
235 6768 : short nSign = (nTime >= 0) ? +1 : -1;
236 6768 : sal_Int32 nHour = GetHour();
237 6768 : sal_Int32 nMin = GetMin();
238 6768 : sal_Int32 nSec = GetSec();
239 6768 : sal_Int32 nNanoSec = GetNanoSec();
240 :
241 6768 : return nSign *
242 13536 : ( nNanoSec +
243 13536 : nSec * nanoSecInSec +
244 13536 : nMin * (secInMin * nanoSecInSec) +
245 13536 : nHour * (minInHour * secInMin * nanoSecInSec) );
246 : }
247 :
248 2 : void tools::Time::MakeTimeFromNS( sal_Int64 nNS )
249 : {
250 : short nSign;
251 2 : if ( nNS < 0 )
252 : {
253 0 : nNS *= -1;
254 0 : nSign = -1;
255 : }
256 : else
257 2 : nSign = 1;
258 :
259 : // avoid overflow when sal_uIntPtr is 32 bits
260 2 : tools::Time aTime( 0, 0, nNS/nanoSecInSec, nNS % nanoSecInSec );
261 2 : SetTime( aTime.GetTime() * nSign );
262 2 : }
263 :
264 0 : sal_Int32 tools::Time::GetMSFromTime() const
265 : {
266 0 : short nSign = (nTime >= 0) ? +1 : -1;
267 0 : sal_Int32 nHour = GetHour();
268 0 : sal_Int32 nMin = GetMin();
269 0 : sal_Int32 nSec = GetSec();
270 0 : sal_Int32 nNanoSec = GetNanoSec();
271 :
272 0 : return nSign *
273 0 : ( nNanoSec/1000000 +
274 0 : nSec * 1000 +
275 0 : nMin * 60000 +
276 0 : nHour * 360000 );
277 : }
278 :
279 0 : void tools::Time::MakeTimeFromMS( sal_Int32 nMS )
280 : {
281 : short nSign;
282 0 : if ( nMS < 0 )
283 : {
284 0 : nMS *= -1;
285 0 : nSign = -1;
286 : }
287 : else
288 0 : nSign = 1;
289 :
290 : // avoid overflow when sal_uIntPtr is 32 bits
291 0 : tools::Time aTime( 0, 0, nMS/1000, (nMS % 1000) * 1000000 );
292 0 : SetTime( aTime.GetTime() * nSign );
293 0 : }
294 :
295 0 : double tools::Time::GetTimeInDays() const
296 : {
297 0 : short nSign = (nTime >= 0) ? +1 : -1;
298 0 : double nHour = GetHour();
299 0 : double nMin = GetMin();
300 0 : double nSec = GetSec();
301 0 : double nNanoSec = GetNanoSec();
302 :
303 0 : return (nHour + (nMin / 60) + (nSec / (minInHour * secInMin)) + (nNanoSec / (minInHour * secInMin * nanoSecInSec))) / 24 * nSign;
304 : }
305 :
306 13138 : Time& tools::Time::operator =( const tools::Time& rTime )
307 : {
308 13138 : nTime = rTime.nTime;
309 13138 : return *this;
310 : }
311 :
312 732 : Time& tools::Time::operator +=( const tools::Time& rTime )
313 : {
314 732 : nTime = NanoSecToTime( TimeToNanoSec( *this ) +
315 732 : TimeToNanoSec( rTime ) ).GetTime();
316 732 : return *this;
317 : }
318 :
319 244 : Time& tools::Time::operator -=( const tools::Time& rTime )
320 : {
321 244 : nTime = NanoSecToTime( TimeToNanoSec( *this ) -
322 244 : TimeToNanoSec( rTime ) ).GetTime();
323 244 : return *this;
324 : }
325 :
326 0 : Time operator +( const tools::Time& rTime1, const tools::Time& rTime2 )
327 : {
328 0 : return NanoSecToTime( TimeToNanoSec( rTime1 ) +
329 0 : TimeToNanoSec( rTime2 ) );
330 : }
331 :
332 38 : Time operator -( const tools::Time& rTime1, const tools::Time& rTime2 )
333 : {
334 38 : return NanoSecToTime( TimeToNanoSec( rTime1 ) -
335 38 : TimeToNanoSec( rTime2 ) );
336 : }
337 :
338 0 : bool tools::Time::IsEqualIgnoreNanoSec( const tools::Time& rTime ) const
339 : {
340 0 : sal_Int32 n1 = (nTime < 0 ? -static_cast<sal_Int32>(GetNanoSec()) : GetNanoSec() );
341 0 : sal_Int32 n2 = (rTime.nTime < 0 ? -static_cast<sal_Int32>(rTime.GetNanoSec()) : rTime.GetNanoSec() );
342 0 : return (nTime - n1) == (rTime.nTime - n2);
343 : }
344 :
345 954 : Time tools::Time::GetUTCOffset()
346 : {
347 : #if defined( WNT )
348 : TIME_ZONE_INFORMATION aTimeZone;
349 : aTimeZone.Bias = 0;
350 : DWORD nTimeZoneRet = GetTimeZoneInformation( &aTimeZone );
351 : sal_Int32 nTempTime = aTimeZone.Bias;
352 : if ( nTimeZoneRet == TIME_ZONE_ID_STANDARD )
353 : nTempTime += aTimeZone.StandardBias;
354 : else if ( nTimeZoneRet == TIME_ZONE_ID_DAYLIGHT )
355 : nTempTime += aTimeZone.DaylightBias;
356 : tools::Time aTime( 0, (sal_uInt16)abs( nTempTime ) );
357 : if ( nTempTime > 0 )
358 : aTime = -aTime;
359 : return aTime;
360 : #else
361 : static sal_uIntPtr nCacheTicks = 0;
362 : static sal_Int32 nCacheSecOffset = -1;
363 954 : sal_uIntPtr nTicks = tools::Time::GetSystemTicks();
364 : time_t nTime;
365 : tm aTM;
366 : sal_Int32 nLocalTime;
367 : sal_Int32 nUTC;
368 : short nTempTime;
369 :
370 : // determine value again if needed
371 1880 : if ( (nCacheSecOffset == -1) ||
372 1852 : ((nTicks - nCacheTicks) > 360000) ||
373 926 : ( nTicks < nCacheTicks ) // handle overflow
374 : )
375 : {
376 28 : nTime = time( 0 );
377 28 : localtime_r( &nTime, &aTM );
378 28 : nLocalTime = mktime( &aTM );
379 : #if defined( SOLARIS )
380 : // Solaris gmtime_r() seems not to handle daylight saving time
381 : // flags correctly
382 : nUTC = nLocalTime + ( aTM.tm_isdst == 0 ? timezone : altzone );
383 : #elif defined( LINUX )
384 : // Linux mktime() seems not to handle tm_isdst correctly
385 28 : nUTC = nLocalTime - aTM.tm_gmtoff;
386 : #else
387 : gmtime_r( &nTime, &aTM );
388 : nUTC = mktime( &aTM );
389 : #endif
390 28 : nCacheTicks = nTicks;
391 28 : nCacheSecOffset = (nLocalTime-nUTC) / 60;
392 : }
393 :
394 954 : nTempTime = abs( nCacheSecOffset );
395 954 : tools::Time aTime( 0, (sal_uInt16)nTempTime );
396 954 : if ( nCacheSecOffset < 0 )
397 0 : aTime = -aTime;
398 954 : return aTime;
399 : #endif
400 : }
401 :
402 1367631 : sal_uIntPtr tools::Time::GetSystemTicks()
403 : {
404 : #if defined WNT
405 : static LARGE_INTEGER nTicksPerSecond;
406 : static bool bTicksPerSecondInitialized = false;
407 : if (!bTicksPerSecondInitialized)
408 : {
409 : QueryPerformanceFrequency(&nTicksPerSecond);
410 : bTicksPerSecondInitialized = true;
411 : }
412 :
413 : LARGE_INTEGER nPerformanceCount;
414 : QueryPerformanceCounter(&nPerformanceCount);
415 :
416 : return (sal_uIntPtr)((nPerformanceCount.QuadPart*1000)/nTicksPerSecond.QuadPart);
417 : #else
418 : timeval tv;
419 1367631 : gettimeofday (&tv, 0);
420 :
421 1367631 : double fTicks = tv.tv_sec;
422 1367631 : fTicks *= 1000;
423 1367631 : fTicks += ((tv.tv_usec + 500) / 1000);
424 :
425 1367631 : fTicks = fmod (fTicks, double(ULONG_MAX));
426 1367631 : return sal_uIntPtr(fTicks);
427 : #endif
428 : }
429 :
430 : } /* namespace tools */
431 :
432 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|