2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "juce_StandardHeader.h"
29 #pragma warning (push)
30 #pragma warning (disable: 4514)
39 #include <sys/timeb.h>
45 #define USE_NEW_SECURE_TIME_FNS
51 #include "juce_Time.h"
52 #include "../threads/juce_Thread.h"
53 #include "../memory/juce_MemoryBlock.h"
54 #include "../text/juce_LocalisedStrings.h"
56 //==============================================================================
59 struct tm
millisToLocal (const int64 millis
) noexcept
62 const int64 seconds
= millis
/ 1000;
64 if (seconds
< literal64bit (86400) || seconds
>= literal64bit (2145916800))
66 // use extended maths for dates beyond 1970 to 2037..
67 const int timeZoneAdjustment
= 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
68 const int64 jdm
= seconds
+ timeZoneAdjustment
+ literal64bit (210866803200);
70 const int days
= (int) (jdm
/ literal64bit (86400));
71 const int a
= 32044 + days
;
72 const int b
= (4 * a
+ 3) / 146097;
73 const int c
= a
- (b
* 146097) / 4;
74 const int d
= (4 * c
+ 3) / 1461;
75 const int e
= c
- (d
* 1461) / 4;
76 const int m
= (5 * e
+ 2) / 153;
78 result
.tm_mday
= e
- (153 * m
+ 2) / 5 + 1;
79 result
.tm_mon
= m
+ 2 - 12 * (m
/ 10);
80 result
.tm_year
= b
* 100 + d
- 6700 + (m
/ 10);
81 result
.tm_wday
= (days
+ 1) % 7;
84 int t
= (int) (jdm
% literal64bit (86400));
85 result
.tm_hour
= t
/ 3600;
87 result
.tm_min
= t
/ 60;
88 result
.tm_sec
= t
% 60;
93 time_t now
= static_cast <time_t> (seconds
);
96 #ifdef USE_NEW_SECURE_TIME_FNS
97 if (now
>= 0 && now
<= 0x793406fff)
98 localtime_s (&result
, &now
);
102 result
= *localtime (&now
);
106 localtime_r (&now
, &result
); // more thread-safe
113 int extendedModulo (const int64 value
, const int modulo
) noexcept
115 return (int) (value
>= 0 ? (value
% modulo
)
116 : (value
- ((value
/ modulo
) + 1) * modulo
));
119 int doFTime (CharPointer_UTF32 dest
, const int maxChars
, const String
& format
, const struct tm
* const tm
) noexcept
122 HeapBlock
<char> tempDest
;
123 tempDest
.calloc (maxChars
+ 2);
124 const int result
= (int) strftime (tempDest
, maxChars
, format
.toUTF8(), tm
);
126 dest
.writeAll (CharPointer_UTF8 (tempDest
.getData()));
129 HeapBlock
<wchar_t> tempDest
;
130 tempDest
.calloc (maxChars
+ 2);
131 const int result
= (int) wcsftime (tempDest
, maxChars
, format
.toWideCharPointer(), tm
);
133 dest
.writeAll (CharPointer_UTF16 (tempDest
.getData()));
136 return (int) wcsftime (dest
.getAddress(), maxChars
, format
.toUTF32(), tm
);
140 static uint32 lastMSCounterValue
= 0;
143 //==============================================================================
144 Time::Time() noexcept
145 : millisSinceEpoch (0)
149 Time::Time (const Time
& other
) noexcept
150 : millisSinceEpoch (other
.millisSinceEpoch
)
154 Time::Time (const int64 ms
) noexcept
155 : millisSinceEpoch (ms
)
159 Time::Time (const int year
,
165 const int milliseconds
,
166 const bool useLocalTime
) noexcept
168 jassert (year
> 100); // year must be a 4-digit version
170 if (year
< 1971 || year
>= 2038 || ! useLocalTime
)
172 // use extended maths for dates beyond 1970 to 2037..
173 const int timeZoneAdjustment
= useLocalTime
? (31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000))
175 const int a
= (13 - month
) / 12;
176 const int y
= year
+ 4800 - a
;
177 const int jd
= day
+ (153 * (month
+ 12 * a
- 2) + 2) / 5
178 + (y
* 365) + (y
/ 4) - (y
/ 100) + (y
/ 400)
181 const int64 s
= ((int64
) jd
) * literal64bit (86400) - literal64bit (210866803200);
183 millisSinceEpoch
= 1000 * (s
+ (hours
* 3600 + minutes
* 60 + seconds
- timeZoneAdjustment
))
189 t
.tm_year
= year
- 1900;
197 millisSinceEpoch
= 1000 * (int64
) mktime (&t
);
199 if (millisSinceEpoch
< 0)
200 millisSinceEpoch
= 0;
202 millisSinceEpoch
+= milliseconds
;
206 Time::~Time() noexcept
210 Time
& Time::operator= (const Time
& other
) noexcept
212 millisSinceEpoch
= other
.millisSinceEpoch
;
216 //==============================================================================
217 int64
Time::currentTimeMillis() noexcept
219 static uint32 lastCounterResult
= 0xffffffff;
220 static int64 correction
= 0;
222 const uint32 now
= getMillisecondCounter();
224 // check the counter hasn't wrapped (also triggered the first time this function is called)
225 if (now
< lastCounterResult
)
227 // double-check it's actually wrapped, in case multi-cpu machines have timers that drift a bit.
228 if (lastCounterResult
== 0xffffffff || now
< lastCounterResult
- 10)
230 // get the time once using normal library calls, and store the difference needed to
231 // turn the millisecond counter into a real time.
234 #ifdef USE_NEW_SECURE_TIME_FNS
239 correction
= (((int64
) t
.time
) * 1000 + t
.millitm
) - now
;
243 gettimeofday (&tv
, &tz
);
244 correction
= (((int64
) tv
.tv_sec
) * 1000 + tv
.tv_usec
/ 1000) - now
;
249 lastCounterResult
= now
;
251 return correction
+ now
;
254 //==============================================================================
255 uint32
juce_millisecondsSinceStartup() noexcept
;
257 uint32
Time::getMillisecondCounter() noexcept
259 const uint32 now
= juce_millisecondsSinceStartup();
261 if (now
< TimeHelpers::lastMSCounterValue
)
263 // in multi-threaded apps this might be called concurrently, so
264 // make sure that our last counter value only increases and doesn't
266 if (now
< TimeHelpers::lastMSCounterValue
- 1000)
267 TimeHelpers::lastMSCounterValue
= now
;
271 TimeHelpers::lastMSCounterValue
= now
;
277 uint32
Time::getApproximateMillisecondCounter() noexcept
279 if (TimeHelpers::lastMSCounterValue
== 0)
280 getMillisecondCounter();
282 return TimeHelpers::lastMSCounterValue
;
285 void Time::waitForMillisecondCounter (const uint32 targetTime
) noexcept
289 const uint32 now
= getMillisecondCounter();
291 if (now
>= targetTime
)
294 const int toWait
= targetTime
- now
;
298 Thread::sleep (jmin (20, toWait
>> 1));
302 // xxx should consider using mutex_pause on the mac as it apparently
303 // makes it seem less like a spinlock and avoids lowering the thread pri.
304 for (int i
= 10; --i
>= 0;)
310 //==============================================================================
311 double Time::highResolutionTicksToSeconds (const int64 ticks
) noexcept
313 return ticks
/ (double) getHighResolutionTicksPerSecond();
316 int64
Time::secondsToHighResolutionTicks (const double seconds
) noexcept
318 return (int64
) (seconds
* (double) getHighResolutionTicksPerSecond());
322 //==============================================================================
323 Time JUCE_CALLTYPE
Time::getCurrentTime() noexcept
325 return Time (currentTimeMillis());
328 //==============================================================================
329 String
Time::toString (const bool includeDate
,
330 const bool includeTime
,
331 const bool includeSeconds
,
332 const bool use24HourClock
) const noexcept
338 result
<< getDayOfMonth() << ' '
339 << getMonthName (true) << ' '
348 const int mins
= getMinutes();
350 result
<< (use24HourClock
? getHours() : getHoursInAmPmFormat())
351 << (mins
< 10 ? ":0" : ":") << mins
;
355 const int secs
= getSeconds();
356 result
<< (secs
< 10 ? ":0" : ":") << secs
;
359 if (! use24HourClock
)
360 result
<< (isAfternoon() ? "pm" : "am");
363 return result
.trimEnd();
366 String
Time::formatted (const String
& format
) const
368 int bufferSize
= 128;
369 HeapBlock
<juce_wchar
> buffer (128);
371 struct tm
t (TimeHelpers::millisToLocal (millisSinceEpoch
));
373 while (TimeHelpers::doFTime (CharPointer_UTF32 (buffer
.getData()), bufferSize
, format
, &t
) <= 0)
376 buffer
.malloc (bufferSize
);
379 return CharPointer_UTF32 (buffer
.getData());
382 //==============================================================================
383 int Time::getYear() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_year
+ 1900; }
384 int Time::getMonth() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_mon
; }
385 int Time::getDayOfMonth() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_mday
; }
386 int Time::getDayOfWeek() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_wday
; }
387 int Time::getHours() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_hour
; }
388 int Time::getMinutes() const noexcept
{ return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_min
; }
389 int Time::getSeconds() const noexcept
{ return TimeHelpers::extendedModulo (millisSinceEpoch
/ 1000, 60); }
390 int Time::getMilliseconds() const noexcept
{ return TimeHelpers::extendedModulo (millisSinceEpoch
, 1000); }
392 int Time::getHoursInAmPmFormat() const noexcept
394 const int hours
= getHours();
398 else if (hours
<= 12)
404 bool Time::isAfternoon() const noexcept
406 return getHours() >= 12;
409 bool Time::isDaylightSavingTime() const noexcept
411 return TimeHelpers::millisToLocal (millisSinceEpoch
).tm_isdst
!= 0;
414 String
Time::getTimeZone() const noexcept
421 #ifdef USE_NEW_SECURE_TIME_FNS
422 for (int i
= 0; i
< 2; ++i
)
424 char name
[128] = { 0 };
426 _get_tzname (&length
, name
, 127, i
);
430 const char** const zonePtr
= (const char**) _tzname
;
431 zone
[0] = zonePtr
[0];
432 zone
[1] = zonePtr
[1];
436 const char** const zonePtr
= (const char**) tzname
;
437 zone
[0] = zonePtr
[0];
438 zone
[1] = zonePtr
[1];
441 if (isDaylightSavingTime())
445 if (zone
[0].length() > 3
446 && zone
[0].containsIgnoreCase ("daylight")
447 && zone
[0].contains ("GMT"))
451 return zone
[0].substring (0, 3);
454 String
Time::getMonthName (const bool threeLetterVersion
) const
456 return getMonthName (getMonth(), threeLetterVersion
);
459 String
Time::getWeekdayName (const bool threeLetterVersion
) const
461 return getWeekdayName (getDayOfWeek(), threeLetterVersion
);
464 String
Time::getMonthName (int monthNumber
, const bool threeLetterVersion
)
466 const char* const shortMonthNames
[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
467 const char* const longMonthNames
[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
471 return TRANS (threeLetterVersion
? shortMonthNames
[monthNumber
]
472 : longMonthNames
[monthNumber
]);
475 String
Time::getWeekdayName (int day
, const bool threeLetterVersion
)
477 const char* const shortDayNames
[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
478 const char* const longDayNames
[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
482 return TRANS (threeLetterVersion
? shortDayNames
[day
]
483 : longDayNames
[day
]);
486 //==============================================================================
487 Time
& Time::operator+= (const RelativeTime
& delta
) { millisSinceEpoch
+= delta
.inMilliseconds(); return *this; }
488 Time
& Time::operator-= (const RelativeTime
& delta
) { millisSinceEpoch
-= delta
.inMilliseconds(); return *this; }
490 Time
operator+ (const Time
& time
, const RelativeTime
& delta
) { Time
t (time
); return t
+= delta
; }
491 Time
operator- (const Time
& time
, const RelativeTime
& delta
) { Time
t (time
); return t
-= delta
; }
492 Time
operator+ (const RelativeTime
& delta
, const Time
& time
) { Time
t (time
); return t
+= delta
; }
493 const RelativeTime
operator- (const Time
& time1
, const Time
& time2
) { return RelativeTime::milliseconds (time1
.toMilliseconds() - time2
.toMilliseconds()); }
495 bool operator== (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() == time2
.toMilliseconds(); }
496 bool operator!= (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() != time2
.toMilliseconds(); }
497 bool operator< (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() < time2
.toMilliseconds(); }
498 bool operator> (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() > time2
.toMilliseconds(); }
499 bool operator<= (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() <= time2
.toMilliseconds(); }
500 bool operator>= (const Time
& time1
, const Time
& time2
) { return time1
.toMilliseconds() >= time2
.toMilliseconds(); }