timefn.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #include "rar.hpp"
  2. void RarTime::GetLocal(RarLocalTime *lt)
  3. {
  4. #ifdef _WIN_ALL
  5. FILETIME ft;
  6. GetWinFT(&ft);
  7. FILETIME lft;
  8. if (WinNT() < WNT_VISTA)
  9. {
  10. // SystemTimeToTzSpecificLocalTime based code produces 1 hour error on XP.
  11. FileTimeToLocalFileTime(&ft,&lft);
  12. }
  13. else
  14. {
  15. // We use these functions instead of FileTimeToLocalFileTime according to
  16. // MSDN recommendation: "To account for daylight saving time
  17. // when converting a file time to a local time ..."
  18. SYSTEMTIME st1,st2;
  19. FileTimeToSystemTime(&ft,&st1);
  20. SystemTimeToTzSpecificLocalTime(NULL,&st1,&st2);
  21. SystemTimeToFileTime(&st2,&lft);
  22. // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
  23. FILETIME rft;
  24. SystemTimeToFileTime(&st1,&rft);
  25. uint64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)-
  26. INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
  27. INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime);
  28. lft.dwLowDateTime=(DWORD)Corrected;
  29. lft.dwHighDateTime=(DWORD)(Corrected>>32);
  30. }
  31. SYSTEMTIME st;
  32. FileTimeToSystemTime(&lft,&st);
  33. lt->Year=st.wYear;
  34. lt->Month=st.wMonth;
  35. lt->Day=st.wDay;
  36. lt->Hour=st.wHour;
  37. lt->Minute=st.wMinute;
  38. lt->Second=st.wSecond;
  39. lt->wDay=st.wDayOfWeek;
  40. lt->yDay=lt->Day-1;
  41. static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  42. for (uint I=1;I<lt->Month && I<=ASIZE(mdays);I++)
  43. lt->yDay+=mdays[I-1];
  44. if (lt->Month>2 && IsLeapYear(lt->Year))
  45. lt->yDay++;
  46. #else
  47. time_t ut=GetUnix();
  48. struct tm *t;
  49. t=localtime(&ut);
  50. lt->Year=t->tm_year+1900;
  51. lt->Month=t->tm_mon+1;
  52. lt->Day=t->tm_mday;
  53. lt->Hour=t->tm_hour;
  54. lt->Minute=t->tm_min;
  55. lt->Second=t->tm_sec;
  56. lt->wDay=t->tm_wday;
  57. lt->yDay=t->tm_yday;
  58. #endif
  59. lt->Reminder=(itime % TICKS_PER_SECOND);
  60. }
  61. void RarTime::SetLocal(RarLocalTime *lt)
  62. {
  63. #ifdef _WIN_ALL
  64. SYSTEMTIME st;
  65. st.wYear=lt->Year;
  66. st.wMonth=lt->Month;
  67. st.wDay=lt->Day;
  68. st.wHour=lt->Hour;
  69. st.wMinute=lt->Minute;
  70. st.wSecond=lt->Second;
  71. st.wMilliseconds=0;
  72. st.wDayOfWeek=0;
  73. FILETIME lft;
  74. if (SystemTimeToFileTime(&st,&lft))
  75. {
  76. FILETIME ft;
  77. if (WinNT() < WNT_VISTA)
  78. {
  79. // TzSpecificLocalTimeToSystemTime based code produces 1 hour error on XP.
  80. LocalFileTimeToFileTime(&lft,&ft);
  81. }
  82. else
  83. {
  84. // Reverse procedure which we do in GetLocal.
  85. SYSTEMTIME st1,st2;
  86. FileTimeToSystemTime(&lft,&st2); // st2 might be unequal to st, because we added lt->Reminder to lft.
  87. TzSpecificLocalTimeToSystemTime(NULL,&st2,&st1);
  88. SystemTimeToFileTime(&st1,&ft);
  89. // Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
  90. FILETIME rft;
  91. SystemTimeToFileTime(&st2,&rft);
  92. uint64 Corrected=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
  93. INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
  94. INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime);
  95. ft.dwLowDateTime=(DWORD)Corrected;
  96. ft.dwHighDateTime=(DWORD)(Corrected>>32);
  97. }
  98. SetWinFT(&ft);
  99. }
  100. else
  101. Reset();
  102. #else
  103. struct tm t;
  104. t.tm_sec=lt->Second;
  105. t.tm_min=lt->Minute;
  106. t.tm_hour=lt->Hour;
  107. t.tm_mday=lt->Day;
  108. t.tm_mon=lt->Month-1;
  109. t.tm_year=lt->Year-1900;
  110. t.tm_isdst=-1;
  111. SetUnix(mktime(&t));
  112. #endif
  113. itime+=lt->Reminder;
  114. }
  115. #ifdef _WIN_ALL
  116. void RarTime::GetWinFT(FILETIME *ft)
  117. {
  118. _ULARGE_INTEGER ul;
  119. ul.QuadPart=GetWin();
  120. ft->dwLowDateTime=ul.LowPart;
  121. ft->dwHighDateTime=ul.HighPart;
  122. }
  123. void RarTime::SetWinFT(FILETIME *ft)
  124. {
  125. _ULARGE_INTEGER ul = {ft->dwLowDateTime, ft->dwHighDateTime};
  126. SetWin(ul.QuadPart);
  127. }
  128. #endif
  129. // Get 64-bit representation of Windows FILETIME (100ns since 01.01.1601).
  130. uint64 RarTime::GetWin()
  131. {
  132. return itime/(TICKS_PER_SECOND/10000000);
  133. }
  134. // Set 64-bit representation of Windows FILETIME (100ns since 01.01.1601).
  135. void RarTime::SetWin(uint64 WinTime)
  136. {
  137. itime=WinTime*(TICKS_PER_SECOND/10000000);
  138. }
  139. time_t RarTime::GetUnix()
  140. {
  141. return time_t(GetUnixNS()/1000000000);
  142. }
  143. void RarTime::SetUnix(time_t ut)
  144. {
  145. if (sizeof(ut)>4)
  146. SetUnixNS(uint64(ut)*1000000000);
  147. else
  148. {
  149. // Convert 32-bit and possibly signed time_t to uint32 first,
  150. // uint64 cast is not enough. Otherwise sign can expand to 64 bits.
  151. SetUnixNS(uint64(uint32(ut))*1000000000);
  152. }
  153. }
  154. // Get the high precision Unix time in nanoseconds since 01-01-1970.
  155. uint64 RarTime::GetUnixNS()
  156. {
  157. // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
  158. uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
  159. return itime*(1000000000/TICKS_PER_SECOND)-ushift;
  160. }
  161. // Set the high precision Unix time in nanoseconds since 01-01-1970.
  162. void RarTime::SetUnixNS(uint64 ns)
  163. {
  164. // 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970.
  165. uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
  166. itime=(ns+ushift)/(1000000000/TICKS_PER_SECOND);
  167. }
  168. uint RarTime::GetDos()
  169. {
  170. RarLocalTime lt;
  171. GetLocal(&lt);
  172. uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)|
  173. (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25);
  174. return DosTime;
  175. }
  176. void RarTime::SetDos(uint DosTime)
  177. {
  178. RarLocalTime lt;
  179. lt.Second=(DosTime & 0x1f)*2;
  180. lt.Minute=(DosTime>>5) & 0x3f;
  181. lt.Hour=(DosTime>>11) & 0x1f;
  182. lt.Day=(DosTime>>16) & 0x1f;
  183. lt.Month=(DosTime>>21) & 0x0f;
  184. lt.Year=(DosTime>>25)+1980;
  185. lt.Reminder=0;
  186. SetLocal(&lt);
  187. }
  188. void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
  189. {
  190. if (IsSet())
  191. {
  192. RarLocalTime lt;
  193. GetLocal(&lt);
  194. if (FullMS)
  195. swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u:%02u,%09u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,lt.Second,lt.Reminder*(1000000000/TICKS_PER_SECOND));
  196. else
  197. swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute);
  198. }
  199. else
  200. {
  201. // We use escape before '?' to avoid weird C trigraph characters.
  202. wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
  203. }
  204. }
  205. #ifndef SFX_MODULE
  206. void RarTime::SetIsoText(const wchar *TimeText)
  207. {
  208. int Field[6];
  209. memset(Field,0,sizeof(Field));
  210. for (uint DigitCount=0;*TimeText!=0;TimeText++)
  211. if (IsDigit(*TimeText))
  212. {
  213. int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
  214. if (FieldPos<ASIZE(Field))
  215. Field[FieldPos]=Field[FieldPos]*10+*TimeText-'0';
  216. DigitCount++;
  217. }
  218. RarLocalTime lt;
  219. lt.Second=Field[5];
  220. lt.Minute=Field[4];
  221. lt.Hour=Field[3];
  222. lt.Day=Field[2]==0 ? 1:Field[2];
  223. lt.Month=Field[1]==0 ? 1:Field[1];
  224. lt.Year=Field[0];
  225. lt.Reminder=0;
  226. SetLocal(&lt);
  227. }
  228. #endif
  229. #ifndef SFX_MODULE
  230. void RarTime::SetAgeText(const wchar *TimeText)
  231. {
  232. uint Seconds=0,Value=0;
  233. for (uint I=0;TimeText[I]!=0;I++)
  234. {
  235. wchar Ch=TimeText[I];
  236. if (IsDigit(Ch))
  237. Value=Value*10+Ch-'0';
  238. else
  239. {
  240. switch(etoupperw(Ch))
  241. {
  242. case 'D':
  243. Seconds+=Value*24*3600;
  244. break;
  245. case 'H':
  246. Seconds+=Value*3600;
  247. break;
  248. case 'M':
  249. Seconds+=Value*60;
  250. break;
  251. case 'S':
  252. Seconds+=Value;
  253. break;
  254. }
  255. Value=0;
  256. }
  257. }
  258. SetCurrentTime();
  259. itime-=uint64(Seconds)*TICKS_PER_SECOND;
  260. }
  261. #endif
  262. void RarTime::SetCurrentTime()
  263. {
  264. #ifdef _WIN_ALL
  265. FILETIME ft;
  266. SYSTEMTIME st;
  267. GetSystemTime(&st);
  268. SystemTimeToFileTime(&st,&ft);
  269. SetWinFT(&ft);
  270. #else
  271. time_t st;
  272. time(&st);
  273. SetUnix(st);
  274. #endif
  275. }
  276. // Add the specified signed number of nanoseconds.
  277. void RarTime::Adjust(int64 ns)
  278. {
  279. ns/=1000000000/TICKS_PER_SECOND; // Convert ns to internal ticks.
  280. itime+=(uint64)ns;
  281. }
  282. #ifndef SFX_MODULE
  283. const wchar *GetMonthName(int Month)
  284. {
  285. return uiGetMonthName(Month);
  286. }
  287. #endif
  288. bool IsLeapYear(int Year)
  289. {
  290. return (Year&3)==0 && (Year%100!=0 || Year%400==0);
  291. }