DateTimeFormat.cpp 8.0 KB

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