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