Leaked source code of windows server 2003
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.

1043 lines
30 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1995 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. FILE HISTORY:
  7. */
  8. #define OEMRESOURCE
  9. #include "stdafx.h"
  10. #include <stdlib.h>
  11. #include <memory.h>
  12. #include <ctype.h>
  13. #include <string.h>
  14. #include "dbgutil.h"
  15. #include "objplus.h"
  16. #include "intltime.h"
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21. #define new DEBUG_NEW
  22. /////////////////////////////////////////////////////////////////////////////
  23. // FormatDateTime
  24. //
  25. // Generates a current local date/time string
  26. //
  27. //
  28. /////////////////////////////////////////////////////////////////////////////
  29. void
  30. InternalFormatDateTime(CString & strOutput, SYSTEMTIME * psystemtime, BOOL fLongDate)
  31. {
  32. int nLen;
  33. CString strDate, strTime;
  34. DWORD dwFlags = 0;
  35. dwFlags = fLongDate ? DATE_LONGDATE : DATE_SHORTDATE;
  36. // call once to get the length, and again to format the string
  37. nLen = GetDateFormat(GetThreadLocale(), dwFlags, psystemtime, NULL, NULL, 0);
  38. nLen = GetDateFormat(GetThreadLocale(), dwFlags, psystemtime, NULL, strDate.GetBuffer(nLen + 1), nLen + 1);
  39. strDate.ReleaseBuffer();
  40. // now the time
  41. nLen = GetTimeFormat(GetThreadLocale(), 0, psystemtime, NULL, NULL, 0);
  42. nLen = GetTimeFormat(GetThreadLocale(), 0, psystemtime, NULL, strTime.GetBuffer(nLen + 1), nLen + 1);
  43. strTime.ReleaseBuffer();
  44. strOutput = strDate + _T(" ") + strTime;
  45. }
  46. void
  47. FormatDateTime(CString & strOutput, SYSTEMTIME * psystemtime, BOOL fLongDate)
  48. {
  49. InternalFormatDateTime(strOutput, psystemtime, fLongDate);
  50. }
  51. void
  52. FormatDateTime(CString & strOutput, FILETIME * pfiletime, BOOL fLongDate)
  53. {
  54. FILETIME localTime;
  55. SYSTEMTIME systemtime;
  56. if (!FileTimeToLocalFileTime(pfiletime, &localTime))
  57. {
  58. return;
  59. }
  60. if (!FileTimeToSystemTime(&localTime, &systemtime))
  61. {
  62. return;
  63. }
  64. InternalFormatDateTime(strOutput, &systemtime, fLongDate);
  65. }
  66. void
  67. FormatDateTime(CString & strOutput, CTime & time, BOOL fLongDate)
  68. {
  69. SYSTEMTIME systemtime;
  70. struct tm * ptm = time.GetLocalTm(NULL);
  71. if (ptm != NULL)
  72. {
  73. systemtime.wYear = (WORD) (1900 + ptm->tm_year);
  74. systemtime.wMonth = (WORD) (1 + ptm->tm_mon);
  75. systemtime.wDayOfWeek = (WORD) ptm->tm_wday;
  76. systemtime.wDay = (WORD) ptm->tm_mday;
  77. systemtime.wHour = (WORD) ptm->tm_hour;
  78. systemtime.wMinute = (WORD) ptm->tm_min;
  79. systemtime.wSecond = (WORD) ptm->tm_sec;
  80. systemtime.wMilliseconds = 0;
  81. InternalFormatDateTime(strOutput, &systemtime, fLongDate);
  82. }
  83. else
  84. {
  85. strOutput.Empty();
  86. }
  87. }
  88. /////////////////////////////////////////////////////////////////////////////
  89. // CIntlTime
  90. //
  91. // These allocations cause a phoney "memory leak" error, since
  92. // they're not freed until after the audit-check. Anyway
  93. // around this?
  94. //
  95. /////////////////////////////////////////////////////////////////////////////
  96. // Initialise static members
  97. CIntlTime::INTL_TIME_SETTINGS CIntlTime::m_itsInternationalSettings;
  98. BOOL CIntlTime::m_fIntlOk = CIntlTime::SetIntlTimeSettings();
  99. CString CIntlTime::m_strBadDate("--");
  100. CString CIntlTime::m_strBadTime("--");
  101. /***
  102. *
  103. * CIntlTime::SetIntlTimeSettings
  104. *
  105. * Purpose:
  106. *
  107. * This is a static function which initialises the international
  108. * settings (date seperator, etc) of the CIntlTime class.
  109. *
  110. * Returns:
  111. *
  112. * TRUE if the international settings are properly initialised,
  113. * or FALSE if they are not.
  114. *
  115. */
  116. BOOL CIntlTime::SetIntlTimeSettings ()
  117. {
  118. #ifdef _WIN32
  119. #define MAXSTR 128
  120. BOOL fOk;
  121. TCHAR str[MAXSTR];
  122. #define GETCSTRINGFIELD(field,cstring)\
  123. ::GetLocaleInfo(GetUserDefaultLCID(), field, cstring.GetBuffer(MAXSTR), MAXSTR);\
  124. cstring.ReleaseBuffer()
  125. #define GETINTFIELD(field, integer)\
  126. ::GetLocaleInfo(GetUserDefaultLCID(), field, str, MAXSTR);\
  127. integer = _ttol(str)
  128. #define GETBOOLFIELD(field, boolean)\
  129. ::GetLocaleInfo(GetUserDefaultLCID(), field, str, MAXSTR);\
  130. boolean=*str == '1'
  131. fOk = GETCSTRINGFIELD(LOCALE_SDATE, CIntlTime::m_itsInternationalSettings.strDateSeperator);
  132. fOk &= GETCSTRINGFIELD(LOCALE_STIME, CIntlTime::m_itsInternationalSettings.strTimeSeperator);
  133. fOk &= GETINTFIELD(LOCALE_IDATE, CIntlTime::m_itsInternationalSettings.nDateFormat);
  134. ASSERT((CIntlTime::m_itsInternationalSettings.nDateFormat >= 0) && (CIntlTime::m_itsInternationalSettings.nDateFormat <= 2));
  135. fOk &= GETBOOLFIELD(LOCALE_ITIME, CIntlTime::m_itsInternationalSettings.f24HourClock);
  136. fOk &= GETBOOLFIELD(LOCALE_ICENTURY, CIntlTime::m_itsInternationalSettings.fCentury);
  137. fOk &= GETBOOLFIELD(LOCALE_ITLZERO, CIntlTime::m_itsInternationalSettings.fLeadingTimeZero);
  138. fOk &= GETBOOLFIELD(LOCALE_IDAYLZERO, CIntlTime::m_itsInternationalSettings.fLeadingDayZero);
  139. fOk &= GETBOOLFIELD(LOCALE_IMONLZERO, CIntlTime::m_itsInternationalSettings.fLeadingMonthZero);
  140. if (CIntlTime::m_itsInternationalSettings.f24HourClock)
  141. {
  142. CIntlTime::m_itsInternationalSettings.strAM = "";
  143. CIntlTime::m_itsInternationalSettings.strPM = "";
  144. }
  145. else
  146. {
  147. fOk &= GETCSTRINGFIELD(LOCALE_S1159, CIntlTime::m_itsInternationalSettings.strAM);
  148. fOk &= GETCSTRINGFIELD(LOCALE_S2359, CIntlTime::m_itsInternationalSettings.strPM);
  149. }
  150. #ifdef _DEBUG
  151. if (!fOk)
  152. {
  153. Trace0("There was a problem with some of the intl time settings\n");
  154. }
  155. #endif // _DEBUG
  156. return(fOk);
  157. #endif // _WIN32
  158. #ifdef _WIN16
  159. #define MAXSTR 128
  160. CString strMisc;
  161. #define GETCSTRINGFIELD(field,cstring,defstring)\
  162. ::GetProfileString("Intl", field, defstring, cstring.GetBuffer(MAXSTR), MAXSTR);\
  163. cstring.ReleaseBuffer()
  164. #define GETINTFIELD(field, integer, defint)\
  165. integer = ::GetProfileInt("Intl", field, defint)
  166. #define GETBOOLFIELD(field, boolean, defint)\
  167. boolean = ::GetProfileInt("Intl", field, defint)==1
  168. // Get the values. Assume American defaults in case of failure.
  169. GETCSTRINGFIELD("sDate", CIntlTime::m_itsInternationalSettings.strDateSeperator, "/");
  170. GETCSTRINGFIELD("sTime", CIntlTime::m_itsInternationalSettings.strTimeSeperator, ":");
  171. GETINTFIELD("iDate", CIntlTime::m_itsInternationalSettings.nDateFormat, 0);
  172. ASSERT((CIntlTime::m_itsInternationalSettings.nDateFormat >= 0) && (CIntlTime::m_itsInternationalSettings.nDateFormat <= 2));
  173. GETBOOLFIELD("iTime", CIntlTime::m_itsInternationalSettings.f24HourClock, FALSE);
  174. GETBOOLFIELD("iTLZero", CIntlTime::m_itsInternationalSettings.fLeadingTimeZero, FALSE);
  175. if (CIntlTime::m_itsInternationalSettings.f24HourClock)
  176. {
  177. CIntlTime::m_itsInternationalSettings.strAM = "";
  178. CIntlTime::m_itsInternationalSettings.strPM = "";
  179. }
  180. else
  181. {
  182. GETCSTRINGFIELD("s1159", CIntlTime::m_itsInternationalSettings.strAM, "AM");
  183. GETCSTRINGFIELD("s2359", CIntlTime::m_itsInternationalSettings.strPM, "PM");
  184. }
  185. GETCSTRINGFIELD("sShortDate", strMisc, "M/d/yy");
  186. // These settings are determined from the short date sample, as
  187. // there is no direct equivalent in the win.ini
  188. CIntlTime::m_itsInternationalSettings.fCentury = strMisc.Find("yyyy") != -1;
  189. CIntlTime::m_itsInternationalSettings.fLeadingDayZero = strMisc.Find("dd") != -1;
  190. CIntlTime::m_itsInternationalSettings.fLeadingMonthZero = strMisc.Find("MM") != -1;
  191. return(TRUE);
  192. #endif // _WIN16
  193. }
  194. /***
  195. *
  196. * CIntlTime::Reset()
  197. *
  198. * Purpose:
  199. *
  200. * Reset the international settings. Usually in response to
  201. * a change in those international settings by the user.
  202. *
  203. * Notes:
  204. *
  205. * This is a publically available static function.
  206. *
  207. */
  208. void CIntlTime::Reset()
  209. {
  210. CIntlTime::m_fIntlOk = CIntlTime::SetIntlTimeSettings();
  211. }
  212. /***
  213. *
  214. * CIntlTime::IsLeapYear
  215. *
  216. * Purpose:
  217. *
  218. * Determine if the given year is/was a leap year
  219. *
  220. * Arguments:
  221. *
  222. * int nYear The year in question.
  223. *
  224. * Returns:
  225. *
  226. * TRUE if the year is/was a leap year, or FALSE otherwise.
  227. *
  228. * Comments:
  229. *
  230. * A year is a leap year, if is divisible by 4, but not by a 100, unless
  231. * it is divisible by 400. e.g. 1900 was not a leap year, but 2000 will
  232. * be.
  233. *
  234. */
  235. BOOL CIntlTime::IsLeapYear(UINT nYear)
  236. {
  237. return(!(nYear % 4) && ( (nYear % 100) || !(nYear % 400) ));
  238. }
  239. /***
  240. *
  241. * CIntlTime::IsValidDate
  242. *
  243. * Purpose:
  244. *
  245. * Determine if the given month, day year values are
  246. * valid.
  247. *
  248. * Arguments:
  249. *
  250. * int nMonth Month
  251. * int nDay Day
  252. * int nYear Year
  253. *
  254. * Returns:
  255. *
  256. * TRUE for a valid date, FALSE otherwise.
  257. *
  258. */
  259. BOOL CIntlTime::IsValidDate(UINT nMonth, UINT nDay, UINT nYear)
  260. {
  261. // Sanity Check:
  262. BOOL fOk = ((nYear <100) || (nYear >= 1970)) &&
  263. (nYear <= 2037) &&
  264. ((nMonth >= 1) && (nMonth <= 12)) &&
  265. ((nDay >= 1) && (nDay <= 31));
  266. // Detailed check of days per month
  267. if (fOk)
  268. {
  269. switch(nMonth)
  270. {
  271. case 1:
  272. case 3:
  273. case 5:
  274. case 7:
  275. case 8:
  276. case 10:
  277. case 12:
  278. break;
  279. case 4:
  280. case 6:
  281. case 9:
  282. case 11:
  283. fOk = (nDay <= 30);
  284. break;
  285. case 2:
  286. fOk = (nDay <= (UINT)(IsLeapYear(nYear) ? 29 : 28));
  287. break;
  288. }
  289. }
  290. return(fOk);
  291. }
  292. /***
  293. *
  294. * CIntlTime::IsValidTime
  295. *
  296. * Purpose:
  297. *
  298. * Determine if the given hour, minute, second values
  299. * valid.
  300. *
  301. * Arguments:
  302. *
  303. * int nHour Hour
  304. * int nMinute Minute
  305. * int nSecond Second
  306. *
  307. * Returns:
  308. *
  309. * TRUE for a valid time, FALSE otherwise.
  310. *
  311. */
  312. BOOL CIntlTime::IsValidTime(UINT nHour, UINT nMinute, UINT nSecond)
  313. {
  314. return ((nHour < 24) && (nMinute < 60) && (nSecond < 60));
  315. }
  316. // Constructors. m_fInitOk will indicate whether or not the object
  317. // was succesfully constructed. This can be checked at runtime by
  318. // the IsValid() member function
  319. CIntlTime::CIntlTime()
  320. :CTime()
  321. {
  322. // Time set to 0, always bad.
  323. m_fInitOk = FALSE;
  324. }
  325. CIntlTime::CIntlTime(const CTime &timeSrc)
  326. :CTime(timeSrc)
  327. {
  328. m_fInitOk = GetTime() > 0L;
  329. }
  330. CIntlTime::CIntlTime(time_t time)
  331. :CTime(time)
  332. {
  333. m_fInitOk = (time > 0);
  334. }
  335. CIntlTime::CIntlTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
  336. :CTime(nYear, nMonth, nDay, nHour, nMin, nSec)
  337. {
  338. m_fInitOk = IsValidDate(nMonth, nDay, nYear) && IsValidTime(nHour, nMin, nSec);
  339. }
  340. CIntlTime::CIntlTime(WORD wDosDate, WORD wDosTime)
  341. :CTime(wDosDate, wDosTime)
  342. {
  343. m_fInitOk = GetTime() != 0L;
  344. }
  345. // Constructor taking a string as an argument. The string can contain
  346. // either a time, a date or both. If the string is missing the date,
  347. // the current date will be filled in. If the string is missing the time,
  348. // the current time will be filled in. As with all constructors, be
  349. // sure the call IsValid() to determine proper contruction.
  350. CIntlTime::CIntlTime(const CString & strTime, int nFormat, time_t * ptmOldValue)
  351. :CTime(ConvertFromString(strTime, nFormat, ptmOldValue, &m_fInitOk))
  352. {
  353. }
  354. CIntlTime::CIntlTime(const CIntlTime &timeSrc)
  355. {
  356. CTime::operator=(timeSrc.GetTime());
  357. m_fInitOk = timeSrc.IsValid();
  358. }
  359. #ifdef _WIN32
  360. CIntlTime::CIntlTime(const SYSTEMTIME& sysTime)
  361. : CTime(sysTime)
  362. {
  363. m_fInitOk = IsValidDate((UINT)sysTime.wMonth, (UINT)sysTime.wDay, (UINT)sysTime.wYear)
  364. && IsValidTime((UINT)sysTime.wHour, (UINT)sysTime.wMinute, (UINT)sysTime.wSecond);
  365. }
  366. CIntlTime::CIntlTime(const FILETIME& fileTime)
  367. : CTime(fileTime)
  368. {
  369. m_fInitOk = GetTime() != 0L;
  370. }
  371. #endif // _WIN32
  372. // Desctructor
  373. CIntlTime::~CIntlTime()
  374. {
  375. }
  376. // Assignment operators. As with constructors, be sure to check the
  377. // IsValid() member function to determine succesfull assignment, as
  378. // assignment operators do set the m_fInitOk member variable.
  379. const CIntlTime& CIntlTime::operator =(const CString & strValue)
  380. {
  381. time_t tmValue = ConvertFromString (strValue, CIntlTime::TFRQ_TIME_OR_DATE, NULL, &m_fInitOk);
  382. if (m_fInitOk)
  383. {
  384. CTime::operator=(tmValue);
  385. }
  386. return(*this);
  387. }
  388. // Assignment operator taking a time_t argument
  389. const CIntlTime& CIntlTime::operator =(time_t tmValue)
  390. {
  391. CTime::operator=(tmValue);
  392. m_fInitOk = (tmValue > 0);
  393. return(*this);
  394. }
  395. const CIntlTime& CIntlTime::operator =(const CTime & time)
  396. {
  397. CTime::operator=(time.GetTime());
  398. m_fInitOk = (GetTime() > 0);
  399. return(*this);
  400. }
  401. const CIntlTime& CIntlTime::operator =(const CIntlTime & time)
  402. {
  403. CTime::operator=(time.GetTime());
  404. m_fInitOk = (GetTime() > 0);
  405. return(*this);
  406. }
  407. // Conversion operators
  408. CIntlTime::operator const time_t() const
  409. {
  410. return(GetTime());
  411. }
  412. // Conversion operator that returns the date followed by the time
  413. // in international format as a CString.
  414. CIntlTime::operator const CString() const
  415. {
  416. return(ConvertToString(TFRQ_TIME_AND_DATE));
  417. }
  418. CIntlTime::operator CString() const
  419. {
  420. return(ConvertToString(TFRQ_TIME_AND_DATE));
  421. }
  422. /***
  423. *
  424. * CIntlTime::GetDateString()
  425. *
  426. * Purpose:
  427. *
  428. * Represent the current date in a format consistent with the current
  429. * international settings in a CString.
  430. *
  431. * Returns:
  432. *
  433. * A CString containing the date in string format, or "--" if
  434. * the date is invalid.
  435. *
  436. */
  437. const CString CIntlTime::GetDateString() const
  438. {
  439. CString strIntl;
  440. if (!IsValid())
  441. {
  442. return(CIntlTime::m_strBadDate);
  443. }
  444. TCHAR szPct02D[] = _T("%02d");
  445. TCHAR szPctD[] = _T("%d");
  446. TCHAR szDay[3], szMonth[16], szYear[8];
  447. TCHAR *first, *second, *third;
  448. int i;
  449. i = GetYear();
  450. if(!CIntlTime::m_itsInternationalSettings.fCentury)
  451. {
  452. i %= 100;
  453. }
  454. // fix year 2000 problem -- ericdav
  455. //::_itot(i, szYear, 10);
  456. ::wsprintf (szYear, szPct02D, i);
  457. ::wsprintf (szMonth, CIntlTime::m_itsInternationalSettings.fLeadingMonthZero
  458. ? szPct02D : szPctD, GetMonth());
  459. ::wsprintf (szDay, CIntlTime::m_itsInternationalSettings.fLeadingDayZero
  460. ? szPct02D : szPctD, GetDay());
  461. if (CIntlTime::m_itsInternationalSettings.nDateFormat == _DFMT_YMD)
  462. {
  463. first = szYear;
  464. second = szMonth;
  465. third = szDay;
  466. }
  467. else
  468. {
  469. third = szYear;
  470. if (CIntlTime::m_itsInternationalSettings.nDateFormat == _DFMT_DMY)
  471. {
  472. first = szDay;
  473. second = szMonth;
  474. }
  475. else
  476. {
  477. first = szMonth;
  478. second = szDay;
  479. }
  480. }
  481. ::wsprintf (strIntl.GetBuffer(80),
  482. _T("%s%s%s%s%s"),
  483. first,
  484. (LPCTSTR)CIntlTime::m_itsInternationalSettings.strDateSeperator,
  485. second,
  486. (LPCTSTR)CIntlTime::m_itsInternationalSettings.strDateSeperator,
  487. third);
  488. strIntl.ReleaseBuffer();
  489. return(strIntl);
  490. }
  491. /***
  492. *
  493. * CIntlTime::GetTimeString()
  494. *
  495. * Purpose:
  496. *
  497. * Represent the current time in a format consistent with the current
  498. * international settings in a CString.
  499. *
  500. * Returns:
  501. *
  502. * A CString containing the time in string format, or "--" if
  503. * the time is invalid.
  504. *
  505. */
  506. const CString CIntlTime::GetTimeString() const
  507. {
  508. CString strIntl;
  509. if (!IsValid())
  510. {
  511. return(CIntlTime::m_strBadTime);
  512. }
  513. int hour = GetHour();
  514. int minute = GetMinute();
  515. int second = GetSecond();
  516. // Set AM/PM depending on non-24 hour clock, and the time
  517. // of day. Note: a space is prepended for readability.
  518. CString strAMPM(CIntlTime::m_itsInternationalSettings.f24HourClock
  519. ? "" : " " + ((hour < 12)
  520. ? CIntlTime::m_itsInternationalSettings.strAM
  521. : CIntlTime::m_itsInternationalSettings.strPM)
  522. );
  523. if ((!CIntlTime::m_itsInternationalSettings.f24HourClock) && (!(hour %= 12)))
  524. {
  525. hour = 12;
  526. }
  527. ::wsprintf (strIntl.GetBuffer(30), CIntlTime::m_itsInternationalSettings.fLeadingTimeZero
  528. ? _T("%02d%s%02d%s%02d%s") : _T("%d%s%02d%s%02d%s"),
  529. hour,
  530. (LPCTSTR)CIntlTime::m_itsInternationalSettings.strTimeSeperator,
  531. minute,
  532. (LPCTSTR)CIntlTime::m_itsInternationalSettings.strTimeSeperator,
  533. second,
  534. (LPCTSTR)strAMPM);
  535. strIntl.ReleaseBuffer();
  536. return(strIntl);
  537. }
  538. const CString CIntlTime::GetMilitaryTime() const
  539. {
  540. CString strIntl;
  541. if (!IsValid())
  542. {
  543. return(CIntlTime::m_strBadTime);
  544. }
  545. int hour = GetHour();
  546. int minute = GetMinute();
  547. int second = GetSecond();
  548. ::wsprintf (strIntl.GetBuffer(30),
  549. _T("%02d:%02d:%02d"),
  550. hour,
  551. minute,
  552. second);
  553. strIntl.ReleaseBuffer();
  554. return(strIntl);
  555. }
  556. /***
  557. *
  558. * CIntlTime::ConvertToString(int nFormat)
  559. *
  560. * Purpose:
  561. *
  562. * Convert the curent time/date to a string
  563. *
  564. * Arguments:
  565. *
  566. * int nFormat Format request ID, can be one of the following
  567. * values (enumerated in CIntlTime):
  568. *
  569. * TFRQ_TIME_ONLY Only give me the time.
  570. * TFRQ_DATE_ONLY Only give me the date.
  571. * TFRQ_TIME_AND_DATE Give me the time and the date.
  572. *
  573. * Returns:
  574. *
  575. * A CString containing the time and/or date in international format.
  576. *
  577. */
  578. const CString CIntlTime::ConvertToString(int nFormat) const
  579. {
  580. switch(nFormat)
  581. {
  582. case TFRQ_TIME_ONLY:
  583. return(GetTimeString());
  584. case TFRQ_DATE_ONLY:
  585. return(GetDateString());
  586. case TFRQ_TIME_AND_DATE:
  587. return(GetDateString() + CString(" ") + GetTimeString());
  588. case TFRQ_MILITARY_TIME:
  589. return(GetMilitaryTime());
  590. case TFRQ_TIME_OR_DATE:
  591. default:
  592. Trace1("Invalid time/date format code %d requested.\n", nFormat);
  593. return(CIntlTime::m_strBadDate);
  594. }
  595. }
  596. /***
  597. *
  598. * CIntlTime::ConvertFromString
  599. *
  600. * Purpose:
  601. *
  602. * Convert a given CString into a time_t
  603. *
  604. * Arguments:
  605. *
  606. * const CString & str The string to convert
  607. * int nFormat Format request ID, can be one of the following
  608. * values (enumerated in CIntlTime):
  609. *
  610. * TFRQ_TIME_ONLY Only give me the time.
  611. * TFRQ_DATE_ONLY Only give me the date.
  612. * TFRQ_TIME_AND_DATE Give me the time and the date.
  613. * TFRQ_TIME_OR_DATE Give me time or date (or both).
  614. *
  615. * time_t * ptmOldValue This time_t will be used to fill in the fields
  616. * not given in the string. If it is NULL, the current
  617. * time or date will be used.
  618. * BOOL * pfOk Returns TRUE for succesfull conversion, FALSE
  619. * otherwise.
  620. *
  621. * Returns:
  622. *
  623. * A time_t representing the time/date string, or 0 in case of error.
  624. *
  625. * Notes:
  626. *
  627. * Full validation of all paremeters will be done, e.g. No Feb 29 in
  628. * a non-leap year will be accepted.
  629. *
  630. * [CAVEAT] Time, date seperators longer than one character will not
  631. * work.
  632. *
  633. */
  634. time_t CIntlTime::ConvertFromString (
  635. const CString & str,
  636. int nFormat,
  637. time_t * ptmOldValue, // If only getting time or date, count on remaining
  638. // fields to be provided here (optionally);
  639. BOOL * pfOk)
  640. {
  641. #define MAXSTRLEN 40
  642. TCHAR dtseps[10] ; // Date/Time separators passed to _tcstok
  643. TCHAR *pchToken;
  644. TCHAR szDateString[MAXSTRLEN+1];
  645. BOOL fGotDate = FALSE;
  646. BOOL fGotTime = FALSE;
  647. BOOL fPM = FALSE;
  648. BOOL fAM = FALSE;
  649. int i;
  650. UINT anValues[6] = { 0, 0, 0, 0, 0, 0 };
  651. CTime tmTmp;
  652. *pfOk = FALSE; // Assume failure.
  653. if (ptmOldValue != NULL)
  654. {
  655. tmTmp = *ptmOldValue;
  656. }
  657. else
  658. {
  659. tmTmp = CTime::GetCurrentTime();
  660. }
  661. if (str.GetLength() > MAXSTRLEN)
  662. {
  663. // Too long to be a proper time/date string
  664. return(0);
  665. }
  666. ::lstrcpy(szDateString, (LPCTSTR)str);
  667. int nIndex = 0;
  668. // If we're looking for something specific, only
  669. // accept specific seperators (time, date, both, either)
  670. if ((nFormat == TFRQ_DATE_ONLY) || (nFormat == TFRQ_TIME_AND_DATE) || (nFormat == TFRQ_TIME_OR_DATE))
  671. {
  672. dtseps[nIndex++] = '/';
  673. dtseps[nIndex++] = '-';
  674. dtseps[nIndex++] = ',';
  675. dtseps[nIndex++] = CIntlTime::m_itsInternationalSettings.strDateSeperator[0];
  676. }
  677. if ((nFormat == TFRQ_TIME_ONLY) || (nFormat == TFRQ_TIME_AND_DATE) || (nFormat == TFRQ_TIME_OR_DATE))
  678. {
  679. dtseps[nIndex++] = ':';
  680. dtseps[nIndex++] = '.';
  681. dtseps[nIndex++] = ' ';
  682. dtseps[nIndex++] = CIntlTime::m_itsInternationalSettings.strTimeSeperator[0];
  683. }
  684. ASSERT(nIndex != 0); // Make sure we asked for something.
  685. if (nIndex == 0)
  686. {
  687. // Request type is illegal
  688. return(0);
  689. }
  690. dtseps[nIndex++] = '\0';
  691. Trace3("CIntlTime::ConvertFromString. String: %s Format = %d Seps: %s\n", str, nFormat, dtseps);
  692. i = 0;
  693. pchToken = ::_tcstok(szDateString, dtseps);
  694. while (pchToken != NULL)
  695. {
  696. if (i > 6) // 7 fields max (date, time + AM/PM maximum)
  697. {
  698. // Too many values, reject the string.
  699. return(0);
  700. }
  701. // Determine if its a number (can't _ttoi, since it will
  702. // merely return 0 for inappropriate values)
  703. BOOL fProperNumber = TRUE;
  704. int l = ::lstrlen(pchToken);
  705. if ( (l == 0) || (l == 3) || (l > 4) )
  706. {
  707. fProperNumber = FALSE;
  708. }
  709. else
  710. {
  711. int j;
  712. for (j=0; j < l; ++j)
  713. {
  714. if (!isdigit(*(pchToken+j)))
  715. {
  716. fProperNumber = FALSE;
  717. break;
  718. }
  719. }
  720. }
  721. if (!fProperNumber)
  722. {
  723. // Ok, this is not a proper numeric field. Only
  724. // if it's AM or PM at the end of the string can this
  725. // string be saved.
  726. fGotTime = TRUE;
  727. if ((CIntlTime::m_itsInternationalSettings.f24HourClock) ||
  728. (::_tcstok(NULL, dtseps) != NULL))
  729. {
  730. return(0);
  731. }
  732. if (!CIntlTime::m_itsInternationalSettings.strAM.CompareNoCase(pchToken))
  733. {
  734. fAM = TRUE;
  735. }
  736. else if (!CIntlTime::m_itsInternationalSettings.strPM.CompareNoCase(pchToken))
  737. {
  738. fPM = TRUE;
  739. }
  740. else
  741. {
  742. // Neither AM nor PM
  743. return(0);
  744. }
  745. break;
  746. }
  747. else
  748. {
  749. // Value is acceptable
  750. anValues[i++] = (UINT)::_ttoi(pchToken);
  751. }
  752. pchToken = ::_tcstok(NULL, dtseps);
  753. }
  754. // Now what did we get, exactly?
  755. ASSERT(!fAM || !fPM); // Make sure we didn't set both somehow.
  756. if (i == 0)
  757. {
  758. // String without values
  759. return(0);
  760. }
  761. switch(i)
  762. {
  763. case 1: // Hour
  764. case 2: // Hour, minutes
  765. Trace0("We got time\n");
  766. fGotTime = TRUE;
  767. break;
  768. case 3:
  769. // This one might be ambiguous, try to intelligently decide what
  770. // we have. First check if only time or date only was requested,
  771. // then check for out of bounds time values, and lastly check for
  772. // the presence of a time seperator.
  773. if (!fGotTime) // If we didn't already have AM/PM
  774. {
  775. Trace0("Picking between time and date by seperator\n");
  776. if (nFormat == TFRQ_DATE_ONLY)
  777. {
  778. fGotDate = TRUE;
  779. }
  780. else if (nFormat == TFRQ_TIME_ONLY)
  781. {
  782. fGotTime = TRUE;
  783. }
  784. else if ((anValues[0] > 23) || (anValues[1] > 59) || (anValues[2] > 59))
  785. {
  786. fGotDate = TRUE;
  787. }
  788. else if (str.Find(CIntlTime::m_itsInternationalSettings.strTimeSeperator) != -1)
  789. {
  790. fGotTime = TRUE;
  791. }
  792. else
  793. {
  794. fGotDate = TRUE;
  795. }
  796. Trace1("Decided on %s", (fGotDate ? "date\n" : "time\n"));
  797. }
  798. break;
  799. case 4: // Date, hour
  800. case 5: // Date, hours, minutes
  801. case 6: // Date, hours, minutes, seconds
  802. Trace0("We got date and time\n");
  803. fGotDate = TRUE;
  804. fGotTime = TRUE;
  805. break;
  806. default:
  807. ASSERT(0 && "Incorrect number of values!");
  808. return(0);
  809. }
  810. // Was that what we're looking for?
  811. if ( ((nFormat == TFRQ_DATE_ONLY) && fGotTime) ||
  812. ((nFormat == TFRQ_TIME_ONLY) && fGotDate) ||
  813. ((nFormat == TFRQ_TIME_AND_DATE) && (!fGotTime || !fGotDate))
  814. )
  815. {
  816. Trace0("Entry didn't match expectations\n");
  817. return(0);
  818. }
  819. i = 0;
  820. int h, m, s, D, M, Y; // Array indices;
  821. // Now determine where to find what.
  822. if (fGotDate) // Date always goes first
  823. {
  824. switch(CIntlTime::m_itsInternationalSettings.nDateFormat)
  825. {
  826. case _DFMT_MDY:
  827. M = i++;
  828. D = i++;
  829. Y = i++;
  830. break;
  831. case _DFMT_DMY:
  832. D = i++;
  833. M = i++;
  834. Y = i++;
  835. break;
  836. case _DFMT_YMD:
  837. Y = i++;
  838. M = i++;
  839. D = i++;
  840. break;
  841. }
  842. // If only 2 digits are given, determine if we're talking about
  843. // the 21st or 20th century
  844. if (anValues[Y] < 100)
  845. {
  846. anValues[Y] += (anValues[Y] > 37) ? 1900 : 2000;
  847. }
  848. Trace3("Month = %d Day = %d Year = %d\n", anValues[M], anValues[D], anValues[Y]);
  849. // Validation.
  850. if (!IsValidDate(anValues[M], anValues[D], anValues[Y]))
  851. {
  852. return(0);
  853. }
  854. }
  855. if (fGotTime)
  856. {
  857. h = i++;
  858. m = i++;
  859. s = i++;
  860. Trace3("Hours = %d Minutes = %d Seconds = %d\n", anValues[h], anValues[m], anValues[s]);
  861. // Shouldn't specify AM or PM with 24 hour clock value.
  862. if ((anValues[h] > 12) && (fAM || fPM))
  863. {
  864. return(0);
  865. }
  866. // Adjust for AM/PM modifiers
  867. if (fPM)
  868. {
  869. if (anValues[h] != 12)
  870. {
  871. anValues[h] += 12;
  872. }
  873. }
  874. else if (fAM)
  875. {
  876. if ( anValues[h] == 12)
  877. {
  878. anValues[h] -= 12;
  879. }
  880. }
  881. // Sanity Check:
  882. if (!IsValidTime(anValues[h], anValues[m], anValues[s]))
  883. {
  884. return(0);
  885. }
  886. }
  887. // Fill in the missing fields
  888. CIntlTime tm( fGotDate ? anValues[Y] : tmTmp.GetYear(),
  889. fGotDate ? anValues[M] : tmTmp.GetMonth(),
  890. fGotDate ? anValues[D] : tmTmp.GetDay(),
  891. fGotTime ? anValues[h] : tmTmp.GetHour(),
  892. fGotTime ? anValues[m] : tmTmp.GetMinute(),
  893. fGotTime ? anValues[s] : tmTmp.GetSecond()
  894. );
  895. *pfOk = (tm.GetTime() > (time_t)0);
  896. return(tm);
  897. }
  898. #ifdef _DEBUG
  899. // Dump to debug device
  900. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CIntlTime& tim)
  901. {
  902. dc << _T("\nDate Seperator: ") << tim.m_itsInternationalSettings.strDateSeperator;
  903. dc << _T("\nTime Seperator: ") << tim.m_itsInternationalSettings.strTimeSeperator;
  904. dc << _T("\nAM String: ") << tim.m_itsInternationalSettings.strAM;
  905. dc << _T("\nPM String: ") << tim.m_itsInternationalSettings.strPM;
  906. dc << _T("\nDate Format: ") << tim.m_itsInternationalSettings.nDateFormat;
  907. dc << _T("\n24 Hour Clock: ") << (tim.m_itsInternationalSettings.f24HourClock ? "TRUE" : "FALSE");
  908. dc << _T("\n4 Digit Century: ") << (tim.m_itsInternationalSettings.fCentury ? "TRUE" : "FALSE");
  909. dc << _T("\nTime Leading Zero: ") << (tim.m_itsInternationalSettings.fLeadingTimeZero ? "TRUE" : "FALSE");
  910. dc << _T("\nDay Leading Zero ") << (tim.m_itsInternationalSettings.fLeadingDayZero ? "TRUE" : "FALSE");
  911. dc << _T("\nMonth Leading Zero: ") << (tim.m_itsInternationalSettings.fLeadingMonthZero ? "TRUE" : "FALSE");
  912. dc << _T("\n\ntime_t: ") << tim.GetTime();
  913. return(dc);
  914. }
  915. #endif // _DEBUG