mptTime.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * mptTime.cpp
  3. * -----------
  4. * Purpose: Various time utility functions.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "mptTime.h"
  11. #include "mptStringBuffer.h"
  12. #include <time.h>
  13. #if MPT_OS_WINDOWS
  14. #include <windows.h>
  15. #if defined(MODPLUG_TRACKER)
  16. #include <mmsystem.h>
  17. #endif
  18. #endif
  19. OPENMPT_NAMESPACE_BEGIN
  20. namespace mpt
  21. {
  22. namespace Date
  23. {
  24. #if defined(MODPLUG_TRACKER)
  25. #if MPT_OS_WINDOWS
  26. namespace ANSI
  27. {
  28. uint64 Now()
  29. {
  30. FILETIME filetime;
  31. GetSystemTimeAsFileTime(&filetime);
  32. return ((uint64)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime);
  33. }
  34. mpt::ustring ToUString(uint64 time100ns)
  35. {
  36. constexpr std::size_t bufsize = 256;
  37. mpt::ustring result;
  38. FILETIME filetime;
  39. SYSTEMTIME systime;
  40. filetime.dwHighDateTime = (DWORD)(((uint64)time100ns) >> 32);
  41. filetime.dwLowDateTime = (DWORD)((uint64)time100ns);
  42. FileTimeToSystemTime(&filetime, &systime);
  43. TCHAR buf[bufsize];
  44. GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, TEXT("yyyy-MM-dd"), buf, bufsize);
  45. result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
  46. result.append(U_(" "));
  47. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &systime, TEXT("HH:mm:ss"), buf, bufsize);
  48. result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
  49. result.append(U_("."));
  50. result.append(mpt::ufmt::dec0<3>((unsigned)systime.wMilliseconds));
  51. return result;
  52. }
  53. } // namespace ANSI
  54. #endif // MPT_OS_WINDOWS
  55. #endif // MODPLUG_TRACKER
  56. Unix::Unix()
  57. : Value(0)
  58. {
  59. return;
  60. }
  61. Unix::Unix(int64 unixtime)
  62. : Value(unixtime)
  63. {
  64. return;
  65. }
  66. Unix::operator int64 () const
  67. {
  68. return Value;
  69. }
  70. static int32 ToDaynum(int32 year, int32 month, int32 day)
  71. {
  72. month = (month + 9) % 12;
  73. year = year - (month / 10);
  74. int32 daynum = year*365 + year/4 - year/100 + year/400 + (month*306 + 5)/10 + (day - 1);
  75. return daynum;
  76. }
  77. static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day)
  78. {
  79. int64 g = d;
  80. int64 y,ddd,mi,mm,dd;
  81. y = (10000*g + 14780)/3652425;
  82. ddd = g - (365*y + y/4 - y/100 + y/400);
  83. if(ddd < 0)
  84. {
  85. y = y - 1;
  86. ddd = g - (365*y + y/4 - y/100 + y/400);
  87. }
  88. mi = (100*ddd + 52)/3060;
  89. mm = (mi + 2)%12 + 1;
  90. y = y + (mi + 2)/12;
  91. dd = ddd - (mi*306 + 5)/10 + 1;
  92. year = static_cast<int32>(y);
  93. month = static_cast<int32>(mm);
  94. day = static_cast<int32>(dd);
  95. }
  96. mpt::Date::Unix Unix::FromUTC(tm timeUtc)
  97. {
  98. int32 daynum = ToDaynum(timeUtc.tm_year+1900, timeUtc.tm_mon+1, timeUtc.tm_mday);
  99. int64 seconds = static_cast<int64>(daynum - ToDaynum(1970,1,1))*24*60*60 + timeUtc.tm_hour*60*60 + timeUtc.tm_min*60 + timeUtc.tm_sec;
  100. return mpt::Date::Unix(seconds);
  101. }
  102. tm Unix::AsUTC() const
  103. {
  104. int64 tmp = Value;
  105. int64 seconds = tmp % 60; tmp /= 60;
  106. int64 minutes = tmp % 60; tmp /= 60;
  107. int64 hours = tmp % 24; tmp /= 24;
  108. int32 year = 0, month = 0, day = 0;
  109. FromDaynum(static_cast<int32>(tmp) + ToDaynum(1970,1,1), year, month, day);
  110. tm result = {};
  111. result.tm_year = year - 1900;
  112. result.tm_mon = month - 1;
  113. result.tm_mday = day;
  114. result.tm_hour = static_cast<int32>(hours);
  115. result.tm_min = static_cast<int32>(minutes);
  116. result.tm_sec = static_cast<int32>(seconds);
  117. return result;
  118. }
  119. mpt::ustring ToShortenedISO8601(tm date)
  120. {
  121. // We assume date in UTC here.
  122. // There are too many differences in supported format specifiers in strftime()
  123. // and strftime does not support reduced precision ISO8601 at all.
  124. // Just do the formatting ourselves.
  125. mpt::ustring result;
  126. mpt::ustring tz = U_("Z");
  127. if(date.tm_year == 0)
  128. {
  129. return result;
  130. }
  131. result += mpt::ufmt::dec0<4>(date.tm_year + 1900);
  132. if(date.tm_mon < 0 || date.tm_mon > 11)
  133. {
  134. return result;
  135. }
  136. result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mon + 1);
  137. if(date.tm_mday < 1 || date.tm_mday > 31)
  138. {
  139. return result;
  140. }
  141. result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mday);
  142. if(date.tm_hour == 0 && date.tm_min == 0 && date.tm_sec == 0)
  143. {
  144. return result;
  145. }
  146. if(date.tm_hour < 0 || date.tm_hour > 23)
  147. {
  148. return result;
  149. }
  150. if(date.tm_min < 0 || date.tm_min > 59)
  151. {
  152. return result;
  153. }
  154. result += U_("T");
  155. if(date.tm_isdst > 0)
  156. {
  157. tz = U_("+01:00");
  158. }
  159. result += mpt::ufmt::dec0<2>(date.tm_hour) + U_(":") + mpt::ufmt::dec0<2>(date.tm_min);
  160. if(date.tm_sec < 0 || date.tm_sec > 61)
  161. {
  162. return result + tz;
  163. }
  164. result += U_(":") + mpt::ufmt::dec0<2>(date.tm_sec);
  165. result += tz;
  166. return result;
  167. }
  168. } // namespace Date
  169. } // namespace mpt
  170. #ifdef MODPLUG_TRACKER
  171. namespace Util
  172. {
  173. #if MPT_OS_WINDOWS
  174. void MultimediaClock::Init()
  175. {
  176. m_CurrentPeriod = 0;
  177. }
  178. void MultimediaClock::SetPeriod(uint32 ms)
  179. {
  180. TIMECAPS caps = {};
  181. if(timeGetDevCaps(&caps, sizeof(caps)) != MMSYSERR_NOERROR)
  182. {
  183. return;
  184. }
  185. if((caps.wPeriodMax == 0) || (caps.wPeriodMin > caps.wPeriodMax))
  186. {
  187. return;
  188. }
  189. ms = std::clamp(mpt::saturate_cast<UINT>(ms), caps.wPeriodMin, caps.wPeriodMax);
  190. if(timeBeginPeriod(ms) != MMSYSERR_NOERROR)
  191. {
  192. return;
  193. }
  194. m_CurrentPeriod = ms;
  195. }
  196. void MultimediaClock::Cleanup()
  197. {
  198. if(m_CurrentPeriod > 0)
  199. {
  200. if(timeEndPeriod(m_CurrentPeriod) != MMSYSERR_NOERROR)
  201. {
  202. // should not happen
  203. MPT_ASSERT_NOTREACHED();
  204. }
  205. m_CurrentPeriod = 0;
  206. }
  207. }
  208. MultimediaClock::MultimediaClock()
  209. {
  210. Init();
  211. }
  212. MultimediaClock::MultimediaClock(uint32 ms)
  213. {
  214. Init();
  215. SetResolution(ms);
  216. }
  217. MultimediaClock::~MultimediaClock()
  218. {
  219. Cleanup();
  220. }
  221. uint32 MultimediaClock::SetResolution(uint32 ms)
  222. {
  223. if(m_CurrentPeriod == ms)
  224. {
  225. return m_CurrentPeriod;
  226. }
  227. Cleanup();
  228. if(ms != 0)
  229. {
  230. SetPeriod(ms);
  231. }
  232. return GetResolution();
  233. }
  234. uint32 MultimediaClock::GetResolution() const
  235. {
  236. return m_CurrentPeriod;
  237. }
  238. uint32 MultimediaClock::Now() const
  239. {
  240. return timeGetTime();
  241. }
  242. uint64 MultimediaClock::NowNanoseconds() const
  243. {
  244. return (uint64)timeGetTime() * (uint64)1000000;
  245. }
  246. #endif // MPT_OS_WINDOWS
  247. } // namespace Util
  248. #endif // MODPLUG_TRACKER
  249. OPENMPT_NAMESPACE_END