Blindly add a few stuff from VST
[juce-lv2.git] / juce / source / src / core / juce_Time.cpp
blob3298a5d11e5c030572ac38887a2856f0f92c0fc8
1 /*
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"
28 #if JUCE_MSVC
29 #pragma warning (push)
30 #pragma warning (disable: 4514)
31 #endif
33 #ifndef JUCE_WINDOWS
34 #include <sys/time.h>
35 #else
36 #include <ctime>
37 #endif
39 #include <sys/timeb.h>
41 #if JUCE_MSVC
42 #pragma warning (pop)
44 #ifdef _INC_TIME_INL
45 #define USE_NEW_SECURE_TIME_FNS
46 #endif
47 #endif
49 BEGIN_JUCE_NAMESPACE
51 #include "juce_Time.h"
52 #include "../threads/juce_Thread.h"
53 #include "../memory/juce_MemoryBlock.h"
54 #include "../text/juce_LocalisedStrings.h"
56 //==============================================================================
57 namespace TimeHelpers
59 struct tm millisToLocal (const int64 millis) noexcept
61 struct tm result;
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;
82 result.tm_yday = -1;
84 int t = (int) (jdm % literal64bit (86400));
85 result.tm_hour = t / 3600;
86 t %= 3600;
87 result.tm_min = t / 60;
88 result.tm_sec = t % 60;
89 result.tm_isdst = -1;
91 else
93 time_t now = static_cast <time_t> (seconds);
95 #if JUCE_WINDOWS
96 #ifdef USE_NEW_SECURE_TIME_FNS
97 if (now >= 0 && now <= 0x793406fff)
98 localtime_s (&result, &now);
99 else
100 zerostruct (result);
101 #else
102 result = *localtime (&now);
103 #endif
104 #else
106 localtime_r (&now, &result); // more thread-safe
107 #endif
110 return result;
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
121 #if JUCE_ANDROID
122 HeapBlock <char> tempDest;
123 tempDest.calloc (maxChars + 2);
124 const int result = (int) strftime (tempDest, maxChars, format.toUTF8(), tm);
125 if (result > 0)
126 dest.writeAll (CharPointer_UTF8 (tempDest.getData()));
127 return result;
128 #elif JUCE_WINDOWS
129 HeapBlock <wchar_t> tempDest;
130 tempDest.calloc (maxChars + 2);
131 const int result = (int) wcsftime (tempDest, maxChars, format.toWideCharPointer(), tm);
132 if (result > 0)
133 dest.writeAll (CharPointer_UTF16 (tempDest.getData()));
134 return result;
135 #else
136 return (int) wcsftime (dest.getAddress(), maxChars, format.toUTF32(), tm);
137 #endif
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,
160 const int month,
161 const int day,
162 const int hours,
163 const int minutes,
164 const int seconds,
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))
174 : 0;
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)
179 - 32045;
181 const int64 s = ((int64) jd) * literal64bit (86400) - literal64bit (210866803200);
183 millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
184 + milliseconds;
186 else
188 struct tm t;
189 t.tm_year = year - 1900;
190 t.tm_mon = month;
191 t.tm_mday = day;
192 t.tm_hour = hours;
193 t.tm_min = minutes;
194 t.tm_sec = seconds;
195 t.tm_isdst = -1;
197 millisSinceEpoch = 1000 * (int64) mktime (&t);
199 if (millisSinceEpoch < 0)
200 millisSinceEpoch = 0;
201 else
202 millisSinceEpoch += milliseconds;
206 Time::~Time() noexcept
210 Time& Time::operator= (const Time& other) noexcept
212 millisSinceEpoch = other.millisSinceEpoch;
213 return *this;
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.
232 #if JUCE_WINDOWS
233 struct _timeb t;
234 #ifdef USE_NEW_SECURE_TIME_FNS
235 _ftime_s (&t);
236 #else
237 _ftime (&t);
238 #endif
239 correction = (((int64) t.time) * 1000 + t.millitm) - now;
240 #else
241 struct timeval tv;
242 struct timezone tz;
243 gettimeofday (&tv, &tz);
244 correction = (((int64) tv.tv_sec) * 1000 + tv.tv_usec / 1000) - now;
245 #endif
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
265 // go backwards..
266 if (now < TimeHelpers::lastMSCounterValue - 1000)
267 TimeHelpers::lastMSCounterValue = now;
269 else
271 TimeHelpers::lastMSCounterValue = now;
274 return 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
287 for (;;)
289 const uint32 now = getMillisecondCounter();
291 if (now >= targetTime)
292 break;
294 const int toWait = targetTime - now;
296 if (toWait > 2)
298 Thread::sleep (jmin (20, toWait >> 1));
300 else
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;)
305 Thread::yield();
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
334 String result;
336 if (includeDate)
338 result << getDayOfMonth() << ' '
339 << getMonthName (true) << ' '
340 << getYear();
342 if (includeTime)
343 result << ' ';
346 if (includeTime)
348 const int mins = getMinutes();
350 result << (use24HourClock ? getHours() : getHoursInAmPmFormat())
351 << (mins < 10 ? ":0" : ":") << mins;
353 if (includeSeconds)
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)
375 bufferSize += 128;
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();
396 if (hours == 0)
397 return 12;
398 else if (hours <= 12)
399 return hours;
400 else
401 return 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
416 String zone[2];
418 #if JUCE_WINDOWS
419 _tzset();
421 #ifdef USE_NEW_SECURE_TIME_FNS
422 for (int i = 0; i < 2; ++i)
424 char name[128] = { 0 };
425 size_t length;
426 _get_tzname (&length, name, 127, i);
427 zone[i] = name;
429 #else
430 const char** const zonePtr = (const char**) _tzname;
431 zone[0] = zonePtr[0];
432 zone[1] = zonePtr[1];
433 #endif
434 #else
435 tzset();
436 const char** const zonePtr = (const char**) tzname;
437 zone[0] = zonePtr[0];
438 zone[1] = zonePtr[1];
439 #endif
441 if (isDaylightSavingTime())
443 zone[0] = zone[1];
445 if (zone[0].length() > 3
446 && zone[0].containsIgnoreCase ("daylight")
447 && zone[0].contains ("GMT"))
448 zone[0] = "BST";
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" };
469 monthNumber %= 12;
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" };
480 day %= 7;
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(); }
503 END_JUCE_NAMESPACE