Source code of Windows XP (NT5)
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.

313 lines
11 KiB

  1. #include "priv.h"
  2. #ifdef _X86_
  3. #include <w95wraps.h>
  4. #endif
  5. #include "ids.h"
  6. #include <mluisupp.h>
  7. #ifndef DATE_LTRREADING
  8. #define DATE_LTRREADING 0x00000010 //FEATURE: figure out why we have to do this, and fix it.
  9. #define DATE_RTLREADING 0x00000020
  10. #endif
  11. /*-------------------------------------------------------------------------
  12. Purpose: Calls GetDateFormat and tries to replace the day with
  13. a relative reference like "Today" or "Yesterday".
  14. Returns the count of characters written to pszBuf.
  15. */
  16. int GetRelativeDateFormat(
  17. DWORD dwDateFlags,
  18. DWORD * pdwFlags,
  19. SYSTEMTIME * pstDate,
  20. LPWSTR pszBuf,
  21. int cchBuf)
  22. {
  23. int cch;
  24. ASSERT(pdwFlags);
  25. ASSERT(pstDate);
  26. ASSERT(pszBuf);
  27. // Assume that no relative date is applied, so clear the bit
  28. // for now.
  29. *pdwFlags &= ~FDTF_RELATIVE;
  30. // Get the Win32 date format. (GetDateFormat's return value includes
  31. // the null terminator.)
  32. cch = GetDateFormat(LOCALE_USER_DEFAULT, dwDateFlags, pstDate, NULL, pszBuf, cchBuf);
  33. if (0 < cch)
  34. {
  35. SYSTEMTIME stCurrentTime;
  36. int iDay = 0; // 1 = today, -1 = yesterday, 0 = neither today nor yesterday.
  37. // Now see if the date merits a replacement to "Yesterday" or "Today".
  38. GetLocalTime(&stCurrentTime); // get the current date
  39. // Does it match the current day?
  40. if (pstDate->wYear == stCurrentTime.wYear &&
  41. pstDate->wMonth == stCurrentTime.wMonth &&
  42. pstDate->wDay == stCurrentTime.wDay)
  43. {
  44. // Yes
  45. iDay = 1;
  46. }
  47. else
  48. {
  49. // No; maybe it matches yesterday
  50. FILETIME ftYesterday;
  51. SYSTEMTIME stYesterday;
  52. // Compute yesterday's date by converting to FILETIME,
  53. // subtracting one day, then converting back.
  54. SystemTimeToFileTime(&stCurrentTime, &ftYesterday);
  55. DecrementFILETIME(&ftYesterday, FT_ONEDAY);
  56. FileTimeToSystemTime(&ftYesterday, &stYesterday);
  57. // Does it match yesterday?
  58. if (pstDate->wYear == stYesterday.wYear &&
  59. pstDate->wMonth == stYesterday.wMonth &&
  60. pstDate->wDay == stYesterday.wDay)
  61. {
  62. // Yes
  63. iDay = -1;
  64. }
  65. }
  66. // Should we try replacing the day?
  67. if (0 != iDay)
  68. {
  69. // Yes
  70. TCHAR szDayOfWeek[32];
  71. LPTSTR pszModifier;
  72. int cchDayOfWeek;
  73. cchDayOfWeek = MLLoadString((IDS_DAYSOFTHEWEEK + pstDate->wDayOfWeek),
  74. szDayOfWeek, SIZECHARS(szDayOfWeek));
  75. // Search for the day of week text in the string we got back.
  76. // Depending on the user's regional settings, there might not
  77. // be a day in the long-date format...
  78. pszModifier = StrStr(pszBuf, szDayOfWeek);
  79. if (pszModifier)
  80. {
  81. // We found the day in the string, so replace it with
  82. // "Today" or "Yesterday"
  83. TCHAR szTemp[64];
  84. TCHAR szRelativeDay[32];
  85. int cchRelativeDay;
  86. // Save the tail end (the part after the "Monday" string)
  87. lstrcpyn(szTemp, &pszModifier[cchDayOfWeek], SIZECHARS(szTemp));
  88. // Load the appropriate string ("Yesterday" or "Today").
  89. // If the string is empty (localizers might need to do this
  90. // if this logic isn't locale-friendly), don't bother doing
  91. // anything.
  92. cchRelativeDay = MLLoadString((1 == iDay) ? IDS_TODAY : IDS_YESTERDAY,
  93. szRelativeDay, SIZECHARS(szRelativeDay));
  94. if (0 < cchRelativeDay)
  95. {
  96. // Make sure that we have enough room for the replacement
  97. // (cch already accounts for the null terminator)
  98. if (cch - cchDayOfWeek + cchRelativeDay <= cchBuf)
  99. {
  100. // copy the friendly name over the day of the week
  101. lstrcpy(pszModifier, szRelativeDay);
  102. // put back the tail end
  103. lstrcat(pszModifier, szTemp);
  104. cch = cch - cchDayOfWeek + cchRelativeDay;
  105. *pdwFlags |= FDTF_RELATIVE;
  106. }
  107. }
  108. }
  109. }
  110. }
  111. return cch;
  112. }
  113. #define LRM 0x200E // UNICODE Left-to-right mark control character
  114. #define RLM 0x200F // UNICODE Left-to-right mark control character
  115. /*-------------------------------------------------------------------------
  116. Purpose: Constructs a displayname form of the file time.
  117. *pdwFlags may be NULL, in which case FDTF_DEFAULT is assumed. Other
  118. valid flags are:
  119. FDTF_DEFAULT "3/29/98 7:48 PM"
  120. FDTF_SHORTTIME "7:48 PM"
  121. FDTF_SHORTDATE "3/29/98"
  122. FDTF_LONGDATE "Monday, March 29, 1998"
  123. FDTF_LONGTIME "7:48:33 PM"
  124. FDTF_RELATIVE only works with FDTF_LONGDATE. If possible,
  125. replace the day with "Yesterday" or "Today":
  126. "Yesterday, March 29, 1998"
  127. This function updates *pdwFlags to indicate which sections of the
  128. string were actually set. For example, if FDTF_RELATIVE is passed
  129. in, but no relative date conversion was performed, then FDTF_RELATIVE
  130. is cleared before returning.
  131. If the date is the magic "Sorry, I don't know what date it is" value
  132. that FAT uses, then we return an empty string.
  133. */
  134. STDAPI_(int) SHFormatDateTimeW(const FILETIME UNALIGNED *puft, DWORD *pdwFlags, LPWSTR pszBuf, UINT ucchBuf)
  135. {
  136. int cchBuf = ucchBuf;
  137. int cchBufSav = cchBuf;
  138. FILETIME ftLocal, ftInput = *puft; // allign the data
  139. ASSERT(IS_VALID_READ_PTR(puft, FILETIME));
  140. ASSERT(IS_VALID_WRITE_BUFFER(pszBuf, WCHAR, cchBuf));
  141. ASSERT(NULL == pdwFlags || IS_VALID_WRITE_PTR(pdwFlags, DWORD));
  142. DWORD dwFlags = 0;
  143. FileTimeToLocalFileTime(&ftInput, &ftLocal);
  144. if (FILETIMEtoInt64(ftInput) == FT_NTFS_UNKNOWNGMT ||
  145. FILETIMEtoInt64(ftLocal) == FT_FAT_UNKNOWNLOCAL)
  146. {
  147. // This date is uninitialized. Don't show a bogus "10/10/72" string.
  148. if (0 < cchBuf)
  149. *pszBuf = 0;
  150. }
  151. else if (0 < cchBuf)
  152. {
  153. int cch;
  154. SYSTEMTIME st;
  155. DWORD dwDateFlags = DATE_SHORTDATE; // default
  156. DWORD dwTimeFlags = TIME_NOSECONDS; // default
  157. dwFlags = pdwFlags ? *pdwFlags : FDTF_DEFAULT;
  158. // Initialize the flags we're going to use
  159. if (dwFlags & FDTF_LONGDATE)
  160. dwDateFlags = DATE_LONGDATE;
  161. else
  162. dwFlags &= ~FDTF_RELATIVE; // can't show relative dates w/o long dates
  163. if (dwFlags & FDTF_LTRDATE)
  164. dwDateFlags |= DATE_LTRREADING;
  165. else if(dwFlags & FDTF_RTLDATE)
  166. dwDateFlags |= DATE_RTLREADING;
  167. if (dwFlags & FDTF_LONGTIME)
  168. dwTimeFlags &= ~TIME_NOSECONDS;
  169. FileTimeToSystemTime(&ftLocal, &st);
  170. cchBuf--; // Account for null terminator first
  171. if (dwFlags & (FDTF_LONGDATE | FDTF_SHORTDATE))
  172. {
  173. // Get the date
  174. if (dwFlags & FDTF_RELATIVE)
  175. cch = GetRelativeDateFormat(dwDateFlags, &dwFlags, &st, pszBuf, cchBuf);
  176. else
  177. cch = GetDateFormat(LOCALE_USER_DEFAULT, dwDateFlags, &st, NULL, pszBuf, cchBuf);
  178. ASSERT(0 <= cch && cch <= cchBuf);
  179. if (0 < cch)
  180. {
  181. cch--; // (null terminator was counted above, so don't count it again)
  182. ASSERT('\0'==pszBuf[cch]);
  183. }
  184. else
  185. dwFlags &= ~(FDTF_LONGDATE | FDTF_SHORTDATE); // no date, so clear these bits
  186. cchBuf -= cch;
  187. pszBuf += cch;
  188. // Are we tacking on the time too?
  189. if (dwFlags & (FDTF_SHORTTIME | FDTF_LONGTIME))
  190. {
  191. // Yes; for long dates, separate with a comma, otherwise
  192. // separate with a space.
  193. if (dwFlags & FDTF_LONGDATE)
  194. {
  195. WCHAR szT[8];
  196. cch = MLLoadString(IDS_LONGDATE_SEP, szT, SIZECHARS(szT));
  197. StrCpyNW(pszBuf, szT, cchBuf);
  198. int cchCopied = min(cchBuf, cch);
  199. cchBuf -= cchCopied;
  200. pszBuf += cchCopied;
  201. }
  202. else
  203. {
  204. if (cchBuf>0)
  205. {
  206. *pszBuf++ = TEXT(' ');
  207. *pszBuf = 0; // (in case GetTimeFormat doesn't add anything)
  208. cchBuf--;
  209. }
  210. }
  211. // [msadek]; need to insert strong a Unicode control character to simulate
  212. // a strong run in the opposite base direction to enforce
  213. // correct display of concatinated string in all cases
  214. if (dwFlags & FDTF_RTLDATE)
  215. {
  216. if (cchBuf>=2)
  217. {
  218. *pszBuf++ = LRM; // simulate an opposite run
  219. *pszBuf++ = RLM; // force RTL display of the time part.
  220. *pszBuf = 0;
  221. cchBuf -= 2;
  222. }
  223. }
  224. else if (dwFlags & FDTF_LTRDATE)
  225. {
  226. if (cchBuf>=2)
  227. {
  228. *pszBuf++ = RLM; // simulate an opposite run
  229. *pszBuf++ = LRM; // force LTR display of the time part.
  230. *pszBuf = 0;
  231. cchBuf -= 2;
  232. }
  233. }
  234. }
  235. }
  236. if (dwFlags & (FDTF_SHORTTIME | FDTF_LONGTIME))
  237. {
  238. // Get the time
  239. cch = GetTimeFormat(LOCALE_USER_DEFAULT, dwTimeFlags, &st, NULL, pszBuf, cchBuf);
  240. if (0 < cch)
  241. cch--; // (null terminator was counted above, so don't count it again)
  242. else
  243. dwFlags &= ~(FDTF_LONGTIME | FDTF_SHORTTIME); // no time, so clear these bits
  244. cchBuf -= cch;
  245. }
  246. }
  247. if (pdwFlags)
  248. *pdwFlags = dwFlags;
  249. return cchBufSav - cchBuf;
  250. }
  251. STDAPI_(int) SHFormatDateTimeA(const FILETIME UNALIGNED *pft, DWORD *pdwFlags, LPSTR pszBuf, UINT cchBuf)
  252. {
  253. WCHAR wsz[256];
  254. int cchRet = SHFormatDateTimeW(pft, pdwFlags, wsz, SIZECHARS(wsz));
  255. if (0 < cchRet)
  256. {
  257. cchRet = SHUnicodeToAnsi(wsz, pszBuf, cchBuf);
  258. }
  259. else if (0 < cchBuf)
  260. {
  261. *pszBuf = 0;
  262. }
  263. return cchRet;
  264. }