DateTimeFormat.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Array.h>
  7. #include <AK/StringBuilder.h>
  8. #include <LibUnicode/DateTimeFormat.h>
  9. #include <LibUnicode/Locale.h>
  10. #if ENABLE_UNICODE_DATA
  11. # include <LibUnicode/UnicodeDateTimeFormat.h>
  12. #endif
  13. namespace Unicode {
  14. HourCycle hour_cycle_from_string(StringView hour_cycle)
  15. {
  16. if (hour_cycle == "h11"sv)
  17. return Unicode::HourCycle::H11;
  18. else if (hour_cycle == "h12"sv)
  19. return Unicode::HourCycle::H12;
  20. else if (hour_cycle == "h23"sv)
  21. return Unicode::HourCycle::H23;
  22. else if (hour_cycle == "h24"sv)
  23. return Unicode::HourCycle::H24;
  24. VERIFY_NOT_REACHED();
  25. }
  26. StringView hour_cycle_to_string(HourCycle hour_cycle)
  27. {
  28. switch (hour_cycle) {
  29. case HourCycle::H11:
  30. return "h11"sv;
  31. case HourCycle::H12:
  32. return "h12"sv;
  33. case HourCycle::H23:
  34. return "h23"sv;
  35. case HourCycle::H24:
  36. return "h24"sv;
  37. default:
  38. VERIFY_NOT_REACHED();
  39. }
  40. }
  41. CalendarPatternStyle calendar_pattern_style_from_string(StringView style)
  42. {
  43. if (style == "narrow"sv)
  44. return CalendarPatternStyle::Narrow;
  45. if (style == "short"sv)
  46. return CalendarPatternStyle::Short;
  47. if (style == "long"sv)
  48. return CalendarPatternStyle::Long;
  49. if (style == "numeric"sv)
  50. return CalendarPatternStyle::Numeric;
  51. if (style == "2-digit"sv)
  52. return CalendarPatternStyle::TwoDigit;
  53. VERIFY_NOT_REACHED();
  54. }
  55. StringView calendar_pattern_style_to_string(CalendarPatternStyle style)
  56. {
  57. switch (style) {
  58. case CalendarPatternStyle::Narrow:
  59. return "narrow"sv;
  60. case CalendarPatternStyle::Short:
  61. return "short"sv;
  62. case CalendarPatternStyle::Long:
  63. return "long"sv;
  64. case CalendarPatternStyle::Numeric:
  65. return "numeric"sv;
  66. case CalendarPatternStyle::TwoDigit:
  67. return "2-digit"sv;
  68. default:
  69. VERIFY_NOT_REACHED();
  70. }
  71. }
  72. // https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
  73. Vector<Unicode::HourCycle> get_regional_hour_cycles([[maybe_unused]] StringView locale)
  74. {
  75. #if ENABLE_UNICODE_DATA
  76. if (auto hour_cycles = Detail::get_regional_hour_cycles(locale); !hour_cycles.is_empty())
  77. return hour_cycles;
  78. auto return_default_hour_cycles = []() {
  79. auto hour_cycles = Detail::get_regional_hour_cycles("001"sv);
  80. VERIFY(!hour_cycles.is_empty());
  81. return hour_cycles;
  82. };
  83. auto language = parse_unicode_language_id(locale);
  84. if (!language.has_value())
  85. return return_default_hour_cycles();
  86. if (!language->region.has_value())
  87. language = add_likely_subtags(*language);
  88. if (!language.has_value() || !language->region.has_value())
  89. return return_default_hour_cycles();
  90. if (auto hour_cycles = Detail::get_regional_hour_cycles(*language->region); !hour_cycles.is_empty())
  91. return hour_cycles;
  92. return return_default_hour_cycles();
  93. #else
  94. return {};
  95. #endif
  96. }
  97. Optional<Unicode::HourCycle> get_default_regional_hour_cycle(StringView locale)
  98. {
  99. if (auto hour_cycles = get_regional_hour_cycles(locale); !hour_cycles.is_empty())
  100. return hour_cycles.first();
  101. return {};
  102. }
  103. String combine_skeletons(StringView first, StringView second)
  104. {
  105. // https://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
  106. constexpr auto field_order = Array {
  107. "G"sv, // Era
  108. "yYuUr"sv, // Year
  109. "ML"sv, // Month
  110. "dDFg"sv, // Day
  111. "Eec"sv, // Weekday
  112. "abB"sv, // Period
  113. "hHKk"sv, // Hour
  114. "m"sv, // Minute
  115. "sSA"sv, // Second
  116. "zZOvVXx"sv, // Zone
  117. };
  118. StringBuilder builder;
  119. auto append_from_skeleton = [&](auto skeleton, auto ch) {
  120. auto first_index = skeleton.find(ch);
  121. if (!first_index.has_value())
  122. return false;
  123. auto last_index = skeleton.find_last(ch);
  124. builder.append(skeleton.substring_view(*first_index, *last_index - *first_index + 1));
  125. return true;
  126. };
  127. for (auto fields : field_order) {
  128. for (auto ch : fields) {
  129. if (append_from_skeleton(first, ch))
  130. break;
  131. if (append_from_skeleton(second, ch))
  132. break;
  133. }
  134. }
  135. return builder.build();
  136. }
  137. Optional<CalendarFormat> get_calendar_format([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] CalendarFormatType type)
  138. {
  139. #if ENABLE_UNICODE_DATA
  140. switch (type) {
  141. case CalendarFormatType::Date:
  142. return Detail::get_calendar_date_format(locale, calendar);
  143. case CalendarFormatType::Time:
  144. return Detail::get_calendar_time_format(locale, calendar);
  145. case CalendarFormatType::DateTime:
  146. return Detail::get_calendar_date_time_format(locale, calendar);
  147. default:
  148. VERIFY_NOT_REACHED();
  149. }
  150. #else
  151. return {};
  152. #endif
  153. }
  154. Vector<CalendarPattern> get_calendar_available_formats([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar)
  155. {
  156. #if ENABLE_UNICODE_DATA
  157. return Detail::get_calendar_available_formats(locale, calendar);
  158. #else
  159. return {};
  160. #endif
  161. }
  162. Optional<Unicode::CalendarRangePattern> get_calendar_default_range_format([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar)
  163. {
  164. #if ENABLE_UNICODE_DATA
  165. return Detail::get_calendar_default_range_format(locale, calendar);
  166. #else
  167. return {};
  168. #endif
  169. }
  170. Vector<Unicode::CalendarRangePattern> get_calendar_range_formats([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] StringView skeleton)
  171. {
  172. #if ENABLE_UNICODE_DATA
  173. return Detail::get_calendar_range_formats(locale, calendar, skeleton);
  174. #else
  175. return {};
  176. #endif
  177. }
  178. Vector<Unicode::CalendarRangePattern> get_calendar_range12_formats([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] StringView skeleton)
  179. {
  180. #if ENABLE_UNICODE_DATA
  181. return Detail::get_calendar_range12_formats(locale, calendar, skeleton);
  182. #else
  183. return {};
  184. #endif
  185. }
  186. Optional<StringView> get_calendar_era_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] CalendarPatternStyle style, [[maybe_unused]] Unicode::Era value)
  187. {
  188. #if ENABLE_UNICODE_DATA
  189. return Detail::get_calendar_era_symbol(locale, calendar, style, value);
  190. #else
  191. return {};
  192. #endif
  193. }
  194. Optional<StringView> get_calendar_month_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] CalendarPatternStyle style, [[maybe_unused]] Unicode::Month value)
  195. {
  196. #if ENABLE_UNICODE_DATA
  197. return Detail::get_calendar_month_symbol(locale, calendar, style, value);
  198. #else
  199. return {};
  200. #endif
  201. }
  202. Optional<StringView> get_calendar_weekday_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] CalendarPatternStyle style, [[maybe_unused]] Unicode::Weekday value)
  203. {
  204. #if ENABLE_UNICODE_DATA
  205. return Detail::get_calendar_weekday_symbol(locale, calendar, style, value);
  206. #else
  207. return {};
  208. #endif
  209. }
  210. Optional<StringView> get_calendar_day_period_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView calendar, [[maybe_unused]] CalendarPatternStyle style, [[maybe_unused]] Unicode::DayPeriod value)
  211. {
  212. #if ENABLE_UNICODE_DATA
  213. return Detail::get_calendar_day_period_symbol(locale, calendar, style, value);
  214. #else
  215. return {};
  216. #endif
  217. }
  218. Optional<StringView> get_time_zone_name([[maybe_unused]] StringView locale, [[maybe_unused]] StringView time_zone, [[maybe_unused]] CalendarPatternStyle style)
  219. {
  220. #if ENABLE_UNICODE_DATA
  221. return Detail::get_time_zone_name(locale, time_zone, style);
  222. #else
  223. return {};
  224. #endif
  225. }
  226. }