Date.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/StringBuilder.h>
  7. #include <LibCore/DateTime.h>
  8. #include <LibJS/Runtime/Date.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. #include <time.h>
  11. namespace JS {
  12. Date* Date::create(GlobalObject& global_object, Core::DateTime datetime, i16 milliseconds, bool is_invalid)
  13. {
  14. return global_object.heap().allocate<Date>(global_object, datetime, milliseconds, is_invalid, *global_object.date_prototype());
  15. }
  16. Date::Date(Core::DateTime datetime, i16 milliseconds, bool is_invalid, Object& prototype)
  17. : Object(prototype)
  18. , m_datetime(datetime)
  19. , m_milliseconds(milliseconds)
  20. , m_is_invalid(is_invalid)
  21. {
  22. }
  23. Date::~Date()
  24. {
  25. }
  26. tm Date::to_utc_tm() const
  27. {
  28. time_t timestamp = m_datetime.timestamp();
  29. struct tm tm;
  30. gmtime_r(&timestamp, &tm);
  31. return tm;
  32. }
  33. int Date::utc_date() const
  34. {
  35. return to_utc_tm().tm_mday;
  36. }
  37. int Date::utc_day() const
  38. {
  39. return to_utc_tm().tm_wday;
  40. }
  41. int Date::utc_full_year() const
  42. {
  43. return to_utc_tm().tm_year + 1900;
  44. }
  45. int Date::utc_hours() const
  46. {
  47. return to_utc_tm().tm_hour;
  48. }
  49. int Date::utc_minutes() const
  50. {
  51. return to_utc_tm().tm_min;
  52. }
  53. int Date::utc_month() const
  54. {
  55. return to_utc_tm().tm_mon;
  56. }
  57. int Date::utc_seconds() const
  58. {
  59. return to_utc_tm().tm_sec;
  60. }
  61. String Date::gmt_date_string() const
  62. {
  63. // Mon, 18 Dec 1995 17:28:35 GMT
  64. // FIXME: Note that we're totally cheating with the timezone part here..
  65. return datetime().to_string("%a, %e %b %Y %T GMT");
  66. }
  67. String Date::iso_date_string() const
  68. {
  69. auto tm = to_utc_tm();
  70. int year = tm.tm_year + 1900;
  71. int month = tm.tm_mon + 1;
  72. StringBuilder builder;
  73. if (year < 0)
  74. builder.appendff("-{:06}", -year);
  75. else if (year > 9999)
  76. builder.appendff("+{:06}", year);
  77. else
  78. builder.appendff("{:04}", year);
  79. builder.append('-');
  80. builder.appendff("{:02}", month);
  81. builder.append('-');
  82. builder.appendff("{:02}", tm.tm_mday);
  83. builder.append('T');
  84. builder.appendff("{:02}", tm.tm_hour);
  85. builder.append(':');
  86. builder.appendff("{:02}", tm.tm_min);
  87. builder.append(':');
  88. builder.appendff("{:02}", tm.tm_sec);
  89. builder.append('.');
  90. builder.appendff("{:03}", m_milliseconds);
  91. builder.append('Z');
  92. return builder.build();
  93. }
  94. // https://tc39.es/ecma262/#eqn-HoursPerDay
  95. static constexpr double HOURS_PER_DAY = 24;
  96. // https://tc39.es/ecma262/#eqn-MinutesPerHour
  97. static constexpr double MINUTES_PER_HOUR = 60;
  98. // https://tc39.es/ecma262/#eqn-SecondsPerMinute
  99. static constexpr double SECONDS_PER_MINUTE = 60;
  100. // https://tc39.es/ecma262/#eqn-msPerSecond
  101. static constexpr double MS_PER_SECOND = 1000;
  102. // https://tc39.es/ecma262/#eqn-msPerMinute
  103. static constexpr double MS_PER_MINUTE = 60000;
  104. // https://tc39.es/ecma262/#eqn-msPerHour
  105. static constexpr double MS_PER_HOUR = 3600000;
  106. // https://tc39.es/ecma262/#eqn-msPerDay
  107. static constexpr double MS_PER_DAY = 86400000;
  108. // DayWithinYear(t), https://tc39.es/ecma262/#eqn-DayWithinYear
  109. u16 day_within_year(double t)
  110. {
  111. // Day(t) - DayFromYear(YearFromTime(t))
  112. return static_cast<u16>(day(t) - day_from_year(year_from_time(t)));
  113. }
  114. // DateFromTime(t), https://tc39.es/ecma262/#sec-date-number
  115. u8 date_from_time(double t)
  116. {
  117. switch (month_from_time(t)) {
  118. // DayWithinYear(t) + 1𝔽 if MonthFromTime(t) = +0𝔽
  119. case 0:
  120. return day_within_year(t) + 1;
  121. // DayWithinYear(t) - 30𝔽 if MonthFromTime(t) = 1𝔽
  122. case 1:
  123. return day_within_year(t) - 30;
  124. // DayWithinYear(t) - 58𝔽 - InLeapYear(t) if MonthFromTime(t) = 2𝔽
  125. case 2:
  126. return day_within_year(t) - 58 - in_leap_year(t);
  127. // DayWithinYear(t) - 89𝔽 - InLeapYear(t) if MonthFromTime(t) = 3𝔽
  128. case 3:
  129. return day_within_year(t) - 89 - in_leap_year(t);
  130. // DayWithinYear(t) - 119𝔽 - InLeapYear(t) if MonthFromTime(t) = 4𝔽
  131. case 4:
  132. return day_within_year(t) - 119 - in_leap_year(t);
  133. // DayWithinYear(t) - 150𝔽 - InLeapYear(t) if MonthFromTime(t) = 5𝔽
  134. case 5:
  135. return day_within_year(t) - 150 - in_leap_year(t);
  136. // DayWithinYear(t) - 180𝔽 - InLeapYear(t) if MonthFromTime(t) = 6𝔽
  137. case 6:
  138. return day_within_year(t) - 180 - in_leap_year(t);
  139. // DayWithinYear(t) - 211𝔽 - InLeapYear(t) if MonthFromTime(t) = 7𝔽
  140. case 7:
  141. return day_within_year(t) - 211 - in_leap_year(t);
  142. // DayWithinYear(t) - 242𝔽 - InLeapYear(t) if MonthFromTime(t) = 8𝔽
  143. case 8:
  144. return day_within_year(t) - 242 - in_leap_year(t);
  145. // DayWithinYear(t) - 272𝔽 - InLeapYear(t) if MonthFromTime(t) = 9𝔽
  146. case 9:
  147. return day_within_year(t) - 272 - in_leap_year(t);
  148. // DayWithinYear(t) - 303𝔽 - InLeapYear(t) if MonthFromTime(t) = 10𝔽
  149. case 10:
  150. return day_within_year(t) - 303 - in_leap_year(t);
  151. // DayWithinYear(t) - 333𝔽 - InLeapYear(t) if MonthFromTime(t) = 11𝔽
  152. case 11:
  153. return day_within_year(t) - 333 - in_leap_year(t);
  154. default:
  155. VERIFY_NOT_REACHED();
  156. }
  157. }
  158. // DaysInYear(y), https://tc39.es/ecma262/#eqn-DaysInYear
  159. u16 days_in_year(i32 y)
  160. {
  161. // 365𝔽 if (ℝ(y) modulo 4) ≠ 0
  162. if (y % 4 != 0)
  163. return 365;
  164. // 366𝔽 if (ℝ(y) modulo 4) = 0 and (ℝ(y) modulo 100) ≠ 0
  165. if (y % 4 == 0 && y % 100 != 0)
  166. return 366;
  167. // 365𝔽 if (ℝ(y) modulo 100) = 0 and (ℝ(y) modulo 400) ≠ 0
  168. if (y % 100 == 0 && y % 400 != 0)
  169. return 365;
  170. // 366𝔽 if (ℝ(y) modulo 400) = 0
  171. if (y % 400 == 0)
  172. return 366;
  173. VERIFY_NOT_REACHED();
  174. }
  175. // DayFromYear(y), https://tc39.es/ecma262/#eqn-DaysFromYear
  176. double day_from_year(i32 y)
  177. {
  178. // 𝔽(365 × (ℝ(y) - 1970) + floor((ℝ(y) - 1969) / 4) - floor((ℝ(y) - 1901) / 100) + floor((ℝ(y) - 1601) / 400))
  179. return 365 * (y - 1970) + floor((y - 1969) / 4.0) - floor((y - 1901) / 100.0) + floor((y - 1601) / 400.0);
  180. }
  181. // YearFromTime(t), https://tc39.es/ecma262/#eqn-YearFromTime
  182. i32 year_from_time(double t)
  183. {
  184. // the largest integral Number y (closest to +∞) such that TimeFromYear(y) ≤ t
  185. return static_cast<i32>(t / (365.0 * MS_PER_DAY) + 1970);
  186. }
  187. // InLeapYear(t), https://tc39.es/ecma262/#eqn-InLeapYear
  188. bool in_leap_year(double t)
  189. {
  190. // +0𝔽 if DaysInYear(YearFromTime(t)) = 365𝔽
  191. // 1𝔽 if DaysInYear(YearFromTime(t)) = 366𝔽
  192. return days_in_year(year_from_time(t)) == 366;
  193. }
  194. // MonthFromTime(t), https://tc39.es/ecma262/#eqn-MonthFromTime
  195. u8 month_from_time(double t)
  196. {
  197. auto in_leap_year = JS::in_leap_year(t);
  198. auto day_within_year = JS::day_within_year(t);
  199. // +0𝔽 if +0𝔽 ≤ DayWithinYear(t) < 31𝔽
  200. if (day_within_year < 31)
  201. return 0;
  202. // 1𝔽 if 31𝔽 ≤ DayWithinYear(t) < 59𝔽 + InLeapYear(t)
  203. if (31 <= day_within_year && day_within_year < 59 + in_leap_year)
  204. return 1;
  205. // 2𝔽 if 59𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 90𝔽 + InLeapYear(t)
  206. if (59 + in_leap_year <= day_within_year && day_within_year < 90 + in_leap_year)
  207. return 2;
  208. // 3𝔽 if 90𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 120𝔽 + InLeapYear(t)
  209. if (90 + in_leap_year <= day_within_year && day_within_year < 120 + in_leap_year)
  210. return 3;
  211. // 4𝔽 if 120𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 151𝔽 + InLeapYear(t)
  212. if (120 + in_leap_year <= day_within_year && day_within_year < 151 + in_leap_year)
  213. return 4;
  214. // 5𝔽 if 151𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 181𝔽 + InLeapYear(t)
  215. if (151 + in_leap_year <= day_within_year && day_within_year < 181 + in_leap_year)
  216. return 5;
  217. // 6𝔽 if 181𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 212𝔽 + InLeapYear(t)
  218. if (181 + in_leap_year <= day_within_year && day_within_year < 212 + in_leap_year)
  219. return 6;
  220. // 7𝔽 if 212𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 243𝔽 + InLeapYear(t)
  221. if (212 + in_leap_year <= day_within_year && day_within_year < 243 + in_leap_year)
  222. return 7;
  223. // 8𝔽 if 243𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 273𝔽 + InLeapYear(t)
  224. if (243 + in_leap_year <= day_within_year && day_within_year < 273 + in_leap_year)
  225. return 8;
  226. // 9𝔽 if 273𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 304𝔽 + InLeapYear(t)
  227. if (273 + in_leap_year <= day_within_year && day_within_year < 304 + in_leap_year)
  228. return 9;
  229. // 10𝔽 if 304𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 334𝔽 + InLeapYear(t)
  230. if (304 + in_leap_year <= day_within_year && day_within_year < 334 + in_leap_year)
  231. return 10;
  232. // 11𝔽 if 334𝔽 + InLeapYear(t) ≤ DayWithinYear(t) < 365𝔽 + InLeapYear(t)
  233. if (334 + in_leap_year <= day_within_year && day_within_year < 365 + in_leap_year)
  234. return 11;
  235. VERIFY_NOT_REACHED();
  236. }
  237. // HourFromTime(t), https://tc39.es/ecma262/#eqn-HourFromTime
  238. u8 hour_from_time(double t)
  239. {
  240. // 𝔽(floor(ℝ(t / msPerHour)) modulo HoursPerDay)
  241. return static_cast<u8>(fmod(floor(t / MS_PER_HOUR), HOURS_PER_DAY));
  242. }
  243. // MinFromTime(t), https://tc39.es/ecma262/#eqn-MinFromTime
  244. u8 min_from_time(double t)
  245. {
  246. // 𝔽(floor(ℝ(t / msPerMinute)) modulo MinutesPerHour)
  247. return static_cast<u8>(fmod(floor(t / MS_PER_MINUTE), MINUTES_PER_HOUR));
  248. }
  249. // SecFromTime(t), https://tc39.es/ecma262/#eqn-SecFromTime
  250. u8 sec_from_time(double t)
  251. {
  252. // 𝔽(floor(ℝ(t / msPerSecond)) modulo SecondsPerMinute)
  253. return static_cast<u8>(fmod(t / MS_PER_SECOND, SECONDS_PER_MINUTE));
  254. }
  255. // msFromTime(t), https://tc39.es/ecma262/#eqn-msFromTime
  256. u16 ms_from_time(double t)
  257. {
  258. // 𝔽(ℝ(t) modulo msPerSecond)
  259. return static_cast<u16>(fmod(t, MS_PER_SECOND));
  260. }
  261. // 21.4.1.11 MakeTime ( hour, min, sec, ms ), https://tc39.es/ecma262/#sec-maketime
  262. Value make_time(GlobalObject& global_object, Value hour, Value min, Value sec, Value ms)
  263. {
  264. // 1. If hour is not finite or min is not finite or sec is not finite or ms is not finite, return NaN.
  265. if (!hour.is_finite_number() || !min.is_finite_number() || !sec.is_finite_number() || !ms.is_finite_number())
  266. return js_nan();
  267. // 2. Let h be 𝔽(! ToIntegerOrInfinity(hour)).
  268. auto h = MUST(hour.to_integer_or_infinity(global_object));
  269. // 3. Let m be 𝔽(! ToIntegerOrInfinity(min)).
  270. auto m = MUST(min.to_integer_or_infinity(global_object));
  271. // 4. Let s be 𝔽(! ToIntegerOrInfinity(sec)).
  272. auto s = MUST(sec.to_integer_or_infinity(global_object));
  273. // 5. Let milli be 𝔽(! ToIntegerOrInfinity(ms)).
  274. auto milli = MUST(ms.to_integer_or_infinity(global_object));
  275. // 6. Let t be ((h * msPerHour + m * msPerMinute) + s * msPerSecond) + milli, performing the arithmetic according to IEEE 754-2019 rules (that is, as if using the ECMAScript operators * and +).
  276. // NOTE: C++ arithmetic abides by IEEE 754 rules
  277. auto t = ((h * MS_PER_HOUR + m * MS_PER_MINUTE) + s * MS_PER_SECOND) + milli;
  278. // 7. Return t.
  279. return Value(t);
  280. }
  281. // Day(t), https://tc39.es/ecma262/#eqn-Day
  282. double day(double time_value)
  283. {
  284. return floor(time_value / MS_PER_DAY);
  285. }
  286. // 21.4.1.12 MakeDay ( year, month, date ), https://tc39.es/ecma262/#sec-makeday
  287. Value make_day(GlobalObject& global_object, Value year, Value month, Value date)
  288. {
  289. // 1. If year is not finite or month is not finite or date is not finite, return NaN.
  290. if (!year.is_finite_number() || !month.is_finite_number() || !date.is_finite_number())
  291. return js_nan();
  292. // 2. Let y be 𝔽(! ToIntegerOrInfinity(year)).
  293. auto y = MUST(year.to_integer_or_infinity(global_object));
  294. // 3. Let m be 𝔽(! ToIntegerOrInfinity(month)).
  295. auto m = MUST(month.to_integer_or_infinity(global_object));
  296. // 4. Let dt be 𝔽(! ToIntegerOrInfinity(date)).
  297. auto dt = MUST(date.to_integer_or_infinity(global_object));
  298. // 5. Let ym be y + 𝔽(floor(ℝ(m) / 12)).
  299. auto ym = Value(y + floor(m / 12));
  300. // 6. If ym is not finite, return NaN.
  301. if (!ym.is_finite_number())
  302. return js_nan();
  303. // 7. Let mn be 𝔽(ℝ(m) modulo 12).
  304. // NOTE: This calculation has no side-effects and is unused, so we omit it
  305. // 8. Find a finite time value t such that YearFromTime(t) is ym and MonthFromTime(t) is mn and DateFromTime(t) is 1𝔽; but if this is not possible (because some argument is out of range), return NaN.
  306. if (!AK::is_within_range<int>(y) || !AK::is_within_range<int>(m + 1))
  307. return js_nan();
  308. auto t = Core::DateTime::create(static_cast<int>(y), static_cast<int>(m + 1), 0).timestamp() * 1000;
  309. // 9. Return Day(t) + dt - 1𝔽.
  310. return Value(day(static_cast<double>(t)) + dt - 1);
  311. }
  312. // 21.4.1.13 MakeDate ( day, time ), https://tc39.es/ecma262/#sec-makedate
  313. Value make_date(Value day, Value time)
  314. {
  315. // 1. If day is not finite or time is not finite, return NaN.
  316. if (!day.is_finite_number() || !time.is_finite_number())
  317. return js_nan();
  318. // 2. Let tv be day × msPerDay + time.
  319. auto tv = Value(day.as_double() * MS_PER_DAY + time.as_double());
  320. // 3. If tv is not finite, return NaN.
  321. if (!tv.is_finite_number())
  322. return js_nan();
  323. // 4. Return tv.
  324. return tv;
  325. }
  326. }