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 0 : sal_Int64 TimeToNanoSec( const Time& rTime )
53 : {
54 0 : short nSign = (rTime.GetTime() >= 0) ? +1 : -1;
55 0 : sal_Int32 nHour = rTime.GetHour();
56 0 : sal_Int32 nMin = rTime.GetMin();
57 0 : sal_Int32 nSec = rTime.GetSec();
58 0 : sal_Int32 nNanoSec = rTime.GetNanoSec();
59 :
60 0 : sal_Int64 nRet = nNanoSec;
61 0 : nRet += nSec * nanoSecInSec;
62 0 : nRet += nMin * secInMin * nanoSecInSec;
63 0 : nRet += nHour * minInHour * secInMin * nanoSecInSec;
64 :
65 0 : return (nRet * nSign);
66 : }
67 :
68 0 : Time NanoSecToTime( sal_Int64 nNanoSec )
69 : {
70 : short nSign;
71 0 : if ( nNanoSec < 0 )
72 : {
73 0 : nNanoSec *= -1;
74 0 : nSign = -1;
75 : }
76 : else
77 0 : nSign = 1;
78 :
79 0 : Time aTime( 0, 0, 0, nNanoSec );
80 0 : aTime.SetTime( aTime.GetTime() * nSign );
81 0 : return aTime;
82 : }
83 :
84 : } // anonymous namespace
85 :
86 0 : 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 0 : 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 0 : time_t nTmpTime = tsTime.tv_sec;
124 0 : if ( localtime_r( &nTmpTime, &aTime ) )
125 : {
126 0 : nTime = aTime.tm_hour * hourMask +
127 0 : aTime.tm_min * minMask +
128 0 : aTime.tm_sec * secMask +
129 0 : tsTime.tv_nsec;
130 : }
131 : else
132 0 : nTime = 0;
133 : #endif // WNT
134 0 : }
135 :
136 0 : Time::Time( const Time& rTime )
137 : {
138 0 : nTime = rTime.nTime;
139 0 : }
140 :
141 0 : Time::Time( sal_uInt32 nHour, sal_uInt32 nMin, sal_uInt32 nSec, sal_uInt64 nNanoSec )
142 : {
143 0 : init(nHour, nMin, nSec, nNanoSec);
144 0 : }
145 0 : Time::Time( const ::com::sun::star::util::Time &_rTime )
146 : {
147 0 : init(_rTime.Hours, _rTime.Minutes, _rTime.Seconds, _rTime.NanoSeconds);
148 0 : }
149 0 : void Time::init( sal_uInt32 nHour, sal_uInt32 nMin, sal_uInt32 nSec, sal_uInt64 nNanoSec )
150 : {
151 : // normalize time
152 0 : nSec += nNanoSec / nanoSecInSec;
153 0 : nNanoSec %= nanoSecInSec;
154 0 : nMin += nSec / secInMin;
155 0 : nSec %= secInMin;
156 0 : nHour += nMin / minInHour;
157 0 : nMin %= minInHour;
158 :
159 : // construct time
160 : nTime = nNanoSec +
161 0 : nSec * secMask +
162 0 : nMin * minMask +
163 0 : nHour * hourMask;
164 0 : }
165 :
166 0 : void Time::SetHour( sal_uInt16 nNewHour )
167 : {
168 0 : short nSign = (nTime >= 0) ? +1 : -1;
169 0 : sal_Int32 nMin = GetMin();
170 0 : sal_Int32 nSec = GetSec();
171 0 : sal_Int32 nNanoSec = GetNanoSec();
172 :
173 0 : nTime = nSign *
174 0 : ( nNanoSec +
175 0 : nSec * secMask +
176 0 : nMin * minMask +
177 0 : nNewHour * hourMask );
178 0 : }
179 :
180 0 : void Time::SetMin( sal_uInt16 nNewMin )
181 : {
182 0 : short nSign = (nTime >= 0) ? +1 : -1;
183 0 : sal_Int32 nHour = GetHour();
184 0 : sal_Int32 nSec = GetSec();
185 0 : sal_Int32 nNanoSec = GetNanoSec();
186 :
187 : // no overflow
188 0 : nNewMin = nNewMin % minInHour;
189 :
190 0 : nTime = nSign *
191 0 : ( nNanoSec +
192 0 : nSec * secMask +
193 0 : nNewMin * minMask +
194 0 : nHour * hourMask );
195 0 : }
196 :
197 0 : void Time::SetSec( sal_uInt16 nNewSec )
198 : {
199 0 : short nSign = (nTime >= 0) ? +1 : -1;
200 0 : sal_Int32 nHour = GetHour();
201 0 : sal_Int32 nMin = GetMin();
202 0 : sal_Int32 nNanoSec = GetNanoSec();
203 :
204 : // no overflow
205 0 : nNewSec = nNewSec % secInMin;
206 :
207 0 : nTime = nSign *
208 0 : ( nNanoSec +
209 0 : nNewSec * secMask +
210 0 : nMin * minMask +
211 0 : nHour * hourMask );
212 0 : }
213 :
214 0 : void Time::SetNanoSec( sal_uInt32 nNewNanoSec )
215 : {
216 0 : short nSign = (nTime >= 0) ? +1 : -1;
217 0 : sal_Int32 nHour = GetHour();
218 0 : sal_Int32 nMin = GetMin();
219 0 : sal_Int32 nSec = GetSec();
220 :
221 : // no overflow
222 0 : nNewNanoSec = nNewNanoSec % nanoSecInSec;
223 :
224 0 : nTime = nSign *
225 0 : ( nNewNanoSec +
226 0 : nSec * secMask +
227 0 : nMin * minMask +
228 0 : nHour * hourMask );
229 0 : }
230 :
231 0 : sal_Int64 Time::GetNSFromTime() const
232 : {
233 0 : short nSign = (nTime >= 0) ? +1 : -1;
234 0 : sal_Int32 nHour = GetHour();
235 0 : sal_Int32 nMin = GetMin();
236 0 : sal_Int32 nSec = GetSec();
237 0 : sal_Int32 nNanoSec = GetNanoSec();
238 :
239 0 : return nSign *
240 0 : ( nNanoSec +
241 0 : nSec * nanoSecInSec +
242 0 : nMin * (secInMin * nanoSecInSec) +
243 0 : 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 0 : Time& Time::operator =( const Time& rTime )
305 : {
306 0 : nTime = rTime.nTime;
307 0 : return *this;
308 : }
309 :
310 0 : Time& Time::operator +=( const Time& rTime )
311 : {
312 0 : nTime = NanoSecToTime( TimeToNanoSec( *this ) +
313 0 : TimeToNanoSec( rTime ) ).GetTime();
314 0 : return *this;
315 : }
316 :
317 0 : Time& Time::operator -=( const Time& rTime )
318 : {
319 0 : nTime = NanoSecToTime( TimeToNanoSec( *this ) -
320 0 : TimeToNanoSec( rTime ) ).GetTime();
321 0 : 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 0 : Time operator -( const Time& rTime1, const Time& rTime2 )
331 : {
332 0 : return NanoSecToTime( TimeToNanoSec( rTime1 ) -
333 0 : 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 0 : 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 0 : 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 0 : if ( (nCacheSecOffset == -1) ||
370 0 : ((nTicks - nCacheTicks) > 360000) ||
371 0 : ( nTicks < nCacheTicks ) // handle overflow
372 : )
373 : {
374 0 : nTime = time( 0 );
375 0 : localtime_r( &nTime, &aTM );
376 0 : 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 0 : nUTC = nLocalTime - aTM.tm_gmtoff;
384 : #else
385 : gmtime_r( &nTime, &aTM );
386 : nUTC = mktime( &aTM );
387 : #endif
388 0 : nCacheTicks = nTicks;
389 0 : nCacheSecOffset = (nLocalTime-nUTC) / 60;
390 : }
391 :
392 0 : nTempTime = abs( nCacheSecOffset );
393 0 : Time aTime( 0, (sal_uInt16)nTempTime );
394 0 : if ( nCacheSecOffset < 0 )
395 0 : aTime = -aTime;
396 0 : return aTime;
397 : #endif
398 : }
399 :
400 0 : sal_uIntPtr Time::GetSystemTicks()
401 : {
402 : #if defined WNT
403 : return (sal_uIntPtr)GetTickCount();
404 : #else
405 : timeval tv;
406 0 : gettimeofday (&tv, 0);
407 :
408 0 : double fTicks = tv.tv_sec;
409 0 : fTicks *= 1000;
410 0 : fTicks += ((tv.tv_usec + 500) / 1000);
411 :
412 0 : fTicks = fmod (fTicks, double(ULONG_MAX));
413 0 : return sal_uIntPtr(fTicks);
414 : #endif
415 : }
416 :
417 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|