TestDateTime.cpp 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EAStdC/EADateTime.h>
  5. #include <EAStdC/EAStopwatch.h>
  6. #include <EAStdC/EASprintf.h>
  7. #include <EAStdC/EAString.h>
  8. #include <EAStdC/EAMemory.h>
  9. #include <EAStdCTest/EAStdCTest.h>
  10. #include <eathread/eathread.h>
  11. #include <EATest/EATest.h>
  12. #include <string.h>
  13. #include <EAAssert/eaassert.h>
  14. #if defined(EA_PLATFORM_MICROSOFT)
  15. EA_DISABLE_ALL_VC_WARNINGS()
  16. #if defined(EA_PLATFORM_XBOXONE) || defined(CS_UNDEFINED_STRING)
  17. #include <winsock2.h> // for timeval
  18. #else
  19. #include <winsock.h> // for timeval
  20. #endif
  21. #include <Windows.h>
  22. EA_RESTORE_ALL_VC_WARNINGS()
  23. bool GetLocaleInfoHelper(LCTYPE lcType, char* lcData, int cchData)
  24. {
  25. #if EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
  26. return (GetLocaleInfoA(LOCALE_USER_DEFAULT, lcType, lcData, cchData) != 0);
  27. #else
  28. wchar_t* temp = static_cast<wchar_t*>(EAAlloca(cchData * sizeof(wchar_t)));
  29. const bool res = GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, lcType, temp, cchData) != 0;
  30. EA::StdC::Strlcpy(lcData, temp, static_cast<size_t>(cchData));
  31. return res;
  32. #endif
  33. }
  34. #endif
  35. #if defined(_MSC_VER)
  36. #pragma warning(push)
  37. #pragma warning(disable: 6011) // Dereferencing NULL pointer.
  38. #endif
  39. #if defined(EA_HAVE_localtime_DECL)
  40. static int VerifyTmMatch(const tm& tmTest, const EA::StdC::DateTime& dtTest)
  41. {
  42. using namespace EA::StdC;
  43. int nErrorCount = 0;
  44. tm temp;
  45. // What we do here is the same as DateTimeToTm(), but also serves to test it:
  46. temp.tm_year = dtTest.GetParameter(kParameterYear) - 1900; // tm_year: years since 1900
  47. temp.tm_mon = dtTest.GetParameter(kParameterMonth) - 1; // tm_mon: months since January - [0,11]
  48. temp.tm_mday = dtTest.GetParameter(kParameterDayOfMonth); // tm_mday: day of the month - [1,31]
  49. temp.tm_wday = dtTest.GetParameter(kParameterDayOfWeek) - 1; // tm_wday: days since Sunday - [0,6]
  50. temp.tm_yday = dtTest.GetParameter(kParameterDayOfYear) - 1; // tm_yday: days since January 1 - [0,365]
  51. temp.tm_hour = dtTest.GetParameter(kParameterHour); // tm_hour: hours since midnight - [0,23]
  52. temp.tm_min = dtTest.GetParameter(kParameterMinute); // tm_min: minutes after the hour - [0,59
  53. temp.tm_sec = dtTest.GetParameter(kParameterSecond); // tm_sec: seconds after the minute - [0,59]
  54. EATEST_VERIFY(temp.tm_year == tmTest.tm_year);
  55. EATEST_VERIFY(temp.tm_mon == tmTest.tm_mon);
  56. EATEST_VERIFY(temp.tm_mday == tmTest.tm_mday);
  57. EATEST_VERIFY(temp.tm_wday == tmTest.tm_wday);
  58. EATEST_VERIFY(temp.tm_yday == tmTest.tm_yday);
  59. EATEST_VERIFY(temp.tm_hour == tmTest.tm_hour);
  60. EATEST_VERIFY(temp.tm_min == tmTest.tm_min);
  61. EATEST_VERIFY(temp.tm_sec == tmTest.tm_sec);
  62. return nErrorCount;
  63. }
  64. static int VerifyTmMatch(const tm& tmA, const tm& tmB)
  65. {
  66. int nErrorCount = 0;
  67. EATEST_VERIFY(tmA.tm_year == tmB.tm_year);
  68. EATEST_VERIFY(tmA.tm_mon == tmB.tm_mon);
  69. EATEST_VERIFY(tmA.tm_mday == tmB.tm_mday);
  70. EATEST_VERIFY(tmA.tm_wday == tmB.tm_wday);
  71. EATEST_VERIFY(tmA.tm_yday == tmB.tm_yday);
  72. EATEST_VERIFY(tmA.tm_hour == tmB.tm_hour);
  73. EATEST_VERIFY(tmA.tm_min == tmB.tm_min);
  74. EATEST_VERIFY(tmA.tm_sec == tmB.tm_sec);
  75. return nErrorCount;
  76. }
  77. #endif
  78. #if defined(EA_HAVE_localtime_DECL)
  79. // TestGMTime
  80. //
  81. // Tests an individual univeral time value by comparing it to what the standard C gmtime and
  82. // localtime functions say on platforms that support these functions. The EAStdC DateTime class
  83. // is somewhat like a C++ version of the tm struct, with member functions and finer precision (nanoseconds).
  84. // The proper calculations for time can be tricky, and we use a conforming Standard C library
  85. // implementation as a benchmark for results.
  86. // We equate GM time with Universal time.
  87. //
  88. static int TestGMTime(time_t timeGM)
  89. {
  90. using namespace EA::StdC;
  91. int nErrorCount = 0;
  92. tm tmLocal = *localtime(&timeGM);
  93. tm tmGM = *gmtime(&timeGM);
  94. tm tmLocalEA;
  95. DateTime dt;
  96. // void TmToDateTime(const tm& time, DateTime& dateTime);
  97. TmToDateTime(tmLocal, dt);
  98. nErrorCount += VerifyTmMatch(tmLocal, dt);
  99. // void DateTimeToTm(const DateTime& dateTime, tm& time);
  100. DateTimeToTm(dt, tmLocalEA);
  101. nErrorCount += VerifyTmMatch(tmLocal, tmLocalEA);
  102. // Set(uint32_t nYear, uint32_t nMonth, uint32_t nDayOfMonth, uint32_t nHour = 0, uint32_t nMinute = 0, uint32_t nSecond = 0, uint32_t nNanosecond = 0);
  103. dt.Set(1900 + tmGM.tm_year, tmGM.tm_mon + 1, tmGM.tm_mday, tmGM.tm_hour, tmGM.tm_min, tmGM.tm_sec, 0);
  104. nErrorCount += VerifyTmMatch(tmGM, dt);
  105. // DateTime(uint32_t nYear, uint32_t nMonth, uint32_t nDayOfMonth, uint32_t nHour = 0, uint32_t nMinute = 0, uint32_t nSecond = 0, uint32_t nNanosecond = 0);
  106. dt = DateTime(1900 + tmGM.tm_year, tmGM.tm_mon + 1, tmGM.tm_mday, tmGM.tm_hour, tmGM.tm_min, tmGM.tm_sec, 0);
  107. nErrorCount += VerifyTmMatch(tmGM, dt);
  108. // int64_t GetTimeZoneBias();
  109. // bool IsDSTDateTime(int64_t dateTimeSeconds);
  110. // int64_t GetDaylightSavingsBias();
  111. const int32_t timeZoneBias = (int32_t)GetTimeZoneBias();
  112. const bool isDaylightSavings = IsDSTDateTime(TimeTSecondsSecondsToDateTime(timeGM));
  113. const int32_t daylightSavingsBias = (int32_t)GetDaylightSavingsBias();
  114. dt.Set(1900 + tmGM.tm_year, tmGM.tm_mon + 1, tmGM.tm_mday, tmGM.tm_hour, tmGM.tm_min, tmGM.tm_sec, 0);
  115. dt.AddTime(kParameterSecond, timeZoneBias); // Offset by the time zone bias.
  116. EATEST_VERIFY(isDaylightSavings == (tmLocal.tm_isdst > 0));
  117. if(isDaylightSavings)
  118. dt.AddTime(kParameterSecond, daylightSavingsBias); // Offset by the daylight savings time bias.
  119. nErrorCount += VerifyTmMatch(tmLocal, dt);
  120. return nErrorCount;
  121. }
  122. #endif
  123. #define LOCAL_MAX(x, y) ((x) > (y) ? (x) : (y))
  124. int TestDateTime()
  125. {
  126. using namespace EA::StdC;
  127. int nErrorCount(0);
  128. DateTime dateTimeTest(1970, 1, 1, 0, 0, 0);
  129. EATEST_VERIFY(DateTimeSecondsToTimeTSeconds(dateTimeTest.GetSeconds()) == 0);
  130. // C tm struct conversion and setting local time.
  131. #if defined(EA_HAVE_localtime_DECL)
  132. // Regression of end-of-month bug, where it is June 1 in Universal time but May 31 in local time (California, -8 hours from Prime Meridian).
  133. // nTime = 1338519441: tm_isdst = 1, tm_yday = 151, tm_wday = 4, tm_year = 112, tm_mon = 4, tm_mday = 31, tm_hour = 19, tm_min = 57, tm_sec = 21.
  134. nErrorCount += TestGMTime(1338519441);
  135. // Test a big range of dates
  136. // http://www.convert-unix-time.com/?t=946080000
  137. time_t timeGMBegin = 946684800; // UTC: Saturday 1st January 2000 12:00:00 AM
  138. time_t timeGMEnd = 1207008000; // UTC: Tuesday 1st April 2008 12:00:00 AM
  139. time_t timeInterval = time_t(2220.0f / LOCAL_MAX(0.1f, EA::UnitTest::GetSystemSpeed(EA::UnitTest::kSpeedTypeCPU))); // 37 minutes divided by the CPU relative speed (making this test run at acceptable speed on slow platforms)
  140. int errorCount = 0;
  141. for(time_t t = timeGMBegin; (t < timeGMEnd) && !errorCount; t += timeInterval)
  142. {
  143. errorCount = TestGMTime(t);
  144. nErrorCount += errorCount;
  145. }
  146. #endif
  147. { // Verify that DateTime matches time()/localtime()
  148. #if defined(EA_HAVE_localtime_DECL)
  149. DateTime dateTime2(EA::StdC::kTimeFrameLocal);
  150. const time_t nTime = time(NULL);
  151. struct tm* pTime = localtime(&nTime);
  152. uint32_t value;
  153. int i;
  154. // We have a small problem: it's possible that the system time turned over to a
  155. // new second right between the two time calls below. If that seems to be the case
  156. // then we do an update of dateTime2 here, which should execute within the same second.
  157. // Only in a pathological case would it not execute within the same second.
  158. for(i = 0; (i < 5) && (dateTime2.GetParameter(kParameterSecond) != (uint32_t)pTime->tm_sec); i++)
  159. {
  160. dateTime2 = DateTime(EA::StdC::kTimeFrameLocal);
  161. pTime = localtime(&nTime);
  162. }
  163. EATEST_VERIFY(i < 5); // Sanity check. i should almost always be 0, and rarely be 1. Just about never anything higher.
  164. value = dateTime2.GetParameter(kParameterYear);
  165. EATEST_VERIFY_F(value == (uint32_t)(1900 + pTime->tm_year), "TestDateTime DateTime year failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  166. value, (uint32_t)(1900 + pTime->tm_year), dateTime2.GetSeconds(), (int64_t)nTime);
  167. value = dateTime2.GetParameter(kParameterMonth);
  168. EATEST_VERIFY_F(value == (uint32_t)(kMonthJanuary + pTime->tm_mon), "TestDateTime DateTime month failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  169. value, (uint32_t)(kMonthJanuary + pTime->tm_mon), dateTime2.GetSeconds(), (int64_t)nTime);
  170. value = dateTime2.GetParameter(kParameterDayOfMonth);
  171. EATEST_VERIFY_F(value == (uint32_t)pTime->tm_mday, "TestDateTime DateTime day of month failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  172. value, (uint32_t)pTime->tm_mday, dateTime2.GetSeconds(), (int64_t)nTime);
  173. value = dateTime2.GetParameter(kParameterHour);
  174. EATEST_VERIFY_F(value == (uint32_t)pTime->tm_hour, "TestDateTime DateTime hour failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  175. value, (uint32_t)pTime->tm_hour, dateTime2.GetSeconds(), (int64_t)nTime);
  176. value = dateTime2.GetParameter(kParameterMinute);
  177. EATEST_VERIFY_F(value == (uint32_t)pTime->tm_min, "TestDateTime DateTime minute failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  178. value, (uint32_t)pTime->tm_min, dateTime2.GetSeconds(), (int64_t)nTime);
  179. value = dateTime2.GetParameter(kParameterSecond);
  180. EATEST_VERIFY_F((value - (uint32_t)pTime->tm_sec < 5), "TestDateTime DateTime second failure: value: %u, expected: %u. DateTime seconds: %I64u, time_t: %I64d",
  181. value, (uint32_t)pTime->tm_sec, dateTime2.GetSeconds(), (int64_t)nTime);
  182. #endif
  183. }
  184. {
  185. // Basic test of setting/getting parameters.
  186. DateTime dateTime(2004, 11, 9, 0, 0, 0);
  187. DateTime dateTime2(EA::StdC::kTimeFrameLocal);
  188. dateTime.SetParameter(kParameterYear, 1888);
  189. dateTime.SetParameter(kParameterMonth, 5);
  190. dateTime.SetParameter(kParameterDayOfMonth, 16);
  191. dateTime.SetParameter(kParameterHour, 16);
  192. dateTime.SetParameter(kParameterMinute, 44);
  193. dateTime.SetParameter(kParameterSecond, 36);
  194. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1888);
  195. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)5);
  196. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)16);
  197. EATEST_VERIFY(dateTime.GetParameter(kParameterHour) == (uint32_t)16);
  198. EATEST_VERIFY(dateTime.GetParameter(kParameterMinute) == (uint32_t)44);
  199. EATEST_VERIFY(dateTime.GetParameter(kParameterSecond) == (uint32_t)36);
  200. dateTime.SetParameter(kParameterDayOfYear, 244);
  201. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)244);
  202. dateTime.SetParameter(kParameterDayOfWeek, kDayOfWeekThursday);
  203. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekThursday);
  204. dateTime.SetParameter(kParameterWeekOfYear, 23);
  205. EATEST_VERIFY(dateTime.GetParameter(kParameterWeekOfYear) == (uint32_t)23);
  206. dateTime.SetParameter(kParameterWeekOfMonth, 2);
  207. EATEST_VERIFY(dateTime.GetParameter(kParameterWeekOfMonth) == (uint32_t)2);
  208. // Basic day of week day determination
  209. dateTime.Set(2004, 9, 25, 0, 0, 0); // 9/25/2004 - Saturday
  210. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSaturday);
  211. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2004);
  212. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)9);
  213. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)25);
  214. // Day of week determination on the very beginning of a year
  215. dateTime.Set(1995, 1, 1, 0, 0, 0); // 1/1/1995 - Sunday
  216. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSunday);
  217. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1995);
  218. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)1);
  219. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)1);
  220. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)1);
  221. // Day of week determination on the very beginning of a leap year
  222. dateTime.Set(1980, 1, 1, 0, 0, 0); // 1/1/1980 - Tuesday
  223. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekTuesday);
  224. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1980);
  225. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)1);
  226. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)1);
  227. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)1);
  228. // Day of week determination on the very end of a year - note: it should be the 365th day of the year
  229. dateTime.Set(2007, 12, 31, 0, 0, 0); // 12/31/2007 - Monday
  230. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekMonday);
  231. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2007);
  232. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)12);
  233. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)31);
  234. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)365);
  235. // Day of week determination on the very end of the leap year - note: it should be the 366th day of the year
  236. dateTime.Set(2004,12,31,0,0,0); // 12/31/2004 - Friday
  237. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekFriday);
  238. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2004);
  239. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)12);
  240. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)31);
  241. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)366);
  242. // Day of week determination on a leap year - note: this day exists only during leap years
  243. dateTime.Set(2004, 2, 29, 0, 0, 0); // 2/29/2004 - Sunday
  244. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSunday);
  245. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2004);
  246. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)2);
  247. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)29);
  248. // Change the year and we no longer have 2/29 - instead we should have 3/1/2005 - Tuesday
  249. dateTime.Set(2005, 0xffffffff, 0xffffffff, 0, 0, 0);
  250. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekTuesday);
  251. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2005);
  252. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)3);
  253. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)1);
  254. // Go back to 1980 and we should have 2/29 back - Friday
  255. dateTime.Set(1980, 2, 29, 0, 0, 0);
  256. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekFriday);
  257. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1980);
  258. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)2);
  259. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)29);
  260. // Wrapping test - handling of values intentionally out of range
  261. dateTime.Set(2004, 14, 32, 25, 66, 126);
  262. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSaturday);
  263. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2005);
  264. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)3);
  265. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)5);
  266. EATEST_VERIFY(dateTime.GetParameter(kParameterHour) == (uint32_t)2);
  267. EATEST_VERIFY(dateTime.GetParameter(kParameterMinute) == (uint32_t)8);
  268. EATEST_VERIFY(dateTime.GetParameter(kParameterSecond) == (uint32_t)6);
  269. // Changing the day of the week so that we go back to a different year
  270. // 01/02/2008 - Wednesday - go back 2 days to Monday and we should have
  271. // 12/31/2007 - Monday
  272. dateTime.Set(2008, 1, 2, 0, 0, 0);
  273. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekWednesday);
  274. dateTime.SetParameter(kParameterDayOfWeek,kDayOfWeekMonday);
  275. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekMonday);
  276. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2007);
  277. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)12);
  278. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)31);
  279. // Set day of year for a non-leap year
  280. dateTime.Set(1983, 1, 1, 0, 0, 0);
  281. dateTime.SetParameter(kParameterDayOfYear, 365);
  282. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSaturday);
  283. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1983);
  284. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)12);
  285. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)31);
  286. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)365);
  287. dateTime.SetParameter(kParameterDayOfYear, 366); // intentional overflow
  288. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekSunday);
  289. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1984);
  290. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)1);
  291. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)1);
  292. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)1);
  293. // Set day of year for a leap year
  294. dateTime.Set(1984, 1, 1, 0, 0, 0);
  295. dateTime.SetParameter(kParameterDayOfYear, 366);
  296. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekMonday);
  297. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)1984);
  298. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)12);
  299. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)31);
  300. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)366);
  301. // Comparisons test
  302. dateTime.Set(1866, 1, 2, 20, 10, 8);
  303. dateTime2.Set(1866, 1, 2, 20, 10, 6);
  304. EATEST_VERIFY(dateTime.Compare(dateTime2,true,true) == 1); // >
  305. EATEST_VERIFY(dateTime.Compare(dateTime2,true,false) == 0); // ==
  306. EATEST_VERIFY(dateTime.Compare(dateTime2,false,true) == 1); // >
  307. dateTime.Set(1866, 1, 1, 20, 10, 8);
  308. EATEST_VERIFY(dateTime.Compare(dateTime2,true,true) == -1); // <
  309. EATEST_VERIFY(dateTime.Compare(dateTime2,true,false) == -1); // <
  310. EATEST_VERIFY(dateTime.Compare(dateTime2,false,true) == 1); // >
  311. // Arithmetic
  312. dateTime.Set(2004, 12, 30, 0, 0, 0);
  313. dateTime.AddTime(kParameterYear, -2);
  314. dateTime.AddTime(kParameterMonth, 1);
  315. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2003);
  316. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)1);
  317. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)30);
  318. dateTime.AddTime(kParameterMonth, -11); // note that we don't have 30 days in Feb hence the date should spill into March
  319. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2002);
  320. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)3);
  321. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)2);
  322. dateTime.AddTime(kParameterMonth, 25); // add more than one year
  323. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2004);
  324. EATEST_VERIFY(dateTime.GetParameter(kParameterMonth) == (uint32_t)4);
  325. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)2);
  326. dateTime.AddTime(kParameterDayOfMonth, 10);
  327. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfMonth) == (uint32_t)12);
  328. dateTime.SetParameter(kParameterDayOfYear, 366);
  329. dateTime.AddTime(kParameterDayOfYear, 40);
  330. EATEST_VERIFY(dateTime.GetParameter(kParameterYear) == (uint32_t)2005);
  331. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)40);
  332. dateTime.SetParameter(kParameterDayOfWeek, kDayOfWeekMonday);
  333. dateTime.AddTime(kParameterDayOfWeek, 3);
  334. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekThursday);
  335. dateTime.SetParameter(kParameterHour, 10);
  336. dateTime.AddTime(kParameterHour, 16);
  337. dateTime.AddTime(kParameterHour, -1);
  338. EATEST_VERIFY(dateTime.GetParameter(kParameterHour) == (uint32_t)1);
  339. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfWeek) == (uint32_t)kDayOfWeekFriday);
  340. dateTime.AddTime(kParameterMinute, 125);
  341. EATEST_VERIFY(dateTime.GetParameter(kParameterHour) == (uint32_t)3);
  342. EATEST_VERIFY(dateTime.GetParameter(kParameterMinute) == (uint32_t)5);
  343. dateTime.AddTime(kParameterSecond, 65);
  344. EATEST_VERIFY(dateTime.GetParameter(kParameterMinute) == (uint32_t)6);
  345. EATEST_VERIFY(dateTime.GetParameter(kParameterSecond) == (uint32_t)5);
  346. dateTime.SetParameter(kParameterDayOfYear, 100);
  347. dateTime.AddTime(kParameterWeekOfYear, 2);
  348. EATEST_VERIFY(dateTime.GetParameter(kParameterDayOfYear) == (uint32_t)114);
  349. }
  350. // Nanosecond precision
  351. {
  352. // DateTime(int64_t nSeconds, uint32_t nNanosecond = 0);
  353. DateTime dtNS1(1000, 2000);
  354. EATEST_VERIFY(dtNS1.GetSeconds() == 1000);
  355. EATEST_VERIFY(dtNS1.GetNanoseconds() == (1000 * EA::StdC::int128_t(1000000000)) + 2000);
  356. dtNS1.SetNanoseconds(3000);
  357. EATEST_VERIFY(dtNS1.GetSeconds() == 0);
  358. EATEST_VERIFY(dtNS1.GetNanoseconds() == 3000);
  359. // DateTime(const int128_t& nanoseconds);
  360. // EA::StdC::int128_t GetNanoseconds() const;
  361. // void SetNanoseconds(const EA::StdC::int128_t& nanoseconds);
  362. DateTime dtNS2;
  363. EA::StdC::int128_t nsNow = dtNS2.GetNanoseconds();
  364. DateTime dtNS3(nsNow);
  365. EATEST_VERIFY(dtNS2 == dtNS3);
  366. nsNow -= (INT64_C(1000000000) * 3600); // Subtrace one hour
  367. dtNS2.SetNanoseconds(nsNow);
  368. EATEST_VERIFY((dtNS2.GetSeconds() + 3600) == dtNS3.GetSeconds());
  369. // void Set(uint32_t nYear, uint32_t nMonth, uint32_t nDay, uint32_t nHour,
  370. // uint32_t nMinute, uint32_t nSecond, uint32_t nNanosecond);
  371. dtNS3.Set(dtNS2.GetParameter(kParameterYear), dtNS2.GetParameter(kParameterMonth),
  372. dtNS2.GetParameter(kParameterDayOfMonth), dtNS2.GetParameter(kParameterHour),
  373. dtNS2.GetParameter(kParameterMinute), dtNS2.GetParameter(kParameterSecond),
  374. dtNS2.GetParameter(kParameterNanosecond));
  375. EATEST_VERIFY(dtNS2 == dtNS3);
  376. }
  377. // Millisecond precision
  378. {
  379. DateTime dtNS1(1); // 1 second
  380. EATEST_VERIFY(dtNS1.GetSeconds() == 1);
  381. EATEST_VERIFY(dtNS1.GetMilliseconds() == 1000);
  382. dtNS1.SetMilliseconds(8);
  383. EATEST_VERIFY(dtNS1.GetNanoseconds() == 8000000);
  384. EATEST_VERIFY(dtNS1.GetMilliseconds() == 8);
  385. EATEST_VERIFY(dtNS1.GetSeconds() == 0);
  386. dtNS1.SetNanoseconds(1);
  387. EATEST_VERIFY(dtNS1.GetSeconds() == 0);
  388. EATEST_VERIFY(dtNS1.GetMilliseconds() == 0);
  389. EATEST_VERIFY(dtNS1.GetNanoseconds() == 1);
  390. dtNS1.SetNanoseconds(8000006);
  391. EATEST_VERIFY(dtNS1.GetSeconds() == 0);
  392. EATEST_VERIFY(dtNS1.GetMilliseconds() == 8);
  393. EATEST_VERIFY(dtNS1.GetNanoseconds() == 8000006);
  394. }
  395. // void DateTimeToFileTime(const DateTime& dateTime, _FILETIME& time);
  396. // void FileTimeToDateTime(const _FILETIME& time, DateTime& dateTime);
  397. // void DateTimeToSystemTime(const DateTime& dateTime, _SYSTEMTIME& time);
  398. // void SystemTimeToDateTime(const _SYSTEMTIME& time, DateTime& dateTime);
  399. #if defined(EA_PLATFORM_MICROSOFT)
  400. {
  401. DateTime dateTime(1234, 5, 6, 7, 8, 9);
  402. DateTime dateTime2(6789, 6, 5, 4, 3, 2);
  403. _FILETIME fileTime;
  404. _SYSTEMTIME systemTime;
  405. // Our current test is feeble: it merely converts to FILETIME and
  406. // then back and verifies that the time is the same.
  407. dateTime.Set();
  408. DateTimeToFileTime(dateTime, fileTime);
  409. FileTimeToDateTime(fileTime, dateTime2);
  410. EATEST_VERIFY(dateTime == dateTime2);
  411. DateTimeToSystemTime(dateTime, systemTime);
  412. SystemTimeToDateTime(systemTime, dateTime2);
  413. EATEST_VERIFY(dateTime == dateTime2);
  414. }
  415. #endif
  416. {
  417. // http://pubs.opengroup.org/onlinepubs/007908799/xsh/strftime.html
  418. // http://msdn.microsoft.com/en-us/library/fe06s4ak%28v=VS.100%29.aspx
  419. // Posix alternative formats:
  420. // "Some conversion specifiers can be modified by the E or O modifier characters
  421. // to indicate that an alternative format or specification should be used rather
  422. // than the one normally used by the unmodified conversion specifier. If the
  423. // alternative format or specification does not exist for the current locale,
  424. // (see ERA in the XBD specification, Section 5.3.5) the behaviour will be as if
  425. // the unmodified conversion specification were used."
  426. //
  427. // Microsoft alternative formats:
  428. // Also, Microsoft (alternatively to Posix E and O) supports using the # char
  429. // after % to indicate alternative behaviour as follows:
  430. // %#a, %#A, %#b, %#B, %#h, %#p, %#X, %#z, %#Z, %#% # flag is ignored.
  431. // %#c Long date and time representation, appropriate for current locale. For example: "Tuesday, March 14, 1995, 12:41:29".
  432. // %#x Long date representation, appropriate to current locale. For example: "Tuesday, March 14, 1995".
  433. // %#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y Remove leading zeros (if any).
  434. // %a Replaced by the locale's abbreviated weekday name. [ tm_wday]
  435. // %A Replaced by the locale's full weekday name. [ tm_wday]
  436. // %b Replaced by the locale's abbreviated month name. [ tm_mon]
  437. // %B Replaced by the locale's full month name. [ tm_mon]
  438. // %c Replaced by the locale's appropriate date and time representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  439. // %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year]
  440. // %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday]
  441. // %D Equivalent to %m / %d / %y. [ tm_mon, tm_mday, tm_year]
  442. // %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [ tm_mday]
  443. // %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday]
  444. // %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year, tm_wday, tm_yday]
  445. // %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday, tm_yday]
  446. // %h Equivalent to %b. [ tm_mon]
  447. // %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour]
  448. // %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour]
  449. // %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday]
  450. // %m Replaced by the month as a decimal number [01,12]. [ tm_mon]
  451. // %M Replaced by the minute as a decimal number [00,59]. [ tm_min]
  452. // %n Replaced by a <newline>.
  453. // %p Replaced by the locale's equivalent of either a.m. or p.m. [ tm_hour]
  454. // %r Replaced by the time in a.m. and p.m. notation; [CX] [Option Start] in the POSIX locale this shall be equivalent to %I : %M : %S %p. [Option End] [ tm_hour, tm_min, tm_sec]
  455. // %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min]
  456. // %S Replaced by the second as a decimal number [00,60]. [ tm_sec]
  457. // %t Replaced by a <tab>.
  458. // %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec]
  459. // %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday]
  460. // %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
  461. // %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing 1 January has four or more days in the new year, then it is considered week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
  462. // %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday]
  463. // %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
  464. // %x Replaced by the locale's appropriate date representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  465. // %X Replaced by the locale's appropriate time representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  466. // %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
  467. // %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year]
  468. // %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no characters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich). [CX] [Option Start] If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [Option End] [ tm_isdst]
  469. // %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
  470. // %% Replaced by %.
  471. const size_t kBufferSize = 2048;
  472. char* pBuffer = new char[kBufferSize];
  473. tm tmValue1, tmValue2;
  474. size_t n;
  475. char* p;
  476. {
  477. DateTime dt(1999, 12, 31, 23, 59, 58);
  478. memset(&tmValue1, 0, sizeof(tmValue1));
  479. memset(&tmValue2, 0, sizeof(tmValue2));
  480. DateTimeToTm(dt, tmValue1);
  481. // In our simplest test, we simply make a string with all formats and make sure it doesn't crash or hang.
  482. Strftime(pBuffer, kBufferSize, "%a | %#a | %A | %#A | %b | %#b | %B | %#B | %c | %#c | %C | %d | %#d | %D | %e | %h | %H | %#H | %I | %#I | %j | %#j | %m | %#m | %M | %#M | %n | %p | %#p | %r | %R | %S | %#S | %t | %T | %u | %U | %#U | %V | %w | %#w | %W | %#W | %x | %#x | %X | %#X | %y | %#y | %Y | %#Y | %Z | %#Z | %% | %#%", &tmValue1, NULL);
  483. // Generate a string buffer and parse it. The format string differs from the above as some specifiers
  484. // like %u and %W aren't supported by Strptime.
  485. Strftime(pBuffer, kBufferSize, "%a | %#a | %A | %#A | %b | %#b | %B | %#B | %c | %#c | %C | %d | %#d | %D | %e | %h | %H | %#H | %I | %#I | %j | %#j | %m | %#m | %M | %#M | %n | %p | %#p | %r | %R | %S | %#S | %t | %T | %w | %#w | %x | %#x | %X | %#X | %y | %#y | %Y | %#Y | %% | %#%", &tmValue1, NULL);
  486. char *ptr = Strptime(pBuffer, "%a | %#a | %A | %#A | %b | %#b | %B | %#B | %c | %#c | %C | %d | %#d | %D | %e | %h | %H | %#H | %I | %#I | %j | %#j | %m | %#m | %M | %#M | %n | %p | %#p | %r | %R | %S | %#S | %t | %T | %w | %#w | %x | %#x | %X | %#X | %y | %#y | %Y | %#Y | %% | %#%", &tmValue2, NULL);
  487. EATEST_VERIFY(ptr != NULL);
  488. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  489. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  490. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  491. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  492. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  493. EATEST_VERIFY(tmValue1.tm_wday == tmValue2.tm_wday);
  494. EATEST_VERIFY(tmValue1.tm_yday == tmValue2.tm_yday);
  495. EATEST_VERIFY(tmValue1.tm_isdst == tmValue2.tm_isdst);
  496. }
  497. {
  498. DateTime dt(2000, 1, 1, 0, 0, 0);
  499. {
  500. // %t Replaced by a <tab>.
  501. // %% Replaced by %.
  502. // %n Replaced by a <newline>.
  503. memcpy(&tmValue2, &tmValue1, sizeof(tmValue2));
  504. const char* kFormat = "%t %t%%%n%n%%";
  505. const char* kResult = "\t \t%\n\n%";
  506. n = Strftime(pBuffer, kBufferSize, kFormat, &tmValue1, NULL);
  507. EATEST_VERIFY((n == Strlen(kResult)) && (Strcmp(pBuffer, kResult) == 0));
  508. EATEST_VERIFY(memcmp(&tmValue1, &tmValue2, sizeof(tmValue2)) == 0); // Verify that tmValue1 was not written to.
  509. p = Strptime(pBuffer, kFormat, &tmValue2, NULL);
  510. EATEST_VERIFY(p == (pBuffer + n));
  511. EATEST_VERIFY(memcmp(&tmValue1, &tmValue2, sizeof(tmValue2)) == 0); // Verify that tmValue2 was not written to.
  512. }
  513. {
  514. // %a Replaced by the locale's abbreviated weekday name. [ tm_wday]
  515. // %A Replaced by the locale's full weekday name. [ tm_wday]
  516. const char* kExpectedResults[7] =
  517. {
  518. "Sun | Sun | Sunday | Sunday",
  519. "Mon | Mon | Monday | Monday",
  520. "Tue | Tue | Tuesday | Tuesday",
  521. "Wed | Wed | Wednesday | Wednesday",
  522. "Thu | Thu | Thursday | Thursday",
  523. "Fri | Fri | Friday | Friday",
  524. "Sat | Sat | Saturday | Saturday",
  525. };
  526. for(uint32_t d = kDayOfWeekSunday; d <= kDayOfWeekSaturday; d++)
  527. {
  528. dt.SetParameter(kParameterDayOfWeek, d);
  529. DateTimeToTm(dt, tmValue1);
  530. n = Strftime(pBuffer, kBufferSize, "%a | %#a | %A | %#A", &tmValue1, NULL);
  531. EA_COMPILETIME_ASSERT(kDayOfWeekSunday == 1);
  532. EATEST_VERIFY(n == Strlen(kExpectedResults[d - 1]));
  533. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[d - 1]) == 0); // d-1 because kDayOfWeekSunday is 1 and not 0.
  534. // This isn't the right way to test this; we need to test each format in turn and not all of them at once.
  535. p = Strptime(pBuffer, "%a | %#a | %A | %#A", &tmValue2, NULL);
  536. EATEST_VERIFY(p == (pBuffer + n));
  537. EATEST_VERIFY(tmValue1.tm_wday == tmValue2.tm_wday);
  538. }
  539. }
  540. {
  541. // %b Replaced by the locale's abbreviated month name. [ tm_mon]
  542. // %B Replaced by the locale's full month name. [ tm_mon]
  543. // %h Equivalent to %b. [ tm_mon]
  544. // %m Replaced by the month as a decimal number [01,12]. [ tm_mon]
  545. const char* kExpectedResults[12] =
  546. {
  547. "Jan | Jan | January | January | Jan | Jan | 01 | 1",
  548. "Feb | Feb | February | February | Feb | Feb | 02 | 2",
  549. "Mar | Mar | March | March | Mar | Mar | 03 | 3",
  550. "Apr | Apr | April | April | Apr | Apr | 04 | 4",
  551. "May | May | May | May | May | May | 05 | 5",
  552. "Jun | Jun | June | June | Jun | Jun | 06 | 6",
  553. "Jul | Jul | July | July | Jul | Jul | 07 | 7",
  554. "Aug | Aug | August | August | Aug | Aug | 08 | 8",
  555. "Sep | Sep | September | September | Sep | Sep | 09 | 9",
  556. "Oct | Oct | October | October | Oct | Oct | 10 | 10",
  557. "Nov | Nov | November | November | Nov | Nov | 11 | 11",
  558. "Dec | Dec | December | December | Dec | Dec | 12 | 12",
  559. };
  560. for(uint32_t m = kMonthJanuary; m <= kMonthDecember; m++)
  561. {
  562. dt.SetParameter(kParameterMonth, m);
  563. DateTimeToTm(dt, tmValue1);
  564. n = Strftime(pBuffer, kBufferSize, "%b | %#b | %B | %#B | %h | %#h | %m | %#m", &tmValue1, NULL);
  565. EA_COMPILETIME_ASSERT(kMonthJanuary == 1);
  566. EATEST_VERIFY(n == Strlen(kExpectedResults[m - 1]));
  567. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[m - 1]) == 0); // m-1 because kMonthJanuary is 1 and not 0.
  568. // This isn't the right way to test this; we need to test each format in turn and not all of them at once.
  569. p = Strptime(pBuffer, "%b | %#b | %B | %#B | %h | %#h | %m | %#m", &tmValue2, NULL);
  570. EATEST_VERIFY(p == (pBuffer + n));
  571. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  572. }
  573. }
  574. {
  575. // %c Replaced by the locale's appropriate date and time representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  576. dt.SetParameter(kParameterYear, 2012);
  577. dt.SetParameter(kParameterMonth, 1);
  578. dt.SetParameter(kParameterDayOfMonth, 9);
  579. dt.SetParameter(kParameterHour, 13);
  580. dt.SetParameter(kParameterMinute, 24);
  581. dt.SetParameter(kParameterSecond, 5);
  582. DateTimeToTm(dt, tmValue1);
  583. const int kResultSize = 512;
  584. char kExpectedResult[kResultSize] = { '\0' };
  585. #if defined (EA_PLATFORM_WINDOWS)
  586. char kLongMonth[32];
  587. char kLongDayOfWeek[32];
  588. char kShortMonth[32];
  589. char kShortDayOfWeek[32];
  590. char shortDateFormat[80];
  591. char longDateFormat[80];
  592. char timeFormat[80];
  593. char* dateFormat[2] =
  594. {
  595. &shortDateFormat[0],
  596. &longDateFormat[0],
  597. };
  598. char* ptr;
  599. size_t i = 0;
  600. kExpectedResult[0] = '\0';
  601. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SSHORTDATE, shortDateFormat, sizeof(shortDateFormat)/sizeof(shortDateFormat[0])) != 0);
  602. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SLONGDATE, longDateFormat, sizeof(longDateFormat)/sizeof(longDateFormat[0])) != 0);
  603. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_STIMEFORMAT, timeFormat, sizeof(timeFormat)/sizeof(timeFormat[0])) != 0);
  604. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SABBREVDAYNAME1, kShortDayOfWeek, sizeof(kShortDayOfWeek)/sizeof(kShortDayOfWeek[0])) != 0);
  605. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SABBREVMONTHNAME1, kShortMonth, sizeof(kShortMonth)/sizeof(kShortMonth[0])) != 0);
  606. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SDAYNAME1, kLongDayOfWeek, sizeof(kLongDayOfWeek)/sizeof(kLongDayOfWeek[0])) != 0);
  607. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SMONTHNAME1, kLongMonth, sizeof(kLongMonth)/sizeof(kLongMonth[0])) != 0);
  608. char tmp[kResultSize];
  609. for(int j = 0; j < 2; j++)
  610. {
  611. i = 0;
  612. pBuffer[0] = '\0';
  613. strncpy(tmp, dateFormat[j], kResultSize);
  614. ptr = strtok(tmp, "/, -");
  615. while(ptr != 0)
  616. {
  617. if(strncmp(ptr, "d", strlen(ptr)) == 0)
  618. strncat(pBuffer, "9", kBufferSize);
  619. else if(strncmp(ptr, "dd", strlen(ptr)) == 0)
  620. strncat(pBuffer, "09", kBufferSize);
  621. else if(strncmp(ptr, "ddd", strlen(ptr)) == 0)
  622. strncat(pBuffer, kShortDayOfWeek, kBufferSize);
  623. else if(strncmp(ptr, "dddd", strlen(ptr)) == 0)
  624. strncat(pBuffer, kLongDayOfWeek, kBufferSize);
  625. else if(strncmp(ptr, "M", strlen(ptr)) == 0)
  626. strncat(pBuffer, "1", kBufferSize);
  627. else if(strncmp(ptr, "MM", strlen(ptr)) == 0)
  628. strncat(pBuffer, "01", kBufferSize);
  629. else if(strncmp(ptr, "MMM", strlen(ptr)) == 0)
  630. strncat(pBuffer, kShortMonth, kBufferSize);
  631. else if(strncmp(ptr, "MMMM", strlen(ptr)) == 0)
  632. strncat(pBuffer, kLongMonth, kBufferSize);
  633. else if(strncmp(ptr, "y", strlen(ptr)) == 0)
  634. strncat(pBuffer, "2", kBufferSize);
  635. else if(strncmp(ptr, "yy", strlen(ptr)) == 0)
  636. strncat(pBuffer, "12", kBufferSize);
  637. else if(strncmp(ptr, "yyyy", strlen(ptr)) == 0)
  638. strncat(pBuffer, "2012", kBufferSize);
  639. else if(strncmp(ptr, "yyyyy", strlen(ptr)) == 0)
  640. strncat(pBuffer, "2012", kBufferSize);
  641. else
  642. EA_FAIL_M("Unsupported date format");
  643. i += strlen(ptr);
  644. size_t separators = strcspn(&dateFormat[j][i], "dmyM");
  645. strncat(pBuffer, &dateFormat[j][i], separators);
  646. i += separators;
  647. ptr = strtok(NULL, "/, -");
  648. }
  649. strncpy(kExpectedResult, pBuffer, kResultSize);
  650. pBuffer[0] = '\0';
  651. strncpy(tmp, timeFormat, kResultSize);
  652. ptr = strtok(tmp, ": ");
  653. i = 0;
  654. while(ptr != 0)
  655. {
  656. if(strncmp(ptr, "h", strlen(ptr)) == 0)
  657. strncat(pBuffer, "1", kBufferSize);
  658. else if(strncmp(ptr, "hh", strlen(ptr)) == 0)
  659. strncat(pBuffer, "01", kBufferSize);
  660. else if(strncmp(ptr, "H", strlen(ptr)) == 0)
  661. strncat(pBuffer, "13", kBufferSize);
  662. else if(strncmp(ptr, "HH", strlen(ptr)) == 0)
  663. strncat(pBuffer, "13", kBufferSize);
  664. else if(strncmp(ptr, "m", strlen(ptr)) == 0)
  665. strncat(pBuffer, "24", kBufferSize);
  666. else if(strncmp(ptr, "mm", strlen(ptr)) == 0)
  667. strncat(pBuffer, "24", kBufferSize);
  668. else if(strncmp(ptr, "s", strlen(ptr)) == 0)
  669. strncat(pBuffer, "5", kBufferSize);
  670. else if(strncmp(ptr, "ss", strlen(ptr)) == 0)
  671. strncat(pBuffer, "05", kBufferSize);
  672. else if(strncmp(ptr, "t", strlen(ptr)) == 0)
  673. strncat(pBuffer, "P", kBufferSize);
  674. else if(strncmp(ptr, "tt", strlen(ptr)) == 0)
  675. strncat(pBuffer, "PM", kBufferSize);
  676. else
  677. EA_FAIL_M("Unsupported date format");
  678. i+=strlen(ptr);
  679. size_t separators = strcspn(&timeFormat[i], "hHmst");
  680. strncat(pBuffer, &timeFormat[i], separators);
  681. i += separators;
  682. ptr = strtok(NULL, ": ");
  683. }
  684. strncat(kExpectedResult, " ", kResultSize);
  685. strncat(kExpectedResult, pBuffer, kResultSize);
  686. if(j == 0)
  687. {
  688. n = Strftime(pBuffer, kBufferSize, "%#c", &tmValue1, NULL);
  689. EATEST_VERIFY(n == Strlen(kExpectedResult));
  690. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  691. ptr = Strptime(pBuffer, "%#c", &tmValue2, NULL);
  692. EATEST_VERIFY(ptr == (pBuffer + n));
  693. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  694. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  695. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  696. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  697. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  698. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  699. }
  700. else
  701. {
  702. n = Strftime(pBuffer, kBufferSize, "%c", &tmValue1, NULL);
  703. EATEST_VERIFY(n == Strlen(kExpectedResult));
  704. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  705. ptr = Strptime(pBuffer, "%c", &tmValue2, NULL);
  706. EATEST_VERIFY(ptr == (pBuffer + n));
  707. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  708. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  709. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  710. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  711. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  712. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  713. }
  714. }
  715. #else
  716. char* ptr;
  717. //Takes on the form of %a %b %d %H:%M:%S %Y
  718. strncpy(kExpectedResult, "Mon Jan 09 13:24:05 2012", kResultSize);
  719. n = Strftime(pBuffer, kBufferSize, "%c", &tmValue1, NULL);
  720. EATEST_VERIFY(n == Strlen(kExpectedResult));
  721. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  722. ptr = Strptime(pBuffer, "%c", &tmValue2, NULL);
  723. EATEST_VERIFY(ptr == (pBuffer + n));
  724. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  725. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  726. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  727. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  728. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  729. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  730. strncpy(kExpectedResult, "Mon Jan 9 13:24:5 2012", kResultSize);
  731. n = Strftime(pBuffer, kBufferSize, "%#c", &tmValue1, NULL);
  732. EATEST_VERIFY(n == Strlen(kExpectedResult));
  733. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  734. ptr = Strptime(pBuffer, "%#c", &tmValue2, NULL);
  735. EATEST_VERIFY(ptr == (pBuffer + n));
  736. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  737. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  738. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  739. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  740. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  741. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  742. #endif
  743. }
  744. {
  745. //strftime %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year]
  746. //strptime %C The century number [00,99]; leading zeros are permitted but not required.
  747. const uint32_t years[5] =
  748. {
  749. 1999,
  750. 2000,
  751. 999,
  752. 99,
  753. 2100,
  754. };
  755. const char* kExpectedResults[5] =
  756. {
  757. "19 | 19",
  758. "20 | 20",
  759. "09 | 9",
  760. "00 | 0",
  761. "21 | 21",
  762. };
  763. for(uint32_t y =0; y < sizeof(years)/sizeof(uint32_t); y++)
  764. {
  765. dt.SetParameter(kParameterYear, years[y]);
  766. DateTimeToTm(dt, tmValue1);
  767. n = Strftime(pBuffer, kBufferSize, "%C | %#C", &tmValue1, NULL);
  768. EATEST_VERIFY(n == Strlen(kExpectedResults[y]));
  769. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[y]) == 0);
  770. p = Strptime(pBuffer, "%C | %#C", &tmValue2, NULL);
  771. EATEST_VERIFY(p == (pBuffer + n));
  772. //Divide by 100 to find number of centuries past 1900, add 19 for 1900 itself, then multiply by 100 to give the proper year
  773. EATEST_VERIFY(((tmValue1.tm_year+1900)/100)*100 == tmValue2.tm_year);
  774. }
  775. }
  776. {
  777. // %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday]
  778. // %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [ tm_mday]
  779. char kExpectedResult[32];
  780. for(uint32_t m = kDayOfMonthMin; m <= kDayOfMonthMax; m++)
  781. {
  782. sprintf(kExpectedResult, "%02u | %u | %2u", m, m, m);
  783. dt.SetParameter(kParameterDayOfMonth, m);
  784. DateTimeToTm(dt, tmValue1);
  785. n = Strftime(pBuffer, kBufferSize, "%d | %#d | %e", &tmValue1, NULL);
  786. EATEST_VERIFY(n == Strlen(kExpectedResult));
  787. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  788. p = Strptime(pBuffer, "%d | %#d | %e", &tmValue2, NULL);
  789. EATEST_VERIFY(p == (pBuffer + n));
  790. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  791. }
  792. }
  793. {
  794. // %D Equivalent to %m/%d/%y. [ tm_mon, tm_mday, tm_year]
  795. const char* kExpectedResults[12] =
  796. {
  797. "01/01/66",
  798. "02/02/67",
  799. "03/03/68",
  800. "04/04/69",
  801. "05/05/70",
  802. "06/06/71",
  803. "07/07/72",
  804. "08/08/73",
  805. "09/09/74",
  806. "10/10/75",
  807. "11/11/76",
  808. "12/12/77",
  809. };
  810. const uint32_t yearOffset = 2065;
  811. for(uint32_t m = kMonthJanuary; m <= kMonthDecember; m++)
  812. {
  813. dt.SetParameter(kParameterDayOfMonth, m);
  814. dt.SetParameter(kParameterMonth, m);
  815. //strptime %y - The year within century. When a century is not otherwise specified, values in the range [69,99] shall refer to years 1969 to 1999
  816. //inclusive, and values in the range [00,68] shall refer to years 2000 to 2068 inclusive; leading zeros shall be permitted but shall not be required.
  817. dt.SetParameter(kParameterYear, m + yearOffset); // Add offset ( > 2068 - 12) so the tmValue2.tm_year value changes ranges from [2000, 2068] to [1969, 1999] when using strptime
  818. DateTimeToTm(dt, tmValue1);
  819. n = Strftime(pBuffer, kBufferSize, "%D", &tmValue1, NULL);
  820. EATEST_VERIFY(n == Strlen(kExpectedResults[m - 1]));
  821. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[m - 1]) == 0); // m-1 because kMonthJanuary is 1 and not 0.
  822. p = Strptime(pBuffer, "%D", &tmValue2, NULL);
  823. EATEST_VERIFY(p == (pBuffer + n));
  824. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  825. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  826. //Check which range the year will be in
  827. if(m + yearOffset <= 2068)
  828. {
  829. //tm-year range from [2000, 2068], inclusively
  830. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  831. }
  832. else
  833. {
  834. //tm-year range from [1969, 1999], inclusively
  835. EATEST_VERIFY((tmValue1.tm_year - 100) == tmValue2.tm_year); // We subtract the offset -> (2000-1900)
  836. }
  837. }
  838. }
  839. {
  840. // %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday]
  841. const char* kExpectedResults[12] =
  842. {
  843. "2001-01-01",
  844. "2002-02-02",
  845. "2003-03-03",
  846. "2004-04-04",
  847. "2005-05-05",
  848. "2006-06-06",
  849. "2007-07-07",
  850. "2008-08-08",
  851. "2009-09-09",
  852. "2010-10-10",
  853. "2011-11-11",
  854. "2012-12-12",
  855. };
  856. const uint32_t yearOffset = 2000;
  857. for(uint32_t m = kMonthJanuary; m <= kMonthDecember; m++)
  858. {
  859. dt.SetParameter(kParameterDayOfMonth, m);
  860. dt.SetParameter(kParameterMonth, m);
  861. dt.SetParameter(kParameterYear, m + yearOffset); //Add offset to make the years more legible/realistic
  862. DateTimeToTm(dt, tmValue1);
  863. n = Strftime(pBuffer, kBufferSize, "%F", &tmValue1, NULL);
  864. EATEST_VERIFY(n == Strlen(kExpectedResults[m - 1]));
  865. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[m - 1]) == 0);
  866. }
  867. }
  868. {
  869. //Unsupported as of yet - we currently maintain no concept of "week number of year"
  870. // %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year, tm_wday, tm_yday]
  871. // %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday, tm_yday]
  872. }
  873. {
  874. // %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour]
  875. // %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour]
  876. // %M Replaced by the minute as a decimal number [00,59]. [ tm_min]
  877. // %S Replaced by the second as a decimal number [00,60]. [ tm_sec]
  878. char kExpectedResult[32];
  879. const int32_t amToPmDifference = 12;
  880. for(int32_t t = 1; t < kHoursPerDay; t++)
  881. {
  882. sprintf(kExpectedResult, "%02d | %d | %02d | %d | %02d | %d", t, t, t, t, t, t);
  883. dt.SetParameter(kParameterHour, (uint32_t)t);
  884. dt.SetParameter(kParameterMinute, (uint32_t)t);
  885. dt.SetParameter(kParameterSecond, (uint32_t)t);
  886. DateTimeToTm(dt, tmValue1);
  887. n = Strftime(pBuffer, kBufferSize, "%H | %#H | %M | %#M | %S | %#S", &tmValue1, NULL);
  888. EATEST_VERIFY(n == Strlen(kExpectedResult));
  889. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  890. p = Strptime(pBuffer, "%H | %#H | %M | %#M | %S | %#S", &tmValue2, NULL);
  891. EATEST_VERIFY(p == (pBuffer + n));
  892. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  893. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  894. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  895. if(t <= amToPmDifference)
  896. {
  897. sprintf(kExpectedResult, "%02d | %d | %02d | %d | %02d | %d", t, t, t, t, t, t);
  898. n = Strftime(pBuffer, kBufferSize, "%I | %#I | %M | %#M | %S | %#S", &tmValue1, NULL);
  899. EATEST_VERIFY(n == Strlen(kExpectedResult));
  900. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  901. p = Strptime(pBuffer, "%I | %#I | %M | %#M | %S | %#S", &tmValue2, NULL);
  902. EATEST_VERIFY(p == (pBuffer + n));
  903. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  904. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  905. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  906. }
  907. else
  908. {
  909. sprintf(kExpectedResult, "%02d | %d | %02d | %d | %02d | %d", t - amToPmDifference, t - amToPmDifference, t, t, t, t);//Adjust for AM to PM rollover
  910. n = Strftime(pBuffer, kBufferSize, "%I | %#I | %M | %#M | %S | %#S", &tmValue1, NULL);
  911. EATEST_VERIFY(n == Strlen(kExpectedResult));
  912. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  913. p = Strptime(pBuffer, "%I | %#I | %M | %#M | %S | %#S", &tmValue2, NULL);
  914. EATEST_VERIFY(p == (pBuffer + n));
  915. EATEST_VERIFY((tmValue1.tm_hour - amToPmDifference) == tmValue2.tm_hour);
  916. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  917. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  918. }
  919. }
  920. }
  921. {
  922. // %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday]
  923. const char* kExpectedResults[4] =
  924. {
  925. "366 | 366",
  926. "365 | 365",
  927. "001 | 1",
  928. "099 | 99",
  929. };
  930. for(uint32_t d = 0; d < 4; d++)
  931. {
  932. switch(d)
  933. {
  934. case 0://Leap Year End
  935. dt.SetParameter(kParameterDayOfMonth, 31);
  936. dt.SetParameter(kParameterMonth, 12);
  937. dt.SetParameter(kParameterYear, 2012);
  938. break;
  939. case 1://Regular Year End
  940. dt.SetParameter(kParameterDayOfMonth, 31);
  941. dt.SetParameter(kParameterMonth, 12);
  942. dt.SetParameter(kParameterYear, 2011);
  943. break;
  944. case 2://Year Beginning
  945. dt.SetParameter(kParameterDayOfMonth, 1);
  946. dt.SetParameter(kParameterMonth, 1);
  947. dt.SetParameter(kParameterYear, 1970);
  948. break;
  949. case 3://Mid-Regular-Year, two significant digits
  950. dt.SetParameter(kParameterDayOfMonth, 9);
  951. dt.SetParameter(kParameterMonth, 4);
  952. dt.SetParameter(kParameterYear, 2011);
  953. break;
  954. }
  955. DateTimeToTm(dt, tmValue1);
  956. n = Strftime(pBuffer, kBufferSize, "%j | %#j", &tmValue1, NULL);
  957. EATEST_VERIFY(n == Strlen(kExpectedResults[d]));
  958. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[d]) == 0);
  959. p = Strptime(pBuffer, "%j | %#j", &tmValue2, NULL);
  960. EATEST_VERIFY(p == (pBuffer + n));
  961. EATEST_VERIFY(tmValue1.tm_yday == tmValue2.tm_yday);
  962. }
  963. }
  964. {
  965. // %p Replaced by the locale's equivalent of either a.m. or p.m. [ tm_hour]
  966. // %r Replaced by the time in a.m. and p.m. notation; [CX] [Option Start] in the POSIX locale this shall be equivalent to %I : %M : %S %p. [Option End] [ tm_hour, tm_min, tm_sec]
  967. // %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min]
  968. // %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec]
  969. const char* kExpectedResults[8] =
  970. {
  971. "AM", "10:11:12 AM", "10:11", "10:11:12",
  972. "PM", "01:02:03 PM", "13:02", "13:02:03",
  973. };
  974. for(int32_t d = 0; d < 2; d++)
  975. {
  976. switch(d)
  977. {
  978. case 0://AM time leading zeroes
  979. dt.SetParameter(kParameterHour, 10);
  980. dt.SetParameter(kParameterMinute, 11);
  981. dt.SetParameter(kParameterSecond, 12);
  982. break;
  983. case 1://PM time
  984. dt.SetParameter(kParameterHour, 13);
  985. dt.SetParameter(kParameterMinute, 2);
  986. dt.SetParameter(kParameterSecond, 3);
  987. break;
  988. }
  989. DateTimeToTm(dt, tmValue1);
  990. n = Strftime(pBuffer, kBufferSize, "%p", &tmValue1, NULL);
  991. EATEST_VERIFY(n == Strlen(kExpectedResults[4*d]));
  992. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[4*d]) == 0);
  993. int32_t oldHour = tmValue2.tm_hour;
  994. p = Strptime(pBuffer, "%p", &tmValue2, NULL);
  995. EATEST_VERIFY(p == (pBuffer + n));
  996. EATEST_VERIFY((oldHour + (12*d)) == tmValue2.tm_hour);
  997. n = Strftime(pBuffer, kBufferSize, "%r", &tmValue1, NULL);
  998. EATEST_VERIFY(n == Strlen(kExpectedResults[4*d+1]));
  999. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[4*d+1]) == 0);
  1000. p = Strptime(pBuffer, "%r", &tmValue2, NULL);
  1001. EATEST_VERIFY(p == (pBuffer + n));
  1002. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1003. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1004. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  1005. n = Strftime(pBuffer, kBufferSize, "%R", &tmValue1, NULL);
  1006. EATEST_VERIFY(n == Strlen(kExpectedResults[4*d+2]));
  1007. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[4*d+2]) == 0);
  1008. p = Strptime(pBuffer, "%R", &tmValue2, NULL);
  1009. EATEST_VERIFY(p == (pBuffer + n));
  1010. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1011. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1012. n = Strftime(pBuffer, kBufferSize, "%T", &tmValue1, NULL);
  1013. EATEST_VERIFY(n == Strlen(kExpectedResults[4*d+3]));
  1014. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[4*d+3]) == 0);
  1015. p = Strptime(pBuffer, "%T", &tmValue2, NULL);
  1016. EATEST_VERIFY(p == (pBuffer + n));
  1017. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1018. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1019. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  1020. }
  1021. }
  1022. {
  1023. // %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday]
  1024. // %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday]
  1025. for(uint32_t d = 1; d <= kDaysPerWeek; d++)
  1026. {
  1027. char kExpectedResult[8];
  1028. Snprintf(kExpectedResult, 8, "%d", d-1);
  1029. dt.SetParameter(kParameterDayOfWeek, d);
  1030. DateTimeToTm(dt, tmValue1);
  1031. n = Strftime(pBuffer, kBufferSize, "%w", &tmValue1, NULL);
  1032. EATEST_VERIFY(kDayOfWeekSunday == 1);
  1033. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1034. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1035. p = Strptime(pBuffer, "%w", &tmValue2, NULL);
  1036. EATEST_VERIFY(p == (pBuffer + n));
  1037. EATEST_VERIFY(tmValue1.tm_wday == tmValue2.tm_wday);
  1038. Snprintf(kExpectedResult, 8, "%d", ((d+5)%7) + 1); //((d+5)%7) + 1) lets wrap around in the range [1,7]
  1039. n = Strftime(pBuffer, kBufferSize, "%u", &tmValue1, NULL);
  1040. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1041. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1042. }
  1043. }
  1044. {
  1045. //Unsupported as of yet - we currently maintain no concept of "week number of year"
  1046. // %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
  1047. // %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing 1 January has four or more days in the new year, then it is considered week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
  1048. // %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
  1049. }
  1050. {
  1051. // %x Replaced by the locale's appropriate date representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  1052. // %X Replaced by the locale's appropriate time representation. (See the Base Definitions volume of IEEE Std 1003.1-2001, <time.h>.)
  1053. dt.SetParameter(kParameterYear, 2012);
  1054. dt.SetParameter(kParameterMonth, 1);
  1055. dt.SetParameter(kParameterDayOfMonth, 9);
  1056. dt.SetParameter(kParameterHour, 13);
  1057. dt.SetParameter(kParameterMinute, 24);
  1058. dt.SetParameter(kParameterSecond, 5);
  1059. DateTimeToTm(dt, tmValue1);
  1060. const int kResultSize = 512;
  1061. char kExpectedResult[kResultSize] = { '\0' };
  1062. #if defined (EA_PLATFORM_WINDOWS)
  1063. char kLongMonth[32];
  1064. char kLongDayOfWeek[32];
  1065. char kShortMonth[32];
  1066. char kShortDayOfWeek[32];
  1067. char shortDateFormat[80];
  1068. char longDateFormat[80];
  1069. char timeFormat[80];
  1070. char* dateFormat[2] =
  1071. {
  1072. &shortDateFormat[0],
  1073. &longDateFormat[0],
  1074. };
  1075. char* ptr;
  1076. size_t i = 0;
  1077. kExpectedResult[0] = '\0';
  1078. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SSHORTDATE, shortDateFormat, sizeof(shortDateFormat)/sizeof(shortDateFormat[0])) != 0);
  1079. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SLONGDATE, longDateFormat, sizeof(longDateFormat)/sizeof(longDateFormat[0])) != 0);
  1080. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_STIMEFORMAT, timeFormat, sizeof(timeFormat)/sizeof(timeFormat[0])) != 0);
  1081. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SABBREVDAYNAME1, kShortDayOfWeek, sizeof(kShortDayOfWeek)/sizeof(kShortDayOfWeek[0])) != 0);
  1082. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SABBREVMONTHNAME1, kShortMonth, sizeof(kShortMonth)/sizeof(kShortMonth[0])) != 0);
  1083. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SDAYNAME1, kLongDayOfWeek, sizeof(kLongDayOfWeek)/sizeof(kLongDayOfWeek[0])) != 0);
  1084. EATEST_VERIFY(GetLocaleInfoHelper(LOCALE_SMONTHNAME1, kLongMonth, sizeof(kLongMonth)/sizeof(kLongMonth[0])) != 0);
  1085. char tmp[kResultSize];
  1086. for(int j = 0; j < 2; j++)
  1087. {
  1088. i = 0;
  1089. pBuffer[0] = '\0';
  1090. strncpy(tmp, dateFormat[j], kResultSize);
  1091. ptr = strtok(tmp, "/, -");
  1092. while(ptr != 0)
  1093. {
  1094. if(strncmp(ptr, "d", strlen(ptr)) == 0)
  1095. strncat(pBuffer, "9", kBufferSize);
  1096. else if(strncmp(ptr, "dd", strlen(ptr)) == 0)
  1097. strncat(pBuffer, "09", kBufferSize);
  1098. else if(strncmp(ptr, "ddd", strlen(ptr)) == 0)
  1099. strncat(pBuffer, kShortDayOfWeek, kBufferSize);
  1100. else if(strncmp(ptr, "dddd", strlen(ptr)) == 0)
  1101. strncat(pBuffer, kLongDayOfWeek, kBufferSize);
  1102. else if(strncmp(ptr, "M", strlen(ptr)) == 0)
  1103. strncat(pBuffer, "1", kBufferSize);
  1104. else if(strncmp(ptr, "MM", strlen(ptr)) == 0)
  1105. strncat(pBuffer, "01", kBufferSize);
  1106. else if(strncmp(ptr, "MMM", strlen(ptr)) == 0)
  1107. strncat(pBuffer, kShortMonth, kBufferSize);
  1108. else if(strncmp(ptr, "MMMM", strlen(ptr)) == 0)
  1109. strncat(pBuffer, kLongMonth, kBufferSize);
  1110. else if(strncmp(ptr, "y", strlen(ptr)) == 0)
  1111. strncat(pBuffer, "2", kBufferSize);
  1112. else if(strncmp(ptr, "yy", strlen(ptr)) == 0)
  1113. strncat(pBuffer, "12", kBufferSize);
  1114. else if(strncmp(ptr, "yyyy", strlen(ptr)) == 0)
  1115. strncat(pBuffer, "2012", kBufferSize);
  1116. else if(strncmp(ptr, "yyyyy", strlen(ptr)) == 0)
  1117. strncat(pBuffer, "2012", kBufferSize);
  1118. else
  1119. EA_FAIL_M("Unsupported date format");
  1120. i += strlen(ptr);
  1121. size_t separators = strcspn(&dateFormat[j][i], "dmyM");
  1122. strncat(pBuffer, &dateFormat[j][i], separators);
  1123. i += separators;
  1124. ptr = strtok(NULL, "/, -");
  1125. }
  1126. strncpy(kExpectedResult, pBuffer, kResultSize);
  1127. if(j == 0)
  1128. {
  1129. n = Strftime(pBuffer, kBufferSize, "%#x", &tmValue1, NULL);
  1130. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1131. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1132. ptr = Strptime(pBuffer, "%#x", &tmValue2, NULL);
  1133. EATEST_VERIFY(ptr == (pBuffer + n));
  1134. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  1135. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  1136. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  1137. }
  1138. else
  1139. {
  1140. n = Strftime(pBuffer, kBufferSize, "%x", &tmValue1, NULL);
  1141. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1142. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1143. }
  1144. }
  1145. pBuffer[0] = '\0';
  1146. strncpy(tmp, timeFormat, kResultSize);
  1147. ptr = strtok(tmp, ": ");
  1148. i = 0;
  1149. while(ptr != 0)
  1150. {
  1151. if(strncmp(ptr, "h", strlen(ptr)) == 0)
  1152. strncat(pBuffer, "1", kBufferSize);
  1153. else if(strncmp(ptr, "hh", strlen(ptr)) == 0)
  1154. strncat(pBuffer, "01", kBufferSize);
  1155. else if(strncmp(ptr, "H", strlen(ptr)) == 0)
  1156. strncat(pBuffer, "13", kBufferSize);
  1157. else if(strncmp(ptr, "HH", strlen(ptr)) == 0)
  1158. strncat(pBuffer, "13", kBufferSize);
  1159. else if(strncmp(ptr, "m", strlen(ptr)) == 0)
  1160. strncat(pBuffer, "24", kBufferSize);
  1161. else if(strncmp(ptr, "mm", strlen(ptr)) == 0)
  1162. strncat(pBuffer, "24", kBufferSize);
  1163. else if(strncmp(ptr, "s", strlen(ptr)) == 0)
  1164. strncat(pBuffer, "5", kBufferSize);
  1165. else if(strncmp(ptr, "ss", strlen(ptr)) == 0)
  1166. strncat(pBuffer, "05", kBufferSize);
  1167. else if(strncmp(ptr, "t", strlen(ptr)) == 0)
  1168. strncat(pBuffer, "P", kBufferSize);
  1169. else if(strncmp(ptr, "tt", strlen(ptr)) == 0)
  1170. strncat(pBuffer, "PM", kBufferSize);
  1171. else
  1172. EA_FAIL_M("Unsupported date format");
  1173. i+=strlen(ptr);
  1174. size_t separators = strcspn(&timeFormat[i], "hHmst");
  1175. strncat(pBuffer, &timeFormat[i], separators);
  1176. i += separators;
  1177. ptr = strtok(NULL, ": ");
  1178. }
  1179. strncpy(kExpectedResult, pBuffer, kResultSize);
  1180. n = Strftime(pBuffer, kBufferSize, "%X", &tmValue1, NULL);
  1181. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1182. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1183. ptr = Strptime(pBuffer, "%X", &tmValue2, NULL);
  1184. EATEST_VERIFY(ptr == (pBuffer + n));
  1185. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1186. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1187. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  1188. #else
  1189. char* ptr;
  1190. strncpy(kExpectedResult, "01/09/12", kResultSize);
  1191. n = Strftime(pBuffer, kBufferSize, "%x", &tmValue1, NULL);
  1192. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1193. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1194. ptr = Strptime(pBuffer, "%x", &tmValue2, NULL);
  1195. EATEST_VERIFY(ptr == (pBuffer + n));
  1196. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  1197. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  1198. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  1199. strncpy(kExpectedResult, "1/9/12", kResultSize);
  1200. n = Strftime(pBuffer, kBufferSize, "%#x", &tmValue1, NULL);
  1201. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1202. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1203. ptr = Strptime(pBuffer, "%#x", &tmValue2, NULL);
  1204. EATEST_VERIFY(ptr == (pBuffer + n));
  1205. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  1206. EATEST_VERIFY(tmValue1.tm_mon == tmValue2.tm_mon);
  1207. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  1208. strncpy(kExpectedResult, "13:24:05", kResultSize);
  1209. n = Strftime(pBuffer, kBufferSize, "%X", &tmValue1, NULL);
  1210. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1211. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResult) == 0);
  1212. ptr = Strptime(pBuffer, "%X", &tmValue2, NULL);
  1213. EATEST_VERIFY(ptr == (pBuffer + n));
  1214. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1215. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1216. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  1217. #endif
  1218. }
  1219. {
  1220. // %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
  1221. // %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year]
  1222. const uint32_t years[5] =
  1223. {
  1224. 2000,
  1225. 2001,
  1226. 1999,
  1227. 2068,
  1228. 1969,
  1229. };
  1230. const char* kExpectedResults[5] =
  1231. {
  1232. "00 | 0 | 2000",
  1233. "01 | 1 | 2001",
  1234. "99 | 99 | 1999",
  1235. "68 | 68 | 2068",
  1236. "69 | 69 | 1969",
  1237. };
  1238. for(uint32_t y = 0; y < 5; y++)
  1239. {
  1240. dt.SetParameter(kParameterYear, years[y]);
  1241. DateTimeToTm(dt, tmValue1);
  1242. n = Strftime(pBuffer, kBufferSize, "%y | %#y | %Y", &tmValue1, NULL);
  1243. EATEST_VERIFY(n == Strlen(kExpectedResults[y]));
  1244. EATEST_VERIFY(Strcmp(pBuffer, kExpectedResults[y]) == 0);
  1245. p = Strptime(pBuffer, "%y | %#y | %Y", &tmValue2, NULL);
  1246. EATEST_VERIFY(p == (pBuffer + n));
  1247. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  1248. }
  1249. }
  1250. {
  1251. // %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no characters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich). [CX] [Option Start] If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [Option End] [ tm_isdst]
  1252. // %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
  1253. int tzBias = (int)GetTimeZoneBias(); // tzBias will be a negative number in the United States.
  1254. int hour = (tzBias / 3600);
  1255. int min = (tzBias - (hour * 3600)) / 60;
  1256. char kExpectedResult[32];
  1257. char timeZoneName[EA::StdC::kTimeZoneNameCapacity];
  1258. EA::StdC::GetTimeZoneName(timeZoneName, tmValue1.tm_isdst != 0);
  1259. Snprintf(kExpectedResult, 32, "%+03d%02d | %s", hour, min, timeZoneName);
  1260. DateTimeToTm(dt, tmValue1);
  1261. n = Strftime(pBuffer, kBufferSize, "%z | %Z", &tmValue1, NULL);
  1262. EATEST_VERIFY(n == Strlen(kExpectedResult));
  1263. EATEST_VERIFY_F(Strcmp(pBuffer, kExpectedResult) == 0, "TestDateTime Strftime(%z %Z) failure: expected: %s, actual: %s", kExpectedResult, pBuffer);
  1264. }
  1265. }
  1266. {
  1267. #if defined(EA_PLATFORM_DESKTOP) // Currently tested only on desktop platforms because not all platforms completely or properly support the time and gmtime functions.
  1268. time_t t = time(NULL);
  1269. tm* pTM = gmtime(&t);
  1270. memcpy(&tmValue1, pTM, sizeof(tm));
  1271. memset(&tmValue2, 0, sizeof(tmValue2));
  1272. // As with the usage of Strftime/Strptime in the first test case above, these do not use all format specifiers
  1273. // as not all (ie: %u, %W) are currently supported by Strptime.
  1274. Strftime(pBuffer, kBufferSize, "%a | %#a | %A | %#A | %b | %#b | %B | %#B | %c | %#c | %C | %d | %#d | %D | %e | %h | %H | %#H | %I | %#I | %j | %#j | %m | %#m | %M | %#M | %n | %p | %#p | %r | %R | %S | %#S | %t | %T | %w | %#w | %x | %#x | %X | %#X | %y | %#y | %Y | %#Y | %% | %#%", &tmValue1, NULL);
  1275. char *ptr = Strptime(pBuffer, "%a | %#a | %A | %#A | %b | %#b | %B | %#B | %c | %#c | %C | %d | %#d | %D | %e | %h | %H | %#H | %I | %#I | %j | %#j | %m | %#m | %M | %#M | %n | %p | %#p | %r | %R | %S | %#S | %t | %T | %w | %#w | %x | %#x | %X | %#X | %y | %#y | %Y | %#Y | %% | %#%", &tmValue2, NULL);
  1276. EATEST_VERIFY(ptr != NULL);
  1277. EATEST_VERIFY(tmValue1.tm_sec == tmValue2.tm_sec);
  1278. EATEST_VERIFY(tmValue1.tm_min == tmValue2.tm_min);
  1279. EATEST_VERIFY(tmValue1.tm_hour == tmValue2.tm_hour);
  1280. EATEST_VERIFY(tmValue1.tm_mday == tmValue2.tm_mday);
  1281. EATEST_VERIFY(tmValue1.tm_year == tmValue2.tm_year);
  1282. EATEST_VERIFY(tmValue1.tm_wday == tmValue2.tm_wday);
  1283. EATEST_VERIFY(tmValue1.tm_yday == tmValue2.tm_yday);
  1284. EATEST_VERIFY(tmValue1.tm_isdst == tmValue2.tm_isdst);
  1285. #endif
  1286. }
  1287. { // Regression
  1288. // Verify basically that %Y supports 4 digit years.
  1289. p = Strptime("1999", "%Y", &tmValue1, NULL);
  1290. //value in tm_year is stored as years past 1900
  1291. EATEST_VERIFY(p && (p[-1] == '9') && (tmValue1.tm_year == (1999 - 1900)));
  1292. n = Strftime(pBuffer, kBufferSize, "%Y", &tmValue1, NULL);
  1293. int32_t nYear = EA::StdC::StrtoI32(pBuffer, NULL, 10);
  1294. EATEST_VERIFY((n == 4) && (nYear == 1999));
  1295. }
  1296. { // Regression
  1297. p = Strptime("969-12-30T12:33:45Z", "%Y-%m-%dT%H:%M:%SZ", &tmValue1, NULL);
  1298. //value in tm_year is stored as years past 1900
  1299. EATEST_VERIFY(p && (p[-1] == 'Z') && (tmValue1.tm_year == (969 - 1900)));
  1300. p = Strptime("1969-12-30T12:33:45Z", "%Y-%m-%dT%H:%M:%SZ", &tmValue1, NULL);
  1301. //value in tm_year is stored as years past 1900
  1302. EATEST_VERIFY(p && (p[-1] == 'Z') && (tmValue1.tm_year == (1969 - 1900)));
  1303. }
  1304. delete[] pBuffer;
  1305. }
  1306. // Misc
  1307. EATEST_VERIFY(IsLeapYear(2004) == true);
  1308. EATEST_VERIFY(IsLeapYear(1800) == false);
  1309. EATEST_VERIFY(GetDaysInYear(2004) == (uint32_t)366);
  1310. EATEST_VERIFY(GetDaysInYear(1800) == (uint32_t)365);
  1311. EATEST_VERIFY(GetDaysInMonth(kMonthFebruary,2004) == (uint32_t)29);
  1312. EATEST_VERIFY(GetDaysInMonth(kMonthFebruary,1800) == (uint32_t)28);
  1313. EATEST_VERIFY(GetDayOfYear(kMonthFebruary,29,2004) == (uint32_t)60);
  1314. EATEST_VERIFY(GetDayOfYear(kMonthMarch,1,1800) == (uint32_t)60);
  1315. { // Regression of user-reported bug
  1316. DateTime date1;
  1317. uint32_t value;
  1318. date1.Set(1, 1, 1, 0, 0, 0);
  1319. value = date1.GetParameter(kParameterYear);
  1320. EATEST_VERIFY(value == 1);
  1321. value = date1.GetParameter(kParameterMonth);
  1322. EATEST_VERIFY(value == 1);
  1323. value = date1.GetParameter(kParameterDayOfYear);
  1324. EATEST_VERIFY(value == 1);
  1325. value = date1.GetParameter(kParameterWeekOfYear);
  1326. EATEST_VERIFY(value == 1);
  1327. value = date1.GetParameter(kParameterDayOfMonth);
  1328. EATEST_VERIFY(value == 1);
  1329. value = date1.GetParameter(kParameterDayOfWeek);
  1330. EATEST_VERIFY(value == kDayOfWeekMonday);
  1331. value = date1.GetParameter(kParameterHour);
  1332. EATEST_VERIFY(value == 0);
  1333. value = date1.GetParameter(kParameterMinute);
  1334. EATEST_VERIFY(value == 0);
  1335. value = date1.GetParameter(kParameterSecond);
  1336. EATEST_VERIFY(value == 0);
  1337. date1.Set(2009, 1, 1, 0, 0, 0);
  1338. value = date1.GetParameter(kParameterYear);
  1339. EATEST_VERIFY(value == 2009);
  1340. value = date1.GetParameter(kParameterMonth);
  1341. EATEST_VERIFY(value == 1);
  1342. value = date1.GetParameter(kParameterDayOfYear);
  1343. EATEST_VERIFY(value == 1);
  1344. value = date1.GetParameter(kParameterWeekOfYear);
  1345. EATEST_VERIFY(value == 1);
  1346. value = date1.GetParameter(kParameterDayOfMonth);
  1347. EATEST_VERIFY(value == 1);
  1348. value = date1.GetParameter(kParameterDayOfWeek);
  1349. EATEST_VERIFY(value == kDayOfWeekThursday);
  1350. value = date1.GetParameter(kParameterHour);
  1351. EATEST_VERIFY(value == 0);
  1352. value = date1.GetParameter(kParameterMinute);
  1353. EATEST_VERIFY(value == 0);
  1354. value = date1.GetParameter(kParameterSecond);
  1355. EATEST_VERIFY(value == 0);
  1356. date1 = 0;
  1357. date1.SetParameter(kParameterYear, 2009);
  1358. date1.SetParameter(kParameterMonth, 1);
  1359. date1.SetParameter(kParameterDayOfMonth, 1);
  1360. value = date1.GetParameter(kParameterYear);
  1361. EATEST_VERIFY(value == 2009);
  1362. value = date1.GetParameter(kParameterMonth);
  1363. EATEST_VERIFY(value == 1);
  1364. value = date1.GetParameter(kParameterDayOfMonth);
  1365. EATEST_VERIFY(value == 1);
  1366. date1 = 0;
  1367. date1.SetParameter(kParameterDayOfMonth, 1);
  1368. date1.SetParameter(kParameterMonth, 1);
  1369. date1.SetParameter(kParameterYear, 2009);
  1370. value = date1.GetParameter(kParameterYear);
  1371. EATEST_VERIFY(value == 2009);
  1372. value = date1.GetParameter(kParameterMonth);
  1373. EATEST_VERIFY(value == 1);
  1374. value = date1.GetParameter(kParameterDayOfMonth);
  1375. EATEST_VERIFY(value == 1);
  1376. //for(int64_t i = 0, secondsPerYear = (kSecondsPerDay * 365), secondsPerFourYears = secondsPerYear * 4; i < secondsPerFourYears; i++)
  1377. //{
  1378. // date1 = i;
  1379. // date1.SetParameter(kParameterYear, 2009);
  1380. // value = date1.GetParameter(kParameterYear);
  1381. // EATEST_VERIFY(value == 2009);
  1382. //}
  1383. }
  1384. { // GetTime
  1385. const int kTestCount = 5;
  1386. const int kFailThreshold = 20;
  1387. // 0.2 seconds and 2.0 seconds. It's this high because many platform
  1388. // implementations of the tv_usec value are grainy and so this is the
  1389. // best we can validate against.
  1390. const uint64_t kMaxErrorNs = (EA::StdC::GetTimePrecision() < UINT64_C(100000000)) ? UINT64_C(200000000) : UINT64_C(2000000000);
  1391. const uint64_t kMaxErrorMs = (EA::StdC::GetTimePrecision() < UINT64_C(100000000)) ? UINT64_C(200) : UINT64_C(2000);
  1392. // Converts GetTimeOfDay output to an uint64_t representation.
  1393. auto GetTimeOfDayAsUInt64 = []
  1394. {
  1395. timeval tv;
  1396. timezone_ tz;
  1397. EA::StdC::GetTimeOfDay(&tv, &tz, true);
  1398. return (uint64_t)((tv.tv_sec * UINT64_C(1000000000)) + (tv.tv_usec * UINT64_C(1000)));
  1399. };
  1400. // We need to capture the initial date which our test started running at
  1401. // so we can try to detect if the system clock has been changed while
  1402. // our tests are running.
  1403. uint64_t testStartTimeNs = GetTimeOfDayAsUInt64();
  1404. uint64_t dateChangedDiffNs = 0;
  1405. uint64_t dateChangedDiffMs = 0;
  1406. int failCount = 0;
  1407. for (int i = 0; i < kTestCount; i++)
  1408. {
  1409. uint64_t t1 = GetTime(); // nanoseconds
  1410. uint64_t t2 = GetTimeOfDayAsUInt64();
  1411. uint64_t t3 = GetTimeMilliseconds(); // milliseconds
  1412. uint64_t t1ms = t1 / 1000000;
  1413. const uint64_t diffNs = (t1 > t2) ? (t1 - t2) : (t2 - t1);
  1414. const uint64_t diffMs = (t1ms > t3) ? (t1ms - t3) : (t3 - t1ms);
  1415. // Adjust the clock if the date has been changed
  1416. t2 += dateChangedDiffNs;
  1417. t3 += dateChangedDiffMs;
  1418. // If a thread context switch happened right between the two calls above, resample t1.
  1419. // We encounter this problem fairly regularly.
  1420. if (diffNs > kMaxErrorNs && failCount < kFailThreshold)
  1421. {
  1422. // If the time discrepancy is greater than a minute the system clock has likely changed so we adjust all
  1423. // future runs of this tests based on the time difference between the old data and the new one
  1424. if (diffNs > kSecondsPerMinute)
  1425. {
  1426. dateChangedDiffNs = t2 > testStartTimeNs ? (~diffNs) + 1 : diffNs; // take diff or two's complement of diff
  1427. dateChangedDiffMs = dateChangedDiffNs / 1000000;
  1428. }
  1429. // It's very unlikely we could get another context switch so soon.
  1430. // Keep trying until we hit the failure limit.
  1431. failCount++;
  1432. continue;
  1433. }
  1434. // For platforms where the main process can be swapped out for extended periods of time,
  1435. // we disable the test on the buildfarm (via the manifest.xml)
  1436. #if !defined(EASTDC_SWAPPABLE_PROCESS_PLATFORM)
  1437. EATEST_VERIFY_F(diffNs <= kMaxErrorNs,
  1438. "GetTimeOfDay failure on run %d of %d: diffNs: %I64u ns, kMaxErrorNs: %I64u ns. GetTime: "
  1439. "%I64u ns (%I64u s)\nGetTimeOfDay: %I64u ns (%I64u s)\n",
  1440. i, kTestCount, diffNs, kMaxErrorNs, t1, t1 / 1000000000, t2,
  1441. t2 / 1000000000); // Verify that the difference is within N nanoseconds.
  1442. EATEST_VERIFY_F(diffMs <= kMaxErrorMs,
  1443. "GetTimeOfDay failure on run %d of %d: diffMs: %I64u ns, kMaxErrorMs: %I64u ms. GetTime: "
  1444. "%I64u ms (%I64u s)\nGetTimeOfDay: %I64u ms (%I64u s)\n",
  1445. i, kTestCount, diffMs, kMaxErrorMs, t1ms, t1ms / 1000, t3,
  1446. t3 / 1000); // Verify that the difference is within N nanoseconds.
  1447. #endif
  1448. EA::Thread::ThreadSleep(EA::Thread::ThreadTime(500)); // Sleep for N milliseconds, and test again.
  1449. }
  1450. }
  1451. { // GetTimeOfDay
  1452. timeval tv;
  1453. timezone_ tz;
  1454. // Test various combinations of arguments.
  1455. int result = EA::StdC::GetTimeOfDay(&tv, &tz, false);
  1456. EATEST_VERIFY(result == 0);
  1457. result = EA::StdC::GetTimeOfDay(&tv, &tz, true);
  1458. EATEST_VERIFY(result == 0);
  1459. result = EA::StdC::GetTimeOfDay(&tv, NULL, true);
  1460. EATEST_VERIFY(result == 0);
  1461. result = EA::StdC::GetTimeOfDay(&tv, NULL, false);
  1462. EATEST_VERIFY(result == 0);
  1463. result = EA::StdC::GetTimeOfDay(NULL, &tz, true);
  1464. EATEST_VERIFY(result == 0);
  1465. result = EA::StdC::GetTimeOfDay(NULL, &tz, false);
  1466. EATEST_VERIFY(result == 0);
  1467. result = EA::StdC::GetTimeOfDay(NULL, NULL, true);
  1468. EATEST_VERIFY(result == 0);
  1469. result = EA::StdC::GetTimeOfDay(NULL, NULL, false);
  1470. EATEST_VERIFY(result == 0);
  1471. }
  1472. {
  1473. // int64_t ConvertEpochSeconds(Epoch src, int64_t srcSeconds, Epoch dest);
  1474. // Do some conversions from kEpochDateTime to other Epochs.
  1475. DateTime dtEpochJulian((uint32_t)-4712, 1, 1, 12, 0, 0);
  1476. int64_t epochJulian = ConvertEpochSeconds(kEpochDateTime, dtEpochJulian.GetSeconds(), kEpochJulian);
  1477. EATEST_VERIFY(epochJulian == 0);
  1478. DateTime dtEpochModifiedJulian(1858, 11, 17, 0, 0, 0);
  1479. int64_t epochModifiedJulian = ConvertEpochSeconds(kEpochDateTime, dtEpochModifiedJulian.GetSeconds(), kEpochModifiedJulian);
  1480. EATEST_VERIFY(epochModifiedJulian == 0);
  1481. DateTime dtEpochGregorian(1752, 9, 14, 0, 0, 0);
  1482. int64_t epochGregorian = ConvertEpochSeconds(kEpochDateTime, dtEpochGregorian.GetSeconds(), kEpochGregorian);
  1483. EATEST_VERIFY(epochGregorian == 0);
  1484. DateTime dtEpoch1900(1900, 1, 1, 0, 0, 0);
  1485. int64_t epoch1900 = ConvertEpochSeconds(kEpochDateTime, dtEpoch1900.GetSeconds(), kEpoch1900);
  1486. EATEST_VERIFY(epoch1900 == 0);
  1487. DateTime dtEpoch1950(1950, 1, 1, 0, 0, 0);
  1488. int64_t epoch1950 = ConvertEpochSeconds(kEpochDateTime, dtEpoch1950.GetSeconds(), kEpoch1950);
  1489. EATEST_VERIFY(epoch1950 == 0);
  1490. DateTime dtEpoch1970(1970, 1, 1, 0, 0, 0);
  1491. int64_t epoch1970 = ConvertEpochSeconds(kEpochDateTime, dtEpoch1970.GetSeconds(), kEpoch1970);
  1492. EATEST_VERIFY(epoch1970 == 0);
  1493. DateTime dtEpoch2000(2000, 1, 1, 0, 0, 0);
  1494. int64_t epoch2000 = ConvertEpochSeconds(kEpochDateTime, dtEpoch2000.GetSeconds(), kEpoch2000);
  1495. EATEST_VERIFY(epoch2000 == 0);
  1496. DateTime dtEpochJ2000(2000, 1, 1, 11, 58, 55);
  1497. int64_t epochJ2000 = ConvertEpochSeconds(kEpochDateTime, dtEpochJ2000.GetSeconds(), kEpochJ2000);
  1498. EATEST_VERIFY(epochJ2000 == 0);
  1499. DateTime dtEpochDateTime(0); // We want to use a full date here instead, but there's a non-trivial issue with the code and documentation currently that prevents this.
  1500. int64_t epochDateTime = ConvertEpochSeconds(kEpochDateTime, dtEpochDateTime.GetSeconds(), kEpochDateTime);
  1501. EATEST_VERIFY(epochDateTime == 0);
  1502. // Do a conversion between Epochs to make sure the math is right.
  1503. int64_t epoch1970RelativeTo1950 = ConvertEpochSeconds(kEpoch1970, epoch1970, kEpoch1950);
  1504. int64_t epoch1970RelativeTo1950Expected = (dtEpoch1970.GetSeconds() - dtEpoch1950.GetSeconds());
  1505. EATEST_VERIFY(epoch1970RelativeTo1950 == epoch1970RelativeTo1950Expected);
  1506. }
  1507. return nErrorCount;
  1508. }
  1509. #undef LOCAL_MAX
  1510. #if defined(_MSC_VER)
  1511. #pragma warning(pop)
  1512. #endif