ChronoTests.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/std/chrono/chrono.h>
  9. #include <AzCore/std/time.h>
  10. #include <AzCore/std/limits.h>
  11. #include <AzCore/std/typetraits/is_integral.h>
  12. #include <AzCore/std/typetraits/is_signed.h>
  13. #include "UserTypes.h"
  14. namespace UnitTest
  15. {
  16. //////////////////////////////////////////////////////////////////////////
  17. // Fixtures
  18. // Fixture for non-typed tests
  19. class DurationTest
  20. : public LeakDetectionFixture
  21. {
  22. };
  23. /*
  24. * Helper Type Trait structure for adding expected value to typed
  25. */
  26. template<typename TestType, size_t RequiredBits, typename ExpectedPeriodType>
  27. struct DurationExpectation
  28. {
  29. using test_type = TestType;
  30. using rep = typename TestType::rep;
  31. using period = typename TestType::period;
  32. using expected_period = ExpectedPeriodType;
  33. static constexpr bool is_signed = AZStd::is_signed<int64_t>::value;
  34. static constexpr bool is_integral = AZStd::is_integral<int64_t>::value;
  35. static constexpr size_t required_bits = RequiredBits;
  36. };
  37. // Fixture for typed tests
  38. template<typename ExpectedResultTraits>
  39. class DurationTypedTest : public LeakDetectionFixture
  40. {
  41. };
  42. using ChronoTestTypes = ::testing::Types<
  43. DurationExpectation<AZStd::chrono::nanoseconds, 63, AZStd::nano>,
  44. DurationExpectation<AZStd::chrono::microseconds, 54, AZStd::micro>,
  45. DurationExpectation<AZStd::chrono::milliseconds, 44, AZStd::milli>,
  46. DurationExpectation<AZStd::chrono::seconds, 44, AZStd::ratio<1>>,
  47. DurationExpectation<AZStd::chrono::minutes, 28, AZStd::ratio<60>>,
  48. DurationExpectation<AZStd::chrono::hours, 22, AZStd::ratio<3600>>>;
  49. TYPED_TEST_SUITE(DurationTypedTest, ChronoTestTypes);
  50. //////////////////////////////////////////////////////////////////////////
  51. // Tests for std::duration compile time requirements
  52. namespace CompileTimeRequirements
  53. {
  54. TYPED_TEST(DurationTypedTest, TraitRequirementsSuccess)
  55. {
  56. static_assert(
  57. AZStd::is_signed<typename TypeParam::rep>::value,
  58. "built in helper types for AZStd::chrono::duration requires representation type to be signed");
  59. static_assert(
  60. AZStd::is_integral<typename TypeParam::rep>::value,
  61. "built in helper types for AZStd::chrono::duration requires representation type to an integral type");
  62. static_assert(
  63. AZStd::numeric_limits<typename TypeParam::rep>::digits >= TypeParam::required_bits,
  64. "representation type does not have the minimum number of required bits");
  65. static_assert(
  66. AZStd::is_same_v<typename TypeParam::period, typename TypeParam::expected_period>,
  67. "duration period type does not match expected period type");
  68. }
  69. }
  70. namespace Comparisons
  71. {
  72. TEST_F(DurationTest, Comparisons_SameType)
  73. {
  74. constexpr AZStd::chrono::milliseconds threeMillis(3);
  75. constexpr AZStd::chrono::milliseconds oneMillis(1);
  76. constexpr AZStd::chrono::milliseconds oneMillisAgain(1);
  77. static_assert(oneMillis == oneMillisAgain);
  78. static_assert(threeMillis > oneMillis);
  79. static_assert(oneMillis < threeMillis);
  80. static_assert(threeMillis >= oneMillis);
  81. static_assert(oneMillis <= threeMillis);
  82. static_assert(threeMillis >= threeMillis);
  83. static_assert(threeMillis <= threeMillis);
  84. }
  85. TEST_F(DurationTest, Comparisons_DifferentType)
  86. {
  87. constexpr AZStd::chrono::milliseconds threeMillis(3);
  88. constexpr AZStd::chrono::milliseconds oneMillis(1);
  89. // different types:
  90. constexpr AZStd::chrono::microseconds threeMillisButInMicroseconds(3000);
  91. constexpr AZStd::chrono::microseconds oneMilliButInMicroseconds(1000);
  92. static_assert(threeMillisButInMicroseconds > oneMillis);
  93. static_assert(oneMilliButInMicroseconds < threeMillis);
  94. static_assert(threeMillis == threeMillisButInMicroseconds);
  95. static_assert(oneMilliButInMicroseconds == oneMillis);
  96. static_assert(threeMillisButInMicroseconds >= threeMillis);
  97. static_assert(threeMillisButInMicroseconds <= threeMillis);
  98. static_assert(threeMillisButInMicroseconds >= oneMillis);
  99. static_assert(oneMilliButInMicroseconds <= threeMillis);
  100. }
  101. }
  102. // Test for std::duration arithmatic operations
  103. namespace ArithmaticOperators
  104. {
  105. TEST_F(DurationTest, MillisecondsSubtractionResultsNegativeSuccess)
  106. {
  107. constexpr AZStd::chrono::milliseconds milliSeconds(3);
  108. constexpr AZStd::chrono::milliseconds inverseMilliSeconds = -milliSeconds;
  109. static_assert(milliSeconds.count() == -inverseMilliSeconds.count(), "inverseMilliseconds should be inverse of milliseconds");
  110. static_assert(inverseMilliSeconds.count() == -3, "inverseMilliseconds value should be negative");
  111. constexpr auto subtractResultMilliSeconds = inverseMilliSeconds - milliSeconds;
  112. static_assert(subtractResultMilliSeconds.count() == -6, "subtract result is incorrect");
  113. AZStd::chrono::milliseconds compoundSubtractMilliSeconds(5);
  114. compoundSubtractMilliSeconds -= AZStd::chrono::milliseconds(4);
  115. EXPECT_EQ(compoundSubtractMilliSeconds.count(), 1);
  116. }
  117. TEST_F(DurationTest, MillisecondsAdditionWithNegativeSuccess)
  118. {
  119. constexpr AZStd::chrono::milliseconds milliSeconds(3);
  120. constexpr AZStd::chrono::milliseconds negativeMilliSeconds(-4);
  121. constexpr auto addResultMilliSeconds = negativeMilliSeconds + milliSeconds;
  122. static_assert(addResultMilliSeconds.count() == -1, "add result is incorrect");
  123. AZStd::chrono::milliseconds compoundAddMilliSeconds(5);
  124. compoundAddMilliSeconds += AZStd::chrono::milliseconds(2);
  125. EXPECT_EQ(compoundAddMilliSeconds.count(), 7);
  126. }
  127. TEST_F(DurationTest, NanosecondsMultiplicationWithNegativeSuccess)
  128. {
  129. constexpr AZStd::chrono::nanoseconds negativeNanoSeconds(-16);
  130. constexpr AZStd::chrono::nanoseconds multiplyResultSeconds = negativeNanoSeconds * 3;
  131. static_assert(multiplyResultSeconds.count() == -48, "multiply result is incorrect");
  132. AZStd::chrono::nanoseconds compoundMultiplyNanoSeconds(9);
  133. compoundMultiplyNanoSeconds *= -2;
  134. EXPECT_EQ(compoundMultiplyNanoSeconds.count(), -18);
  135. }
  136. TEST_F(DurationTest, SecondsDivideWithNegativeSuccess)
  137. {
  138. constexpr AZStd::chrono::seconds testSeconds(17);
  139. constexpr AZStd::chrono::seconds negativeTestSeconds(-3);
  140. constexpr auto divideResultSeconds = testSeconds / negativeTestSeconds;
  141. static_assert(divideResultSeconds == -5, "divide result is incorrect");
  142. AZStd::chrono::seconds compoundDivideSeconds(-42);
  143. compoundDivideSeconds /= -2;
  144. EXPECT_EQ(compoundDivideSeconds.count(), 21);
  145. }
  146. TEST_F(DurationTest, MicrosecondsModOperatorSuccess)
  147. {
  148. constexpr AZStd::chrono::microseconds microSeconds(23);
  149. constexpr AZStd::chrono::microseconds microSecondsDivisor(2);
  150. constexpr auto modResultMicroSeconds = microSeconds % microSecondsDivisor;
  151. static_assert(modResultMicroSeconds.count() == 1, "mod result is incorrect");
  152. AZStd::chrono::microseconds compoundModMicroSeconds(30);
  153. compoundModMicroSeconds %= 7;
  154. EXPECT_EQ(compoundModMicroSeconds.count(), 2);
  155. }
  156. }
  157. namespace Date
  158. {
  159. // Contains test for the date utility functions added in C++20
  160. TEST_F(DurationTest, DayDuration_ConvertibleToOtherDurations_Succeeds)
  161. {
  162. constexpr AZStd::chrono::days testDays(2);
  163. static_assert(AZStd::chrono::hours(48) == testDays);
  164. static_assert(AZStd::chrono::minutes(2880) == testDays);
  165. constexpr AZStd::chrono::seconds convertedSeconds = testDays;
  166. static_assert(convertedSeconds == AZStd::chrono::seconds(2880 * 60));
  167. }
  168. TEST_F(DurationTest, WeeksDuration_ConvertibleToOtherDurations_Succeeds)
  169. {
  170. constexpr AZStd::chrono::weeks testWeeks(2);
  171. static_assert(AZStd::chrono::days(14) == testWeeks);
  172. static_assert(AZStd::chrono::hours(336) == testWeeks);
  173. constexpr AZStd::chrono::minutes convertedMinutes = testWeeks;
  174. static_assert(convertedMinutes == AZStd::chrono::minutes(336 * 60));
  175. }
  176. TEST_F(DurationTest, YearsDuration_ConvertibleToOtherDurations_Succeeds)
  177. {
  178. constexpr AZStd::chrono::years testYears(2);
  179. static_assert(AZStd::chrono::months(24) == testYears);
  180. static_assert(AZStd::chrono::days(365 * 2) < testYears);
  181. static_assert(AZStd::chrono::days(366 * 2) > testYears);
  182. // A year is 365.2425 days in the gregorian calendar
  183. // It is not convertible a duration of chrono::days
  184. // without a cast due to precisions loss
  185. // duration_cast will round toward 0
  186. constexpr auto convertedDays = AZStd::chrono::duration_cast<AZStd::chrono::days>(testYears);
  187. static_assert(convertedDays == AZStd::chrono::days(730));
  188. // There should be at least 52 weeks in every year
  189. constexpr auto convertedWeeks = AZStd::chrono::duration_cast<AZStd::chrono::weeks>(testYears);
  190. static_assert(convertedWeeks == AZStd::chrono::weeks(104));
  191. }
  192. TEST_F(DurationTest, MonthsDuration_ConvertibleToOtherDurations_Succeeds)
  193. {
  194. constexpr AZStd::chrono::months testMonths(24);
  195. static_assert(AZStd::chrono::years(2) == testMonths);
  196. // Every month is at least 4 weeks
  197. static_assert(AZStd::chrono::weeks(8) <= testMonths);
  198. // Every month is at least 28 days
  199. static_assert(AZStd::chrono::days(56) <= testMonths);
  200. // A month is defined as a year in the gregorian calendar divided by 12
  201. // A year is 365.2425 days so a month is defined as 365.2425 / 12 = 30.436875
  202. // duration_cast will round toward 0
  203. // 24 months are equivalent to 30.436875 * 24 days = 730.485 days
  204. constexpr auto convertedDays = AZStd::chrono::duration_cast<AZStd::chrono::days>(testMonths);
  205. static_assert(convertedDays >= AZStd::chrono::days(730));
  206. static_assert(convertedDays < AZStd::chrono::days(731));
  207. // 24 months are equivalent to (30.436875 / 7) * 24 weeks = 104.355... weeks
  208. constexpr auto convertedWeeks = AZStd::chrono::duration_cast<AZStd::chrono::weeks>(testMonths);
  209. static_assert(convertedWeeks >= AZStd::chrono::weeks(104));
  210. static_assert(convertedWeeks < AZStd::chrono::weeks(105));
  211. }
  212. TEST_F(DurationTest, UtcClock_IsConvertibleToSystemClock)
  213. {
  214. auto utcTime = AZStd::chrono::utc_clock::now();
  215. auto sysTime = AZStd::chrono::utc_clock::to_sys(utcTime);
  216. // sysTime should not be equal to utc time due to the accumulation of leap seconds
  217. // https://www.ietf.org/timezones/data/leap-seconds.list
  218. EXPECT_NE(utcTime.time_since_epoch(), sysTime.time_since_epoch());
  219. }
  220. TEST_F(DurationTest, UtcClock_IsConvertibleFromSystemClock)
  221. {
  222. auto sysTime = AZStd::chrono::system_clock::now();
  223. auto utcTime = AZStd::chrono::utc_clock::from_sys(sysTime);
  224. // sysTime should not be equal to utc time due to the accumulation of leap seconds
  225. // https://www.ietf.org/timezones/data/leap-seconds.list
  226. EXPECT_NE(sysTime.time_since_epoch(), utcTime.time_since_epoch());
  227. }
  228. TEST_F(DurationTest, UtcClock_ToSys_RoundTrips_WithFromSys)
  229. {
  230. const auto utcTime = AZStd::chrono::utc_clock::now();
  231. const auto sysTime = AZStd::chrono::utc_clock::to_sys(utcTime);
  232. const auto utcTimeRoundTrip = AZStd::chrono::utc_clock::from_sys(sysTime);
  233. EXPECT_EQ(utcTime, utcTimeRoundTrip);
  234. }
  235. // BIG NOTE: chrono::days with an s is a chrono::duration counting days
  236. // chrono::day without an s is a abstraction of a day
  237. TEST_F(DurationTest, Day_CanRepresent_DayOfArbitrary_Month)
  238. {
  239. AZStd::chrono::day testDay{};
  240. // A day is only valid between 1 and 31 inclusive
  241. // default constructs to 0
  242. EXPECT_FALSE(testDay.ok());
  243. // pre-increment / pre-decrement
  244. auto updatedDay = ++testDay;
  245. EXPECT_EQ(testDay, updatedDay);
  246. updatedDay = --testDay;
  247. EXPECT_EQ(testDay, updatedDay);
  248. // post-increment / post-decrement
  249. auto oldDay = testDay++;
  250. EXPECT_NE(oldDay, testDay);
  251. oldDay = testDay--;
  252. EXPECT_NE(oldDay, testDay);
  253. // Day 1 - ok
  254. testDay = AZStd::chrono::day{ 1 };
  255. EXPECT_TRUE(testDay.ok());
  256. // Day 31 - ok
  257. testDay = AZStd::chrono::day{ 31 };
  258. EXPECT_TRUE(testDay.ok());
  259. // Day 32 - not ok
  260. testDay = AZStd::chrono::day{ 32 };
  261. EXPECT_FALSE(testDay.ok());
  262. }
  263. TEST_F(DurationTest, Day_Comparison_Succeeds)
  264. {
  265. constexpr AZStd::chrono::day testDay1{ 13 };
  266. constexpr AZStd::chrono::day testDay2{ 27 };
  267. static_assert(testDay1 == testDay1);
  268. static_assert(testDay1 != testDay2);
  269. static_assert(testDay1 < testDay2);
  270. static_assert(testDay2 > testDay1);
  271. static_assert(testDay1 <= testDay2);
  272. static_assert(testDay2 >= testDay1);
  273. }
  274. TEST_F(DurationTest, Day_Arithmetic_Succeeds)
  275. {
  276. constexpr AZStd::chrono::day testDay1{ 20 };
  277. constexpr AZStd::chrono::day testDay2{ 25 };
  278. constexpr AZStd::chrono::days days{ 15 };
  279. static_assert(testDay1 + days == AZStd::chrono::day{ 35 });
  280. static_assert(testDay2 - days == AZStd::chrono::day{ 10 });
  281. static_assert(testDay2 - testDay1 == AZStd::chrono::days{ 5 });
  282. static_assert(testDay1 - testDay2 == AZStd::chrono::days{ -5 });
  283. }
  284. // BIG NOTE: chrono::months with an s is a chrono::duration counting months
  285. // chrono::month without an s is a abstraction of a month
  286. TEST_F(DurationTest, Month_CanRepresent_MonthOfYear)
  287. {
  288. AZStd::chrono::month testMonth{};
  289. // A month is only valid between 1 and 12 inclusive
  290. // default constructs to 0
  291. EXPECT_FALSE(testMonth.ok());
  292. // pre-increment / pre-decrement
  293. auto updatedMonth = ++testMonth;
  294. EXPECT_EQ(testMonth, updatedMonth);
  295. updatedMonth = --testMonth;
  296. EXPECT_EQ(testMonth, updatedMonth);
  297. // post-increment / post-decrement
  298. auto oldMonth = testMonth++;
  299. EXPECT_NE(oldMonth, testMonth);
  300. oldMonth = testMonth--;
  301. EXPECT_NE(oldMonth, testMonth);
  302. // Month 1 - ok
  303. testMonth = AZStd::chrono::month{ 1 };
  304. EXPECT_TRUE(testMonth.ok());
  305. // Month 12 - ok
  306. testMonth = AZStd::chrono::month{ 12 };
  307. EXPECT_TRUE(testMonth.ok());
  308. // Month 13 - not ok
  309. testMonth = AZStd::chrono::month{ 13 };
  310. EXPECT_FALSE(testMonth.ok());
  311. }
  312. TEST_F(DurationTest, Month_Comparison_Succeeds)
  313. {
  314. constexpr AZStd::chrono::day testMonth1{ 13 };
  315. constexpr AZStd::chrono::day testMonth2{ 27 };
  316. static_assert(testMonth1 == testMonth1);
  317. static_assert(testMonth1 != testMonth2);
  318. static_assert(testMonth1 < testMonth2);
  319. static_assert(testMonth2 > testMonth1);
  320. static_assert(testMonth1 <= testMonth2);
  321. static_assert(testMonth2 >= testMonth1);
  322. }
  323. TEST_F(DurationTest, Month_Arithmetic_Succeeds)
  324. {
  325. constexpr AZStd::chrono::month testMonth1{ 3 };
  326. constexpr AZStd::chrono::month testMonth2{ 10 };
  327. constexpr AZStd::chrono::months months{ 6 };
  328. static_assert(testMonth1 + months == AZStd::chrono::month{ 9 });
  329. static_assert(testMonth2 - months == AZStd::chrono::month{ 4 });
  330. static_assert(testMonth2 - testMonth1 == AZStd::chrono::months{ 7 });
  331. static_assert(testMonth1 - testMonth2 == AZStd::chrono::months{ 5 });
  332. }
  333. TEST_F(DurationTest, Month_CanArithmetic_IsCircular)
  334. {
  335. // August + 5 months should be January
  336. constexpr auto monthOverflow = AZStd::chrono::August + AZStd::chrono::months{ 5 };
  337. static_assert(AZStd::chrono::January == monthOverflow);
  338. // August - 8 months should be December
  339. constexpr auto monthUnderflow = AZStd::chrono::August - AZStd::chrono::months{ 8 };
  340. static_assert(AZStd::chrono::December == monthUnderflow);
  341. // Subtraction between months is bounded in the range of [0, 11]
  342. // It represents a how many months to add to go form the right month to the left month
  343. // Because a month does not take year into account, the range is circular
  344. // September - August should be 1 month as adding 1 month to August results in September
  345. static_assert(AZStd::chrono::months{ 1 } == AZStd::chrono::September - AZStd::chrono::August);
  346. // August - September should be 11 months as adding 11 months to September results in Augustst
  347. static_assert(AZStd::chrono::months{ 11 } == AZStd::chrono::August - AZStd::chrono::September);
  348. }
  349. // BIG NOTE: chrono::years with an s is a chrono::duration counting years
  350. // chrono::year without an s is a abstraction of a year
  351. TEST_F(DurationTest, Year_Represents_YearInCivilCalendar)
  352. {
  353. AZStd::chrono::year testYear{};
  354. // A year is valid between -32767 and -32767 inclusive
  355. // default constructs to 0
  356. EXPECT_TRUE(testYear.ok());
  357. // pre-increment / pre-decrement
  358. auto updatedYear = ++testYear;
  359. EXPECT_EQ(testYear, updatedYear);
  360. updatedYear = --testYear;
  361. EXPECT_EQ(testYear, updatedYear);
  362. // post-increment / post-decrement
  363. auto oldYear = testYear++;
  364. EXPECT_NE(oldYear, testYear);
  365. oldYear = testYear--;
  366. EXPECT_NE(oldYear, testYear);
  367. // Year 2000 - ok
  368. testYear = AZStd::chrono::year{ 2000 };
  369. EXPECT_TRUE(testYear.ok());
  370. // Year -32768 - not ok
  371. testYear = AZStd::chrono::year{ -32768 };
  372. EXPECT_FALSE(testYear.ok());
  373. // Year 32768 - not ok
  374. testYear = AZStd::chrono::year{ 32768 };
  375. EXPECT_FALSE(testYear.ok());
  376. }
  377. TEST_F(DurationTest, Year_Comparison_Succeeds)
  378. {
  379. constexpr AZStd::chrono::year testYear1{ 2000 };
  380. constexpr AZStd::chrono::year testYear2{ 2025 };
  381. static_assert(testYear1 == testYear1);
  382. static_assert(testYear1 != testYear2);
  383. static_assert(testYear1 < testYear2);
  384. static_assert(testYear2 > testYear1);
  385. static_assert(testYear1 <= testYear2);
  386. static_assert(testYear2 >= testYear1);
  387. }
  388. TEST_F(DurationTest, Year_Arithmetic_Succeeds)
  389. {
  390. constexpr AZStd::chrono::year testYear1{ 2000 };
  391. constexpr AZStd::chrono::year testYear2{ 2025 };
  392. constexpr AZStd::chrono::years years{ 15 };
  393. static_assert(testYear1 + years == AZStd::chrono::year{ 2015 });
  394. static_assert(testYear2 - years == AZStd::chrono::year{ 2010 });
  395. static_assert(testYear2 - testYear1 == AZStd::chrono::years{ 25 });
  396. static_assert(testYear1 - testYear2 == AZStd::chrono::years{ -25 });
  397. }
  398. TEST_F(DurationTest, Weekday_Represents_DayOfWeek_BetweenSundayAndSaturday)
  399. {
  400. AZStd::chrono::weekday testWeekday{};
  401. // default constructs to 0
  402. // which corresponds to Sunbday
  403. EXPECT_TRUE(testWeekday.ok());
  404. // pre-increment / pre-decrement
  405. auto updatedWeekday = ++testWeekday;
  406. EXPECT_EQ(testWeekday, updatedWeekday);
  407. updatedWeekday = --testWeekday;
  408. EXPECT_EQ(testWeekday, updatedWeekday);
  409. // post-increment / post-decrement
  410. auto oldWeekday = testWeekday++;
  411. EXPECT_NE(oldWeekday, testWeekday);
  412. oldWeekday = testWeekday--;
  413. EXPECT_NE(oldWeekday, testWeekday);
  414. // Weekday 4 - ok
  415. testWeekday = AZStd::chrono::weekday{ 4 };
  416. EXPECT_TRUE(testWeekday.ok());
  417. // Weekday 7 - ok (converts to Sunday(0)
  418. testWeekday = AZStd::chrono::weekday{ 7 };
  419. EXPECT_TRUE(testWeekday.ok());
  420. // Weekday 8 - not ok
  421. testWeekday = AZStd::chrono::weekday{ 8 };
  422. EXPECT_FALSE(testWeekday.ok());
  423. }
  424. TEST_F(DurationTest, Weekday_Comparison_Succeeds)
  425. {
  426. // Weekdays can only compare for equality, not order
  427. // since their is no universal consensu on the start of the week
  428. // http://eel.is/c++draft/time#cal.wd.overview-note-1
  429. constexpr AZStd::chrono::weekday testWeekday1{ 0 };
  430. constexpr AZStd::chrono::weekday testWeekday2{ 3 };
  431. constexpr AZStd::chrono::weekday testWeekday3{ 6 };
  432. static_assert(testWeekday1 != testWeekday2);
  433. static_assert(testWeekday1 != testWeekday3);
  434. static_assert(testWeekday2 != testWeekday3);
  435. static_assert(testWeekday1 == AZStd::chrono::Sunday);
  436. static_assert(testWeekday2 == AZStd::chrono::Wednesday);
  437. static_assert(testWeekday3 == AZStd::chrono::Saturday);
  438. }
  439. TEST_F(DurationTest, Weekday_Arithmetic_Succeeds)
  440. {
  441. constexpr AZStd::chrono::weekday testWeekday1{ AZStd::chrono::Monday };
  442. constexpr AZStd::chrono::weekday testWeekday2{ AZStd::chrono::Thursday };
  443. constexpr AZStd::chrono::days days{ 15 };
  444. // adding two weeks and 1 day should transition Monday -> Tuesday
  445. static_assert(testWeekday1 + days == AZStd::chrono::Tuesday);
  446. // subtracting two weeks and 1 day should transition Thursday -> Wednesday
  447. static_assert(testWeekday2 - days == AZStd::chrono::Wednesday);
  448. // Weekday arithmetic is circular
  449. // Subtraction returns a value that represents that can be added to the right operand
  450. // to get the left operand.
  451. // i.e Monday(1) - Thursday(4) = 4 days as adding 4 days to Thursday result in Monday
  452. static_assert(testWeekday2 - testWeekday1 == AZStd::chrono::days{ 3 });
  453. static_assert(testWeekday1 - testWeekday2 == AZStd::chrono::days{ 4 });
  454. }
  455. TEST_F(DurationTest, YearMonthDay_RepresentsDateInCivilCalendar)
  456. {
  457. using namespace AZStd::chrono;
  458. constexpr AZStd::chrono::year_month_day ymd = 2024_y / February / 29_d;
  459. static_assert(ymd.ok());
  460. static_assert(ymd.year() == 2024_y);
  461. static_assert(ymd.month() == February);
  462. static_assert(ymd.day() == 29_d);
  463. }
  464. TEST_F(DurationTest, YearMonthDay_Comparison_Succeeds)
  465. {
  466. using namespace AZStd::chrono;
  467. constexpr AZStd::chrono::year_month_day ymd1 = 2024_y / February / 29_d;
  468. constexpr AZStd::chrono::year_month_day ymd2 = 2024_y / March / 1_d;
  469. static_assert(ymd1 == ymd1);
  470. static_assert(ymd1 != ymd2);
  471. }
  472. TEST_F(DurationTest, YearMonthDay_Arithmetic_Succeeds)
  473. {
  474. using namespace AZStd::chrono;
  475. constexpr AZStd::chrono::year_month_day ymd1{ 2024_y / February / 29_d };
  476. constexpr AZStd::chrono::years years{ 3 };
  477. // validate adding years to a date
  478. // February 2027 is not a leap year, so the 29th is not a valid day,
  479. // making the year-month-day not ok
  480. static_assert(!(ymd1 + years).ok());
  481. static_assert((ymd1 + years).year() == 2027_y);
  482. static_assert((ymd1 + years).month() == February);
  483. // check subtracting years from a date
  484. // February 2021 is also not a leap year
  485. static_assert(!(ymd1 - years).ok());
  486. static_assert((ymd1 - years).year() == 2021_y);
  487. static_assert((ymd1 - years).month() == February);
  488. // test adding months to a date
  489. constexpr AZStd::chrono::months months{ 2 };
  490. // April 29th is a valid date
  491. static_assert((ymd1 + months).ok());
  492. static_assert((ymd1 + months).year() == 2024_y);
  493. static_assert((ymd1 + months).month() == April);
  494. static_assert((ymd1 + months).day() == 29_d);
  495. // verify subtracting months from a date
  496. // December 29th is a valid date of the previous year
  497. static_assert((ymd1 - months).ok());
  498. static_assert((ymd1 - months).year() == 2023_y);
  499. static_assert((ymd1 - months).month() == December);
  500. static_assert((ymd1 - months).day() == 29_d);
  501. }
  502. TEST_F(DurationTest, HourMinuteSecond_RepresentsTimeOfDay)
  503. {
  504. // Contrived value of time past 12 hours in the day
  505. constexpr AZStd::chrono::microseconds time14Hours6Minutes23Seconds506293Microseconds{ AZStd::chrono::hours{ 14 } +
  506. AZStd::chrono::minutes{ 6 } +
  507. AZStd::chrono::seconds{ 23 } +
  508. AZStd::chrono::microseconds{ 506293 } };
  509. constexpr AZStd::chrono::hh_mm_ss timeOfDay(time14Hours6Minutes23Seconds506293Microseconds);
  510. static_assert(timeOfDay.hours() == AZStd::chrono::hours{ 14 });
  511. static_assert(timeOfDay.minutes() == AZStd::chrono::minutes{ 6 });
  512. static_assert(timeOfDay.seconds() == AZStd::chrono::seconds{ 23 });
  513. static_assert(timeOfDay.subseconds() == AZStd::chrono::microseconds{ 506293 });
  514. }
  515. TEST_F(DurationTest, HourMinuteSecond_CanBeNegative)
  516. {
  517. using namespace AZStd::chrono_literals;
  518. constexpr AZStd::chrono::hh_mm_ss timeOfDay(-5s);
  519. static_assert(timeOfDay.is_negative());
  520. // hours, minutes, seconds and subseconds are stored as absolute values
  521. // using the hh_mm_ss::to_duration will return a duration accounting for the sign
  522. static_assert(timeOfDay.hours() == AZStd::chrono::hours{ 0 });
  523. static_assert(timeOfDay.minutes() == AZStd::chrono::minutes{ 0 });
  524. static_assert(timeOfDay.seconds() == AZStd::chrono::seconds{ 5 });
  525. static_assert(timeOfDay.subseconds() == typename decltype(timeOfDay)::precision{ 0 });
  526. static_assert(timeOfDay.to_duration() == -5s);
  527. }
  528. }
  529. namespace Time_12_24_Functions
  530. {
  531. TEST_F(DurationTest, IsAm_Hours_Succeeds)
  532. {
  533. using namespace AZStd::chrono_literals;
  534. static_assert(AZStd::chrono::is_am(0h));
  535. static_assert(AZStd::chrono::is_am(11h));
  536. static_assert(!AZStd::chrono::is_am(12h));
  537. static_assert(!AZStd::chrono::is_am(23h));
  538. }
  539. TEST_F(DurationTest, IsPm_Hours_Succeeds)
  540. {
  541. using namespace AZStd::chrono_literals;
  542. static_assert(!AZStd::chrono::is_pm(0h));
  543. static_assert(!AZStd::chrono::is_pm(11h));
  544. static_assert(AZStd::chrono::is_pm(12h));
  545. static_assert(AZStd::chrono::is_pm(23h));
  546. }
  547. TEST_F(DurationTest, Make12_CanConvertHours24)
  548. {
  549. using namespace AZStd::chrono_literals;
  550. static_assert(AZStd::chrono::make12(0h) == 12h);
  551. static_assert(AZStd::chrono::make12(11h) == 11h);
  552. static_assert(AZStd::chrono::make12(12h) == 12h);
  553. static_assert(AZStd::chrono::make12(23h) == 11h);
  554. }
  555. TEST_F(DurationTest, Make24_CanConvertHours12_WithPMFalse_ToHoursBelow12)
  556. {
  557. using namespace AZStd::chrono_literals;
  558. static_assert(AZStd::chrono::make24(1h, false) == 1h);
  559. static_assert(AZStd::chrono::make24(11h, false) == 11h);
  560. static_assert(AZStd::chrono::make24(12h, false) == 0h);
  561. }
  562. TEST_F(DurationTest, Make24_CanConvertHours12_WithPMTrue_ToHoursBelow12)
  563. {
  564. using namespace AZStd::chrono_literals;
  565. static_assert(AZStd::chrono::make24(1h, true) == 13h);
  566. static_assert(AZStd::chrono::make24(11h, true) == 23h);
  567. static_assert(AZStd::chrono::make24(12h, true) == 12h);
  568. }
  569. }
  570. }