1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3// Copyright (c) 2022-2023 Alexander Grund
4//
5// Distributed under the Boost Software License, Version 1.0.
6// https://www.boost.org/LICENSE_1_0.txt
7
8#ifndef BOOST_LOCALE_FORMATTING_HPP_INCLUDED
9#define BOOST_LOCALE_FORMATTING_HPP_INCLUDED
10
11#include <boost/locale/detail/any_string.hpp>
12#include <boost/locale/time_zone.hpp>
13#include <cstdint>
14#include <cstring>
15#include <istream>
16#include <ostream>
17#include <string>
18
19#ifdef BOOST_MSVC
20# pragma warning(push)
21# pragma warning(disable : 4275 4251 4231 4660)
22#endif
23
24namespace boost { namespace locale {
25
26 /// \brief This namespace holds additional formatting
27 /// flags that can be set using ios_info.
28 namespace flags {
29
30 /// Formatting flags, each one of them has corresponding manipulation
31 /// in namespace \a as
32 enum display_flags_type {
33 posix = 0,
34 number = 1,
35 currency = 2,
36 percent = 3,
37 date = 4,
38 time = 5,
39 datetime = 6,
40 strftime = 7,
41 spellout = 8,
42 ordinal = 9,
43
44 display_flags_mask = 31,
45
46 currency_default = 0 << 5,
47 currency_iso = 1 << 5,
48 currency_national = 2 << 5,
49
50 currency_flags_mask = 3 << 5,
51
52 time_default = 0 << 7,
53 time_short = 1 << 7,
54 time_medium = 2 << 7,
55 time_long = 3 << 7,
56 time_full = 4 << 7,
57 time_flags_mask = 7 << 7,
58
59 date_default = 0 << 10,
60 date_short = 1 << 10,
61 date_medium = 2 << 10,
62 date_long = 3 << 10,
63 date_full = 4 << 10,
64 date_flags_mask = 7 << 10,
65 };
66
67 /// Special string patterns that can be used for text formatting
68 enum pattern_type {
69 datetime_pattern, ///< strftime like formatting
70 time_zone_id ///< time zone name
71 };
72
73 /// Special integer values that can be used for formatting
74 enum value_type {
75 domain_id ///< Domain code - for message formatting
76 };
77
78 } // namespace flags
79
80 /// \brief This class holds external data beyond existing fmtflags that std::ios_base holds
81 ///
82 /// You should almost never create this object directly. Instead, you should access it via
83 /// ios_info::get(stream_object) static member function. It automatically creates default formatting data for that
84 /// stream
85 class BOOST_LOCALE_DECL ios_info {
86 public:
87 /// \cond INTERNAL
88 ios_info();
89 ios_info(const ios_info&);
90 ios_info& operator=(const ios_info&);
91 ~ios_info();
92 /// \endcond
93
94 /// Get ios_info instance for specific stream object
95 static ios_info& get(std::ios_base& ios);
96
97 /// Set flags that define how to format data, e.g. number, spell, currency etc.
98 void display_flags(uint64_t flags);
99 /// Get flags that define how to format data, e.g. number, spell, currency etc.
100 uint64_t display_flags() const;
101
102 /// Set flags that define how to format currency
103 void currency_flags(uint64_t flags);
104 /// Get flags that define how to format currency
105 uint64_t currency_flags() const;
106
107 /// Set flags that define how to format date
108 void date_flags(uint64_t flags);
109 /// Get flags that define how to format date
110 uint64_t date_flags() const;
111
112 /// Set flags that define how to format time
113 void time_flags(uint64_t flags);
114 /// Get flags that define how to format time
115 uint64_t time_flags() const;
116
117 /// Set special message domain identification
118 void domain_id(int);
119 /// Get special message domain identification
120 int domain_id() const;
121
122 /// Set time zone for formatting dates and time
123 void time_zone(const std::string&);
124 /// Get time zone for formatting dates and time
125 std::string time_zone() const;
126
127 /// Set date/time pattern (strftime like)
128 template<typename CharType>
129 void date_time_pattern(const std::basic_string<CharType>& str)
130 {
131 datetime_.set<CharType>(str);
132 }
133 /// Get date/time pattern (strftime like)
134 template<typename CharType>
135 std::basic_string<CharType> date_time_pattern() const
136 {
137 return datetime_.get<CharType>();
138 }
139
140 /// \cond INTERNAL
141 void on_imbue();
142 /// \endcond
143
144 private:
145 uint64_t flags_;
146 int domain_id_;
147 std::string time_zone_;
148 detail::any_string datetime_;
149 };
150
151 /// \brief This namespace includes all manipulators that can be used on IO streams
152 namespace as {
153 /// \defgroup manipulators I/O Stream manipulators
154 ///
155 /// @{
156
157 /// Format values with "POSIX" or "C" locale. Note, if locale was created with additional non-classic locale
158 /// then These numbers may be localized
159 inline std::ios_base& posix(std::ios_base& ios)
160 {
161 ios_info::get(ios).display_flags(flags: flags::posix);
162 return ios;
163 }
164
165 /// Format a number. Note, unlike standard number formatting, integers would be treated like real numbers when
166 /// std::fixed or std::scientific manipulators were applied
167 inline std::ios_base& number(std::ios_base& ios)
168 {
169 ios_info::get(ios).display_flags(flags: flags::number);
170 return ios;
171 }
172
173 /// Format currency, number is treated like amount of money
174 inline std::ios_base& currency(std::ios_base& ios)
175 {
176 ios_info::get(ios).display_flags(flags: flags::currency);
177 return ios;
178 }
179
180 /// Format percent, value 0.3 is treated as 30%.
181 inline std::ios_base& percent(std::ios_base& ios)
182 {
183 ios_info::get(ios).display_flags(flags: flags::percent);
184 return ios;
185 }
186
187 /// Format a date, number is treated as POSIX time
188 inline std::ios_base& date(std::ios_base& ios)
189 {
190 ios_info::get(ios).display_flags(flags: flags::date);
191 return ios;
192 }
193
194 /// Format a time, number is treated as POSIX time
195 inline std::ios_base& time(std::ios_base& ios)
196 {
197 ios_info::get(ios).display_flags(flags: flags::time);
198 return ios;
199 }
200
201 /// Format a date and time, number is treated as POSIX time
202 inline std::ios_base& datetime(std::ios_base& ios)
203 {
204 ios_info::get(ios).display_flags(flags: flags::datetime);
205 return ios;
206 }
207
208 /// Create formatted date time, Please note, this manipulator only changes formatting mode,
209 /// and not format itself, so you are probably looking for ftime manipulator
210 inline std::ios_base& strftime(std::ios_base& ios)
211 {
212 ios_info::get(ios).display_flags(flags: flags::strftime);
213 return ios;
214 }
215
216 /// Spell the number, like "one hundred and ten"
217 inline std::ios_base& spellout(std::ios_base& ios)
218 {
219 ios_info::get(ios).display_flags(flags: flags::spellout);
220 return ios;
221 }
222
223 /// Write an order of the number like 4th.
224 inline std::ios_base& ordinal(std::ios_base& ios)
225 {
226 ios_info::get(ios).display_flags(flags: flags::ordinal);
227 return ios;
228 }
229
230 /// Set default currency formatting style -- national, like "$"
231 inline std::ios_base& currency_default(std::ios_base& ios)
232 {
233 ios_info::get(ios).currency_flags(flags: flags::currency_default);
234 return ios;
235 }
236
237 /// Set ISO currency formatting style, like "USD", (requires ICU >= 4.2)
238 inline std::ios_base& currency_iso(std::ios_base& ios)
239 {
240 ios_info::get(ios).currency_flags(flags: flags::currency_iso);
241 return ios;
242 }
243
244 /// Set national currency formatting style, like "$"
245 inline std::ios_base& currency_national(std::ios_base& ios)
246 {
247 ios_info::get(ios).currency_flags(flags: flags::currency_national);
248 return ios;
249 }
250
251 /// set default (medium) time formatting style
252 inline std::ios_base& time_default(std::ios_base& ios)
253 {
254 ios_info::get(ios).time_flags(flags: flags::time_default);
255 return ios;
256 }
257
258 /// set short time formatting style
259 inline std::ios_base& time_short(std::ios_base& ios)
260 {
261 ios_info::get(ios).time_flags(flags: flags::time_short);
262 return ios;
263 }
264
265 /// set medium time formatting style
266 inline std::ios_base& time_medium(std::ios_base& ios)
267 {
268 ios_info::get(ios).time_flags(flags: flags::time_medium);
269 return ios;
270 }
271
272 /// set long time formatting style
273 inline std::ios_base& time_long(std::ios_base& ios)
274 {
275 ios_info::get(ios).time_flags(flags: flags::time_long);
276 return ios;
277 }
278
279 /// set full time formatting style
280 inline std::ios_base& time_full(std::ios_base& ios)
281 {
282 ios_info::get(ios).time_flags(flags: flags::time_full);
283 return ios;
284 }
285
286 /// set default (medium) date formatting style
287 inline std::ios_base& date_default(std::ios_base& ios)
288 {
289 ios_info::get(ios).date_flags(flags: flags::date_default);
290 return ios;
291 }
292
293 /// set short date formatting style
294 inline std::ios_base& date_short(std::ios_base& ios)
295 {
296 ios_info::get(ios).date_flags(flags: flags::date_short);
297 return ios;
298 }
299
300 /// set medium date formatting style
301 inline std::ios_base& date_medium(std::ios_base& ios)
302 {
303 ios_info::get(ios).date_flags(flags: flags::date_medium);
304 return ios;
305 }
306
307 /// set long date formatting style
308 inline std::ios_base& date_long(std::ios_base& ios)
309 {
310 ios_info::get(ios).date_flags(flags: flags::date_long);
311 return ios;
312 }
313
314 /// set full date formatting style
315 inline std::ios_base& date_full(std::ios_base& ios)
316 {
317 ios_info::get(ios).date_flags(flags: flags::date_full);
318 return ios;
319 }
320
321 /// \cond INTERNAL
322 namespace detail {
323 inline bool is_datetime_display_flags(const uint64_t display_flags)
324 {
325 return (display_flags == flags::date || display_flags == flags::time || display_flags == flags::datetime
326 || display_flags == flags::strftime);
327 }
328
329 template<typename CharType>
330 struct add_ftime {
331 std::basic_string<CharType> ftime;
332
333 void apply(std::basic_ios<CharType>& ios) const
334 {
335 ios_info::get(ios).date_time_pattern(ftime);
336 as::strftime(ios);
337 }
338 };
339
340 template<typename CharType>
341 std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const add_ftime<CharType>& fmt)
342 {
343 fmt.apply(out);
344 return out;
345 }
346
347 template<typename CharType>
348 std::basic_istream<CharType>& operator>>(std::basic_istream<CharType>& in, const add_ftime<CharType>& fmt)
349 {
350 fmt.apply(in);
351 return in;
352 }
353
354 } // namespace detail
355 /// \endcond
356
357 /// Set strftime like formatting string
358 ///
359 /// Please note, formatting flags are very similar but not exactly the same as flags for C function strftime.
360 /// Differences: some flags as "%e" do not add blanks to fill text up to two spaces, not all flags supported.
361 ///
362 /// Flags:
363 /// - "%a" -- Abbreviated weekday (Sun.)
364 /// - "%A" -- Full weekday (Sunday)
365 /// - "%b" -- Abbreviated month (Jan.)
366 /// - "%B" -- Full month (January)
367 /// - "%c" -- Locale date-time format. **Note:** prefer using "as::datetime"
368 /// - "%d" -- Day of Month [01,31]
369 /// - "%e" -- Day of Month [1,31]
370 /// - "%h" -- Same as "%b"
371 /// - "%H" -- 24 clock hour [00,23]
372 /// - "%I" -- 12 clock hour [01,12]
373 /// - "%j" -- Day of year [1,366]
374 /// - "%m" -- Month [01,12]
375 /// - "%M" -- Minute [00,59]
376 /// - "%n" -- New Line
377 /// - "%p" -- AM/PM in locale representation
378 /// - "%r" -- Time with AM/PM, same as "%I:%M:%S %p"
379 /// - "%R" -- Same as "%H:%M"
380 /// - "%S" -- Second [00,61]
381 /// - "%t" -- Tab character
382 /// - "%T" -- Same as "%H:%M:%S"
383 /// - "%x" -- Local date representation. **Note:** prefer using "as::date"
384 /// - "%X" -- Local time representation. **Note:** prefer using "as::time"
385 /// - "%y" -- Year [00,99]
386 /// - "%Y" -- 4 digits year. (2009)
387 /// - "%Z" -- Time Zone
388 /// - "%%" -- Percent symbol
389 ///
390
391 template<typename CharType>
392#ifdef BOOST_LOCALE_DOXYGEN
393 unspecified_type
394#else
395 detail::add_ftime<CharType>
396#endif
397 ftime(const std::basic_string<CharType>& format)
398 {
399 detail::add_ftime<CharType> fmt;
400 fmt.ftime = format;
401 return fmt;
402 }
403
404 /// See ftime(std::basic_string<CharType> const &format)
405 template<typename CharType>
406#ifdef BOOST_LOCALE_DOXYGEN
407 unspecified_type
408#else
409 detail::add_ftime<CharType>
410#endif
411 ftime(const CharType* format)
412 {
413 detail::add_ftime<CharType> fmt;
414 fmt.ftime = format;
415 return fmt;
416 }
417
418 /// \cond INTERNAL
419 namespace detail {
420 struct set_timezone {
421 std::string id;
422 };
423 template<typename CharType>
424 std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const set_timezone& fmt)
425 {
426 ios_info::get(ios&: out).time_zone(fmt.id);
427 return out;
428 }
429
430 template<typename CharType>
431 std::basic_istream<CharType>& operator>>(std::basic_istream<CharType>& in, const set_timezone& fmt)
432 {
433 ios_info::get(ios&: in).time_zone(fmt.id);
434 return in;
435 }
436 } // namespace detail
437 /// \endcond
438
439 /// Set GMT time zone to stream
440 inline std::ios_base& gmt(std::ios_base& ios)
441 {
442 ios_info::get(ios).time_zone("GMT");
443 return ios;
444 }
445
446 /// Set local time zone to stream
447 inline std::ios_base& local_time(std::ios_base& ios)
448 {
449 ios_info::get(ios).time_zone(time_zone::global());
450 return ios;
451 }
452
453 /// Set time zone using \a id
454 inline
455#ifdef BOOST_LOCALE_DOXYGEN
456 unspecified_type
457#else
458 detail::set_timezone
459#endif
460 time_zone(const char* id)
461 {
462 detail::set_timezone tz;
463 tz.id = id;
464 return tz;
465 }
466
467 /// Set time zone using \a id
468 inline
469#ifdef BOOST_LOCALE_DOXYGEN
470 unspecified_type
471#else
472 detail::set_timezone
473#endif
474 time_zone(const std::string& id)
475 {
476 detail::set_timezone tz;
477 tz.id = id;
478 return tz;
479 }
480
481 /// @}
482
483 } // namespace as
484
485}} // namespace boost::locale
486
487#ifdef BOOST_MSVC
488# pragma warning(pop)
489#endif
490
491#endif
492

source code of boost/libs/locale/include/boost/locale/formatting.hpp