The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

526 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #ifdef _MSC_VER
  24. #pragma warning (disable: 4514)
  25. #pragma warning (push)
  26. #endif
  27. #include "juce_StandardHeader.h"
  28. #ifndef JUCE_WIN32
  29. #include <sys/time.h>
  30. #else
  31. #include <ctime>
  32. #endif
  33. #include <sys/timeb.h>
  34. BEGIN_JUCE_NAMESPACE
  35. #include "juce_Time.h"
  36. #include "../threads/juce_Thread.h"
  37. #include "../containers/juce_MemoryBlock.h"
  38. #include "../text/juce_LocalisedStrings.h"
  39. #ifdef _MSC_VER
  40. #pragma warning (pop)
  41. #ifdef _INC_TIME_INL
  42. #define USE_NEW_SECURE_TIME_FNS
  43. #endif
  44. #endif
  45. //==============================================================================
  46. static void millisToLocal (const int64 millis, struct tm& result) throw()
  47. {
  48. const int64 seconds = millis / 1000;
  49. if (seconds < literal64bit (86400) || seconds >= literal64bit (2145916800))
  50. {
  51. // use extended maths for dates beyond 1970 to 2037..
  52. const int timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
  53. const int64 jdm = seconds + timeZoneAdjustment + literal64bit (210866803200);
  54. const int days = (int) (jdm / literal64bit (86400));
  55. const int a = 32044 + days;
  56. const int b = (4 * a + 3) / 146097;
  57. const int c = a - (b * 146097) / 4;
  58. const int d = (4 * c + 3) / 1461;
  59. const int e = c - (d * 1461) / 4;
  60. const int m = (5 * e + 2) / 153;
  61. result.tm_mday = e - (153 * m + 2) / 5 + 1;
  62. result.tm_mon = m + 2 - 12 * (m / 10);
  63. result.tm_year = b * 100 + d - 6700 + (m / 10);
  64. result.tm_wday = (days + 1) % 7;
  65. result.tm_yday = -1;
  66. int t = (int) (jdm % literal64bit (86400));
  67. result.tm_hour = t / 3600;
  68. t %= 3600;
  69. result.tm_min = t / 60;
  70. result.tm_sec = t % 60;
  71. result.tm_isdst = -1;
  72. }
  73. else
  74. {
  75. time_t now = (time_t) (seconds);
  76. #if JUCE_WIN32
  77. #ifdef USE_NEW_SECURE_TIME_FNS
  78. if (now >= 0 && now <= 0x793406fff)
  79. localtime_s (&result, &now);
  80. else
  81. zeromem (&result, sizeof (result));
  82. #else
  83. result = *localtime (&now);
  84. #endif
  85. #else
  86. // more thread-safe
  87. localtime_r (&now, &result);
  88. #endif
  89. }
  90. }
  91. //==============================================================================
  92. Time::Time() throw()
  93. : millisSinceEpoch (0)
  94. {
  95. }
  96. Time::Time (const Time& other) throw()
  97. : millisSinceEpoch (other.millisSinceEpoch)
  98. {
  99. }
  100. Time::Time (const int64 ms) throw()
  101. : millisSinceEpoch (ms)
  102. {
  103. }
  104. Time::Time (const int year,
  105. const int month,
  106. const int day,
  107. const int hours,
  108. const int minutes,
  109. const int seconds,
  110. const int milliseconds) throw()
  111. {
  112. jassert (year > 100); // year must be a 4-digit version
  113. if (year < 1971 || year >= 2038)
  114. {
  115. // use extended maths for dates beyond 1970 to 2037..
  116. const int timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
  117. const int a = (13 - month) / 12;
  118. const int y = year + 4800 - a;
  119. const int jd = day + (153 * (month + 12 * a - 2) + 2) / 5
  120. + (y * 365) + (y / 4) - (y / 100) + (y / 400)
  121. - 32045;
  122. const int64 s = ((int64) jd) * literal64bit (86400) - literal64bit (210866803200);
  123. millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
  124. + milliseconds;
  125. }
  126. else
  127. {
  128. struct tm t;
  129. t.tm_year = year - 1900;
  130. t.tm_mon = month;
  131. t.tm_mday = day;
  132. t.tm_hour = hours;
  133. t.tm_min = minutes;
  134. t.tm_sec = seconds;
  135. t.tm_isdst = -1;
  136. millisSinceEpoch = 1000 * (int64) mktime (&t);
  137. if (millisSinceEpoch < 0)
  138. millisSinceEpoch = 0;
  139. else
  140. millisSinceEpoch += milliseconds;
  141. }
  142. }
  143. Time::~Time() throw()
  144. {
  145. }
  146. const Time& Time::operator= (const Time& other) throw()
  147. {
  148. millisSinceEpoch = other.millisSinceEpoch;
  149. return *this;
  150. }
  151. //==============================================================================
  152. int64 Time::currentTimeMillis() throw()
  153. {
  154. static uint32 lastCounterResult = 0xffffffff;
  155. static int64 correction = 0;
  156. const uint32 now = getMillisecondCounter();
  157. // check the counter hasn't wrapped (also triggered the first time this function is called)
  158. if (now < lastCounterResult)
  159. {
  160. // double-check it's actually wrapped, in case multi-cpu machines have timers that drift a bit.
  161. if (lastCounterResult == 0xffffffff || now < lastCounterResult - 10)
  162. {
  163. // get the time once using normal library calls, and store the difference needed to
  164. // turn the millisecond counter into a real time.
  165. #if JUCE_WIN32
  166. struct _timeb t;
  167. #ifdef USE_NEW_SECURE_TIME_FNS
  168. _ftime_s (&t);
  169. #else
  170. _ftime (&t);
  171. #endif
  172. correction = (((int64) t.time) * 1000 + t.millitm) - now;
  173. #else
  174. struct timeval tv;
  175. struct timezone tz;
  176. gettimeofday (&tv, &tz);
  177. correction = (((int64) tv.tv_sec) * 1000 + tv.tv_usec / 1000) - now;
  178. #endif
  179. }
  180. }
  181. lastCounterResult = now;
  182. return correction + now;
  183. }
  184. //==============================================================================
  185. uint32 juce_millisecondsSinceStartup() throw();
  186. static uint32 lastMSCounterValue = 0;
  187. uint32 Time::getMillisecondCounter() throw()
  188. {
  189. const uint32 now = juce_millisecondsSinceStartup();
  190. if (now < lastMSCounterValue)
  191. {
  192. // in multi-threaded apps this might be called concurrently, so
  193. // make sure that our last counter value only increases and doesn't
  194. // go backwards..
  195. if (now < lastMSCounterValue - 1000)
  196. lastMSCounterValue = now;
  197. }
  198. else
  199. {
  200. lastMSCounterValue = now;
  201. }
  202. return now;
  203. }
  204. uint32 Time::getApproximateMillisecondCounter() throw()
  205. {
  206. jassert (lastMSCounterValue != 0);
  207. return lastMSCounterValue;
  208. }
  209. void Time::waitForMillisecondCounter (const uint32 targetTime) throw()
  210. {
  211. for (;;)
  212. {
  213. const uint32 now = getMillisecondCounter();
  214. if (now >= targetTime)
  215. break;
  216. const int toWait = targetTime - now;
  217. if (toWait > 2)
  218. {
  219. Thread::sleep (jmin (20, toWait >> 1));
  220. }
  221. else
  222. {
  223. // xxx should consider using mutex_pause on the mac as it apparently
  224. // makes it seem less like a spinlock and avoids lowering the thread pri.
  225. for (int i = 10; --i >= 0;)
  226. Thread::yield();
  227. }
  228. }
  229. }
  230. //==============================================================================
  231. double Time::highResolutionTicksToSeconds (const int64 ticks) throw()
  232. {
  233. return ticks / (double) getHighResolutionTicksPerSecond();
  234. }
  235. int64 Time::secondsToHighResolutionTicks (const double seconds) throw()
  236. {
  237. return (int64) (seconds * (double) getHighResolutionTicksPerSecond());
  238. }
  239. //==============================================================================
  240. const Time JUCE_CALLTYPE Time::getCurrentTime() throw()
  241. {
  242. return Time (currentTimeMillis());
  243. }
  244. //==============================================================================
  245. const String Time::toString (const bool includeDate,
  246. const bool includeTime,
  247. const bool includeSeconds,
  248. const bool use24HourClock) const throw()
  249. {
  250. String result;
  251. if (includeDate)
  252. {
  253. result << getDayOfMonth() << ' '
  254. << getMonthName (true) << ' '
  255. << getYear();
  256. if (includeTime)
  257. result << ' ';
  258. }
  259. if (includeTime)
  260. {
  261. if (includeSeconds)
  262. {
  263. result += String::formatted (T("%d:%02d:%02d "),
  264. (use24HourClock) ? getHours()
  265. : getHoursInAmPmFormat(),
  266. getMinutes(),
  267. getSeconds());
  268. }
  269. else
  270. {
  271. result += String::formatted (T("%d.%02d"),
  272. (use24HourClock) ? getHours()
  273. : getHoursInAmPmFormat(),
  274. getMinutes());
  275. }
  276. if (! use24HourClock)
  277. result << (isAfternoon() ? "pm" : "am");
  278. }
  279. return result.trimEnd();
  280. }
  281. const String Time::formatted (const tchar* const format) const throw()
  282. {
  283. tchar buffer[80];
  284. struct tm t;
  285. millisToLocal (millisSinceEpoch, t);
  286. if (CharacterFunctions::ftime (buffer, 79, format, &t) <= 0)
  287. {
  288. int bufferSize = 128;
  289. for (;;)
  290. {
  291. MemoryBlock mb (bufferSize * sizeof (tchar));
  292. tchar* const b = (tchar*) mb.getData();
  293. if (CharacterFunctions::ftime (b, bufferSize, format, &t) > 0)
  294. return String (b);
  295. bufferSize += 128;
  296. }
  297. }
  298. return String (buffer);
  299. }
  300. //==============================================================================
  301. int Time::getYear() const throw()
  302. {
  303. struct tm t;
  304. millisToLocal (millisSinceEpoch, t);
  305. return t.tm_year + 1900;
  306. }
  307. int Time::getMonth() const throw()
  308. {
  309. struct tm t;
  310. millisToLocal (millisSinceEpoch, t);
  311. return t.tm_mon;
  312. }
  313. int Time::getDayOfMonth() const throw()
  314. {
  315. struct tm t;
  316. millisToLocal (millisSinceEpoch, t);
  317. return t.tm_mday;
  318. }
  319. int Time::getDayOfWeek() const throw()
  320. {
  321. struct tm t;
  322. millisToLocal (millisSinceEpoch, t);
  323. return t.tm_wday;
  324. }
  325. int Time::getHours() const throw()
  326. {
  327. struct tm t;
  328. millisToLocal (millisSinceEpoch, t);
  329. return t.tm_hour;
  330. }
  331. int Time::getHoursInAmPmFormat() const throw()
  332. {
  333. const int hours = getHours();
  334. if (hours == 0)
  335. return 12;
  336. else if (hours <= 12)
  337. return hours;
  338. else
  339. return hours - 12;
  340. }
  341. bool Time::isAfternoon() const throw()
  342. {
  343. return getHours() >= 12;
  344. }
  345. static int extendedModulo (const int64 value, const int modulo) throw()
  346. {
  347. return (int) (value >= 0 ? (value % modulo)
  348. : (value - ((value / modulo) + 1) * modulo));
  349. }
  350. int Time::getMinutes() const throw()
  351. {
  352. return extendedModulo (millisSinceEpoch / 60000, 60);
  353. }
  354. int Time::getSeconds() const throw()
  355. {
  356. return extendedModulo (millisSinceEpoch / 1000, 60);
  357. }
  358. int Time::getMilliseconds() const throw()
  359. {
  360. return extendedModulo (millisSinceEpoch, 1000);
  361. }
  362. bool Time::isDaylightSavingTime() const throw()
  363. {
  364. struct tm t;
  365. millisToLocal (millisSinceEpoch, t);
  366. return t.tm_isdst != 0;
  367. }
  368. const String Time::getTimeZone() const throw()
  369. {
  370. String zone[2];
  371. #if JUCE_WIN32
  372. _tzset();
  373. #ifdef USE_NEW_SECURE_TIME_FNS
  374. {
  375. char name [128];
  376. size_t length;
  377. for (int i = 0; i < 2; ++i)
  378. {
  379. zeromem (name, sizeof (name));
  380. _get_tzname (&length, name, 127, i);
  381. zone[i] = name;
  382. }
  383. }
  384. #else
  385. const char** const zonePtr = (const char**) _tzname;
  386. zone[0] = zonePtr[0];
  387. zone[1] = zonePtr[1];
  388. #endif
  389. #else
  390. tzset();
  391. const char** const zonePtr = (const char**) tzname;
  392. zone[0] = zonePtr[0];
  393. zone[1] = zonePtr[1];
  394. #endif
  395. if (isDaylightSavingTime())
  396. {
  397. zone[0] = zone[1];
  398. if (zone[0].length() > 3
  399. && zone[0].containsIgnoreCase (T("daylight"))
  400. && zone[0].contains (T("GMT")))
  401. zone[0] = "BST";
  402. }
  403. return zone[0].substring (0, 3);
  404. }
  405. const String Time::getMonthName (const bool threeLetterVersion) const throw()
  406. {
  407. return getMonthName (getMonth(), threeLetterVersion);
  408. }
  409. const String Time::getWeekdayName (const bool threeLetterVersion) const throw()
  410. {
  411. return getWeekdayName (getDayOfWeek(), threeLetterVersion);
  412. }
  413. const String Time::getMonthName (int monthNumber,
  414. const bool threeLetterVersion) throw()
  415. {
  416. const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  417. const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
  418. monthNumber %= 12;
  419. return TRANS (threeLetterVersion ? shortMonthNames [monthNumber]
  420. : longMonthNames [monthNumber]);
  421. }
  422. const String Time::getWeekdayName (int day,
  423. const bool threeLetterVersion) throw()
  424. {
  425. const char* const shortDayNames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  426. const char* const longDayNames[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
  427. day %= 7;
  428. return TRANS (threeLetterVersion ? shortDayNames [day]
  429. : longDayNames [day]);
  430. }
  431. END_JUCE_NAMESPACE