locale_settings/time.rs
1/*!
2Fetch locale-specific date and time formatting settings.
3
4This module provides the details for both time and date formatting
5as well as a set of calendar names used for day and month display.
6
7## Date and Time Formatting
8
9The date and time formatting strings use the field specifiers from
10the C [`strftime`](https://man.openbsd.org/strftime.3) function. These
11strings may also be used with the chrono crate's
12[`format::strftime`](https://docs.rs/chrono/0.4.7/chrono/format/strftime/index.html)
13module.
14*/
15
16use crate::ffi::utils::*;
17use crate::ffi::*;
18use crate::Category;
19use locale_types::{Locale, LocaleResult};
20
21// ------------------------------------------------------------------------------------------------
22// Public Types
23// ------------------------------------------------------------------------------------------------
24
25/// This structure captures a name and its abbreviated form.
26#[derive(Debug, Clone, PartialEq)]
27pub struct Name {
28 /// Full name
29 name: Option<String>,
30 /// Abbreviated name
31 abbreviated: Option<String>,
32}
33
34/// The set of all calendar names.
35#[derive(Debug, Clone, PartialEq)]
36pub struct CalendarNames {
37 /// Names of the days of the week (Sunday .. Saturday)
38 week_day_names: Vec<Name>,
39 /// Names of the months in a year (January .. December)
40 month_names: Vec<Name>,
41 /// The string for AM time
42 am_string: Option<String>,
43 /// The string for PM time
44 pm_string: Option<String>,
45}
46
47/// The complete date and time formatting information.
48#[derive(Debug, Clone, PartialEq)]
49pub struct DateTimeFormat {
50 /// The string to use to format a complete date and time.
51 date_time_format: Option<String>,
52 /// The string to use to format a date.
53 date_format: Option<String>,
54 /// The string to use to format a time, in 24 hours.
55 time_format: Option<String>,
56 /// The string to use to format a time, with am/pm.
57 time_ampm_format: Option<String>,
58 /// Alternate era name
59 era: Option<String>,
60 /// The string to use to format a complete date and time in the alternate era.
61 era_date_time_format: Option<String>,
62 /// The string to use to format a date in the alternate era.
63 era_date_format: Option<String>,
64 /// The string to use to format a time in the alternate era.
65 era_time_format: Option<String>,
66 /// The alternate symbols for digits.
67 alternate_digit_symbol: Option<String>,
68}
69
70// ------------------------------------------------------------------------------------------------
71// Public Functions
72// ------------------------------------------------------------------------------------------------
73
74/// Fetch calendar names for days and months.
75pub fn get_calendar_names() -> CalendarNames {
76 CalendarNames {
77 week_day_names: make_name_vector(7, DAY_1, ABDAY_1),
78 month_names: make_name_vector(12, MON_1, ABMON_1),
79 am_string: get_nl_string(AM_STR),
80 pm_string: get_nl_string(PM_STR),
81 }
82}
83
84/// Fetch the calendar names for a specified `Locale`.
85///
86/// # Arguments
87///
88/// * `locale` - The locale to query.
89/// * `inherit_current` - Whether the specified locale should inherit
90/// from the current locale.
91///
92/// If `inherit_current` is `false` the `locale` specified will be treated
93/// as an entirely new and complete locale when calling the C
94/// [`newlocale`](https://man.openbsd.org/newlocale.3) function. If it is
95/// `true` the `locale` is assumed to be a partially specified one and inherits
96/// any unspecified components from the current locale. For example, if the
97/// current locale is `en_US.UTF-8` and the parameters passed are `_NZ` and
98/// `true` then the resulting locale will be `en_NZ.UTF-8`.
99pub fn get_calendar_names_for_locale(
100 locale: Locale,
101 inherit_current: bool,
102) -> LocaleResult<CalendarNames> {
103 get_format_for_locale(Category::Time, locale, &get_calendar_names, inherit_current)
104}
105
106/// Fetch the date and time formatting settings for the current locale.
107pub fn get_date_time_format() -> DateTimeFormat {
108 DateTimeFormat {
109 date_time_format: get_nl_string(D_T_FMT),
110 date_format: get_nl_string(D_FMT),
111 time_format: get_nl_string(T_FMT),
112 time_ampm_format: get_nl_string(T_FMT_AMPM),
113 era: get_nl_string(ERA),
114 era_date_time_format: get_nl_string(ERA_D_T_FMT),
115 era_date_format: get_nl_string(ERA_D_FMT),
116 era_time_format: get_nl_string(ERA_T_FMT),
117 alternate_digit_symbol: get_nl_string(ALT_DIGITS),
118 }
119}
120
121/// Fetch the date and time formatting rules for a specified `Locale`.
122///
123/// # Arguments
124///
125/// * `locale` - The locale to query.
126/// * `inherit_current` - Whether the specified locale should inherit
127/// from the current locale.
128///
129/// If `inherit_current` is `false` the `locale` specified will be treated
130/// as an entirely new and complete locale when calling the C
131/// [`newlocale`](https://man.openbsd.org/newlocale.3) function. If it is
132/// `true` the `locale` is assumed to be a partially specified one and inherits
133/// any unspecified components from the current locale. For example, if the
134/// current locale is `en_US.UTF-8` and the parameters passed are `_NZ` and
135/// `true` then the resulting locale will be `en_NZ.UTF-8`.
136pub fn get_date_time_format_for_locale(
137 locale: Locale,
138 inherit_current: bool,
139) -> LocaleResult<DateTimeFormat> {
140 get_format_for_locale(
141 Category::Time,
142 locale,
143 &get_date_time_format,
144 inherit_current,
145 )
146}
147
148// ------------------------------------------------------------------------------------------------
149// Private Functions
150// ------------------------------------------------------------------------------------------------
151
152fn make_name_vector(count: u32, n_st: u32, ab_st: u32) -> Vec<Name> {
153 (0..count)
154 .map(|offset| Name {
155 name: get_nl_string(n_st + offset),
156 abbreviated: get_nl_string(ab_st + offset),
157 })
158 .collect()
159}
160
161// ------------------------------------------------------------------------------------------------
162// Unit Tests
163// ------------------------------------------------------------------------------------------------
164
165#[cfg(test)]
166mod tests {
167 use super::{get_calendar_names, get_date_time_format};
168 use crate::locale::{set_locale, Category};
169 use crate::time::Name;
170 use locale_types::Locale;
171
172 // --------------------------------------------------------------------------------------------
173 #[test]
174 fn test_week_day_names() {
175 if set_locale(&Locale::POSIX, &Category::Time) {
176 let names = get_calendar_names();
177 assert_eq!(names.week_day_names.len(), 7);
178 let sunday = names.week_day_names.get(0).unwrap();
179 assert_eq!(
180 sunday,
181 &Name {
182 name: Some("Sunday".to_string()),
183 abbreviated: Some("Sun".to_string())
184 }
185 );
186 } else {
187 panic!("set_locale returned false");
188 }
189 }
190
191 #[test]
192 fn test_month_names() {
193 if set_locale(&Locale::POSIX, &Category::Time) {
194 let names = get_calendar_names();
195 assert_eq!(names.month_names.len(), 12);
196 let january = names.month_names.get(0).unwrap();
197 assert_eq!(
198 january,
199 &Name {
200 name: Some("January".to_string()),
201 abbreviated: Some("Jan".to_string())
202 }
203 );
204 } else {
205 panic!("set_locale returned false");
206 }
207 }
208
209 #[test]
210 fn test_ampm_names() {
211 if set_locale(&Locale::POSIX, &Category::Time) {
212 let names = get_calendar_names();
213 assert_eq!(names.am_string, Some("AM".to_string()));
214 assert_eq!(names.pm_string, Some("PM".to_string()));
215 } else {
216 panic!("set_locale returned false");
217 }
218 }
219
220 // --------------------------------------------------------------------------------------------
221 #[test]
222 fn test_date_time_formats() {
223 if set_locale(&Locale::POSIX, &Category::Time) {
224 let formats = get_date_time_format();
225 println!("{:#?}", formats);
226 assert_eq!(formats.date_format, Some("%m/%d/%y".to_string()));
227 assert_eq!(formats.era, None);
228 } else {
229 panic!("set_locale returned false");
230 }
231 }
232}