BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlt_timeformatter.h
Go to the documentation of this file.
1/// @file bdlt_timeformatter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_timeformatter.h -*-C++-*-
8#ifndef INCLUDED_BDLT_TIMEFORMATTER
9#define INCLUDED_BDLT_TIMEFORMATTER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_timeformatter bdlt_timeformatter
15/// @brief Provide `bsl::formatter` specialization for `bdlt::Time`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_timeformatter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_timeformatter-purpose"> Purpose</a>
25/// * <a href="#bdlt_timeformatter-classes"> Classes </a>
26/// * <a href="#bdlt_timeformatter-description"> Description </a>
27///
28/// # Purpose {#bdlt_timeformatter-purpose}
29/// Provide `bsl::formatter` specialization for `bdlt::Time`.
30///
31/// # Classes {#bdlt_timeformatter-classes}
32///
33/// - bdlt::TimeFormatter: time formatter for `bslfmt` framework
34/// - bsl::formatter<bdlt::Time, t_CHAR>: specialization
35///
36/// @see bdlt_time, bslfmt_formatter
37///
38/// # Description {#bdlt_timeformatter-description}
39/// This component provides `bdlt::TimeFormatter` and a
40/// specialization of `bsl::formatter` that allow `bsl::format` to output
41/// values of `bdlt::Time`.
42///
43/// The formatter interprets the following modifiers:
44/// - ',' (comma) - the decimal point when displaying seconds is shown as a
45/// comma rather than a period.
46///
47/// The formatter supports various time format specifiers including:
48/// - Hour: 'H' (2 digit) "00" - "24"
49/// - Hour: 'I' (2 digit) "01" - "12"
50/// - AM/PM: 'p' - "AM" or "PM"
51/// - Minute: 'M' (2 digits) "00" - "59"
52/// - Second: 'S' (2 digits) "00" - "59"
53/// - Composite: "{}" or 'T' (time in default format), or 'i' (time in ISO 8601
54/// format)
55/// @}
56/** @} */
57/** @} */
58
59/** @addtogroup bdl
60 * @{
61 */
62/** @addtogroup bdlt
63 * @{
64 */
65/** @addtogroup bdlt_timeformatter
66 * @{
67 */
68
69#include <bdlscm_version.h>
70
71#include <bdlt_formatter.h>
72#include <bdlt_formatutil.h>
73#include <bdlt_time.h>
74
76
77#include <bsl_iosfwd.h>
78#include <bsl_optional.h>
79#include <bsl_string_view.h>
80
81
82namespace bdlt {
83
84class TimeFormatter_Cache;
85
86 // ===================
87 // class TimeFormatter
88 // ===================
89
90/// This `class` provides a specifier formatter for printing `Time` objects.
91///
92/// See @ref bdlt_timeformatter
93template <class t_CHAR>
95 private:
96 // PRIVATE TYPES
97 typedef FormatUtil<t_CHAR> Util;
100
101 enum {
102 k_HOUR_WIDTH = 2,
103 k_AMPM_WIDTH = 2,
104 k_MINUTE_WIDTH = 2,
105 k_SECOND_WIDTH = 2,
106 k_COLON_WIDTH = 1,
107 k_DEFAULT_PRECISION = 6,
108 k_DEFAULT_ISO8601_PRECISION = 3
109 };
110
111 // DATA
112 int d_fixedWidth;
113
114 unsigned d_numDefaultSecondSpecifiers;
115 unsigned d_numIso8601SecondSpecifiers;
116 // Number of explicit or implicit seconds specifiers in the format
117 // string, for default-style or iso8601-style seconds.
118
119 bsl::optional<int> d_precision;
120
121 bool d_comma;
122
123 // PRIVATE CLASS METHODS
124
125 /// Write the two-digit, zero-padded hours from the specified `value` to
126 /// the specified `out` and return `out`.
127 template <class t_ITERATOR>
128 static t_ITERATOR formatHours(t_ITERATOR out, const FormatCache& value);
129
130 /// Write the two-digit, zero-padded minutes from the specified `value` to
131 /// the specified `out` and return `out`.
132 template <class t_ITERATOR>
133 static t_ITERATOR formatMinutes(t_ITERATOR out, const FormatCache& value);
134
135 // PRIVATE ACCESSORS
136
137 /// Write the two-digit, zero-padded integral seconds from the specified
138 /// `value` to the specified `out`, the write the decimal as either a
139 /// period or comma, then the fraction of a second to the specified
140 /// `precision` decimal places, then return `out`.
141 template <class t_ITERATOR>
142 t_ITERATOR formatSeconds(t_ITERATOR out,
143 int precision,
144 const FormatCache& value) const;
145
146 /// Format the time from the specified `value` to `out` with the specified
147 /// `precision` decimal points representing the fraction of a second, then
148 /// return `out`.
149 template <class t_ITERATOR>
150 t_ITERATOR formatTime(t_ITERATOR out,
151 int precision,
152 const FormatCache& value) const;
153
154 /// Return the precision to be used when default formatting a time. If a
155 /// precision has been specified, return that, otherwise return 6.
156 int precision() const;
157
158 /// Return the precision to be used when Iso8601 formatting a time. If a
159 /// precision has been specified, return that, otherwise return 3.
160 int iso8601Precision() const;
161
162 public:
163 // CREATORS
164
165 /// Create an object in its default initial state.
168
169 // MANIPULATORS
170
171 /// Parse a time that will be formatted in default mode.
173
174 /// Parse a time that will be formatted in Iso8601 mode.
176
177 /// Examine the first character of the specified `*specInOut` and if it is
178 /// recognized as a modifier by this object, update this object's state to
179 /// reflect it and pop it off the front of `*specInOut` and return `true`,
180 /// and if not, return `false` with no modification to `*specInOut`.
182
183 /// If the first character of the specified `*specInOut` is recognized by
184 /// this specifier formatter, parse it, remove it from `*specInOut`, and
185 /// return `true`, otherwise return `false` with no modification to `*specInOut`.
186 ///
187 /// \pre The behavior is undefined if `*specInOut` is empty.
189 bool parseNextSpecifier(StringView *specInOut);
190
191 /// Read post-processed fields from the specified `spec` that are relevant
192 /// to this specifier formatter.
194
195 // ACCESSORS
196
197 /// Return the `bslfmt::FormatSpecificationParser::Sections` flags that
198 /// apply to this value type.
200
201 /// If the first character of the specified `*specInOut` is recognized by
202 /// this specifier formatter, use it to format the specified `value` to
203 /// `*outIt`, remove the character from `*specInOut`, and return `true`,
204 /// otherwise return `false` with no modification to `*specInOut`.
205 template <class t_ITERATOR>
206 bool formatNextSpecifier(StringView *specInOut,
207 t_ITERATOR *outIt,
208 const FormatCache& value) const;
209
210 /// Format the specified `value` to the specified `out` using the default
211 /// format and return `out`.
212 template <class t_ITERATOR>
213 t_ITERATOR formatDefault(t_ITERATOR out, const FormatCache& value) const;
214
215 /// Format the specified `value` to the specified `out` using the Iso8601
216 /// format and return `out`.
217 template <class t_ITERATOR>
218 t_ITERATOR formatIso8601(t_ITERATOR out, const FormatCache& value) const;
219
220 /// Return the anticipated width of output given all the `parse*` calls
221 /// that have been happened thus far and the specified `value`.
222 int totalWidth(const FormatCache& value) const;
223};
224
225 // =========================
226 // class TimeFormatter_Cache
227 // =========================
228
229/// This `class` facilitates faster access to a `Time` object during printing
230/// by batching access to several fields in a single call during construction
231/// and caching them for quick access later.
232///
233/// See @ref bdlt_timeformatter
235 // DATA
236 int d_hour;
237 int d_minute;
238 int d_second;
239 int d_millisecond;
240 int d_microsecond;
241
242 public:
243 // CREATORS
244
245 /// Populate all the data members of this `class` with a call to `getTime`
246 /// on the specified `value`.
247 explicit TimeFormatter_Cache(const Time& value);
248
249 // ACCESSORS
250
251 /// Return the cached `hour` field.
252 int hour() const;
253
254 /// Return the cached `minute` field.
255 int minute() const;
256
257 /// Return the cached `second` field.
258 int second() const;
259
260 /// Return the cached `millisecone` field.
261 int millisecond() const;
262
263 /// Return the cached `microsecond` field.
264 int microsecond() const;
265};
266
267// ============================================================================
268// INLINE FUNCTION DEFINITIONS
269// ============================================================================
270
271 // -------------------
272 // class TimeFormatter
273 // -------------------
274
275// PRIVATE CLASS METHODSS
276template <class t_CHAR>
277template <class t_ITERATOR>
278inline
280 t_ITERATOR out, const FormatCache& value)
281{
282 return Util::writeZeroPaddedDigits(out, value.hour(), k_HOUR_WIDTH);
283}
284
285template <class t_CHAR>
286template <class t_ITERATOR>
287inline
288t_ITERATOR TimeFormatter<t_CHAR>::formatMinutes(
289 t_ITERATOR out, const FormatCache& value)
290{
291 return Util::writeZeroPaddedDigits(out, value.minute(), k_MINUTE_WIDTH);
292}
293
294// PRIVATE ACCESSORS
295
296template <class t_CHAR>
297template <class t_ITERATOR>
298inline
299t_ITERATOR TimeFormatter<t_CHAR>::formatSeconds(
300 t_ITERATOR out, int precision, const FormatCache& value) const
301{
302 out = Util::writeZeroPaddedDigits(out, value.second(), k_SECOND_WIDTH);
303 out = Util::writeSecondFraction(out,
304 precision,
305 d_comma ? ',' : '.',
306 value.millisecond(),
307 value.microsecond());
308 return out;
309}
310
311template <class t_CHAR>
312template <class t_ITERATOR>
313inline
314t_ITERATOR TimeFormatter<t_CHAR>::formatTime(t_ITERATOR out,
315 int precision,
316 const FormatCache& value) const
317{
318 out = formatHours(out, value);
319 *out++ = t_CHAR(':');
320 out = formatMinutes(out, value);
321 *out++ = t_CHAR(':');
322 out = formatSeconds(out, precision, value);
323
324 return out;
325}
326
327template <class t_CHAR>
328inline
329int TimeFormatter<t_CHAR>::precision() const
330{
331 return d_precision.value_or(6);
332}
333
334template <class t_CHAR>
335inline
336int TimeFormatter<t_CHAR>::iso8601Precision() const
337{
338 return d_precision.value_or(3);
339}
340
341// CREATORS
342template <class t_CHAR>
345: d_fixedWidth(0)
346, d_numDefaultSecondSpecifiers(0)
347, d_numIso8601SecondSpecifiers(0)
348, d_precision()
349, d_comma(false)
350{}
351
352// MANIPULATORS
353template <class t_CHAR>
356{
357 ++d_numDefaultSecondSpecifiers;
358 d_fixedWidth += k_HOUR_WIDTH + k_COLON_WIDTH + k_MINUTE_WIDTH +
359 k_COLON_WIDTH + k_SECOND_WIDTH;
360}
361
362template <class t_CHAR>
365{
366 ++d_numIso8601SecondSpecifiers;
367 d_fixedWidth += k_HOUR_WIDTH + k_COLON_WIDTH + k_MINUTE_WIDTH +
368 k_COLON_WIDTH + k_SECOND_WIDTH;
369}
370
371template <class t_CHAR>
374{
375 if (t_CHAR(',') == specInOut->front()) {
376 d_comma = true;
377 specInOut->remove_prefix(1);
378 return true; // RETURN
379 }
380
381 return false;
382}
383
384template <class t_CHAR>
387{
388 BSLS_ASSERT(!specInOut->empty());
389
390 switch(static_cast<char>(specInOut->front())) {
391 case 'H':
392 case 'I': {
393 d_fixedWidth += k_HOUR_WIDTH;
394 } break;
395 case 'p': {
396 d_fixedWidth += k_AMPM_WIDTH;
397 } break;
398 case 'M': {
399 d_fixedWidth += k_MINUTE_WIDTH;
400 } break;
401 case 'S': {
402 d_fixedWidth += k_SECOND_WIDTH;
403 ++d_numDefaultSecondSpecifiers;
404 } break;
405 case 'R': {
406 d_fixedWidth += k_HOUR_WIDTH + k_COLON_WIDTH + k_MINUTE_WIDTH;
407 } break;
408 case 'T': {
409 parseDefault();
410 } break;
411 case 'i': {
412 parseIso8601();
413 } break;
414 default: {
415 return false; // RETURN
416 } break;
417 }
418
419 specInOut->remove_prefix(1);
420 return true;
421}
422
423template <class t_CHAR>
424inline
433
434// ACCESSORS
435template <class t_CHAR>
441
442template <class t_CHAR>
443template <class t_ITERATOR>
444inline
446 StringView *specInOut,
447 t_ITERATOR *outIt,
448 const FormatCache& value) const
449{
450 BSLS_ASSERT_SAFE(!specInOut->empty());
451
452 StringView spec = *specInOut;
453
454 switch (static_cast<char>(spec.front())) {
455 case 'H': {
456 *outIt = formatHours(*outIt, value);
457 } break;
458 case 'I': {
459 // hour - 01 - 12
460
461 int hh = value.hour();
462 hh %= 12; // time is '00'-'11'
463 if (00 == hh) {
464 hh = 12;
465 }
466 *outIt = Util::writeZeroPaddedDigits(*outIt, hh);
467 } break;
468 case 'p': {
469 bsl::string_view ampm = value.hour() < 12 ? "AM" : "PM";
471 ampm.data(),
472 ampm.data() + ampm.length(),
473 *outIt);
474 } break;
475 case 'M': {
476 *outIt = formatMinutes(*outIt, value);
477 } break;
478 case 'S': {
479 *outIt = formatSeconds(*outIt, precision(), value);
480 } break;
481 case 'T': {
482 *outIt = formatDefault(*outIt, value);
483 } break;
484 case 'i': {
485 *outIt = formatIso8601(*outIt, value);
486 } break;
487 default: {
488 return false; // RETURN
489 } break;
490 }
491
492 *specInOut = spec.substr(1);
493
494 return true;
495}
496
497template <class t_CHAR>
498template <class t_ITERATOR>
499inline
501 t_ITERATOR out, const FormatCache& value) const
502{
503 return formatTime(out, precision(), value);
504}
505
506template <class t_CHAR>
507template <class t_ITERATOR>
508inline
510 t_ITERATOR out, const FormatCache& value) const
511{
512 return formatTime(out, iso8601Precision(), value);
513}
514
515template <class t_CHAR>
516inline
518{
519 int ret = d_fixedWidth;
520
521 if (d_precision) {
522 if (0 < *d_precision) {
523 ret += (*d_precision + 1) * (d_numDefaultSecondSpecifiers +
524 d_numIso8601SecondSpecifiers);
525 }
526 }
527 else {
528 ret += (k_DEFAULT_PRECISION + 1) * d_numDefaultSecondSpecifiers;
529 ret += (k_DEFAULT_ISO8601_PRECISION+1) * d_numIso8601SecondSpecifiers;
530 }
531
532 return ret;
533}
534
535 // -------------------------
536 // class TimeFormatter_Cache
537 // -------------------------
538
539// CREATORS
540inline
542{
543 value.getTime(&d_hour,
544 &d_minute,
545 &d_second,
546 &d_millisecond,
547 &d_microsecond);
548}
549
550// ACCESSORS
551inline
553{
554 return d_hour;
555}
556
557inline
559{
560 return d_minute;
561}
562
563inline
565{
566 return d_second;
567}
568
569inline
571{
572 return d_millisecond;
573}
574
575inline
577{
578 return d_microsecond;
579}
580
581} // close package namespace
582
583
584namespace bsl {
585
586/// This type implements the formatter logic specific for `Time` objects.
587template <class t_CHAR>
588class formatter<BloombergLP::bdlt::Time, t_CHAR> {
589 // PRIVATE TYPES
590 typedef BloombergLP::bdlt::Time Time;
591 typedef BloombergLP::bdlt::TimeFormatter_Cache FormatCache;
592 typedef BloombergLP::bdlt::Formatter<
593 BloombergLP::bdlt::TimeFormatter, t_CHAR> Formatter;
594
595 // DATA
596 Formatter d_formatter;
597
598 public:
599 /// Parse and validate the specification string stored in the specified
600 /// `parseContext`. Return an end iterator of the parsed range. Throw
601 /// `bsl::format_error`, in the event of failure.
602 template <class t_PARSE_CONTEXT>
603 BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator parse(
604 t_PARSE_CONTEXT& context)
605 {
606 return d_formatter.parse(context);
607 }
608
609 /// Format the value in the specified `value` parameter according to the
610 /// specification stored as a result of a previous call to the `parse`
611 /// method, and write the result to the iterator accessed by calling the
612 /// `out()` method on the specified `formatContext` parameter. Return an
613 /// end iterator of the output range.
614 template <class t_FORMAT_CONTEXT>
615 typename t_FORMAT_CONTEXT::iterator format(
616 const Time& value,
617 t_FORMAT_CONTEXT& formatContext) const
618 {
619 return d_formatter.format(FormatCache(value), formatContext);
620 }
621};
622
623} // close bsl namespace
624
625#endif
626
627// ----------------------------------------------------------------------------
628// Copyright 2026 Bloomberg Finance L.P.
629//
630// Licensed under the Apache License, Version 2.0 (the "License");
631// you may not use this file except in compliance with the License.
632// You may obtain a copy of the License at
633//
634// http://www.apache.org/licenses/LICENSE-2.0
635//
636// Unless required by applicable law or agreed to in writing, software
637// distributed under the License is distributed on an "AS IS" BASIS,
638// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
639// See the License for the specific language governing permissions and
640// limitations under the License.
641// ----------------------------- END-OF-FILE ----------------------------------
642
643/** @} */
644/** @} */
645/** @} */
Definition bdlt_formatutil.h:87
Definition bdlt_timeformatter.h:234
int second() const
Return the cached second field.
Definition bdlt_timeformatter.h:564
int minute() const
Return the cached minute field.
Definition bdlt_timeformatter.h:558
int hour() const
Return the cached hour field.
Definition bdlt_timeformatter.h:552
int microsecond() const
Return the cached microsecond field.
Definition bdlt_timeformatter.h:576
TimeFormatter_Cache(const Time &value)
Definition bdlt_timeformatter.h:541
int millisecond() const
Return the cached millisecone field.
Definition bdlt_timeformatter.h:570
Definition bdlt_timeformatter.h:94
BSLS_KEYWORD_CONSTEXPR_CPP20 void parseDefault()
Parse a time that will be formatted in default mode.
Definition bdlt_timeformatter.h:355
BSLS_KEYWORD_CONSTEXPR_CPP20 bool parseNextModifier(StringView *specInOut)
Definition bdlt_timeformatter.h:373
t_ITERATOR formatDefault(t_ITERATOR out, const FormatCache &value) const
Definition bdlt_timeformatter.h:500
BSLS_KEYWORD_CONSTEXPR_CPP20 TimeFormatter()
Create an object in its default initial state.
Definition bdlt_timeformatter.h:344
t_ITERATOR formatIso8601(t_ITERATOR out, const FormatCache &value) const
Definition bdlt_timeformatter.h:509
BSLS_KEYWORD_CONSTEXPR_CPP20 int extraSections() const
Definition bdlt_timeformatter.h:437
BSLS_KEYWORD_CONSTEXPR_CPP20 bool parseNextSpecifier(StringView *specInOut)
Definition bdlt_timeformatter.h:386
BSLS_KEYWORD_CONSTEXPR_CPP20 void parseIso8601()
Parse a time that will be formatted in Iso8601 mode.
Definition bdlt_timeformatter.h:364
void postprocess(const bslfmt::FormatSpecificationParser< t_CHAR > &spec)
Definition bdlt_timeformatter.h:425
bool formatNextSpecifier(StringView *specInOut, t_ITERATOR *outIt, const FormatCache &value) const
Definition bdlt_timeformatter.h:445
int totalWidth(const FormatCache &value) const
Definition bdlt_timeformatter.h:517
Definition bdlt_time.h:195
void getTime(int *hour, int *minute=0, int *second=0, int *millisecond=0, int *microsecond=0) const
Definition bslstl_stringview.h:471
BSLS_KEYWORD_CONSTEXPR size_type length() const BSLS_KEYWORD_NOEXCEPT
Return the length of this view.
Definition bslstl_stringview.h:1913
BSLS_KEYWORD_CONSTEXPR const_pointer data() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_stringview.h:1988
BSLS_KEYWORD_CONSTEXPR_CPP14 basic_string_view substr(size_type position=0, size_type numChars=npos) const
Definition bslstl_stringview.h:2027
BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference front() const
Definition bslstl_stringview.h:1966
BSLS_KEYWORD_CONSTEXPR_CPP14 void remove_prefix(size_type numChars)
Definition bslstl_stringview.h:1800
BSLS_KEYWORD_CONSTEXPR bool empty() const BSLS_KEYWORD_NOEXCEPT
Return true if this view has length 0, and false otherwise.
Definition bslstl_stringview.h:1931
BSLS_KEYWORD_CONSTEXPR_CPP20 t_PARSE_CONTEXT::iterator parse(t_PARSE_CONTEXT &context)
Definition bdlt_timeformatter.h:603
t_FORMAT_CONTEXT::iterator format(const Time &value, t_FORMAT_CONTEXT &formatContext) const
Definition bdlt_timeformatter.h:615
Definition bslstl_optional.h:2043
Definition bslfmt_formatspecificationparser.h:151
BSLS_KEYWORD_CONSTEXPR_CPP20 const FormatterSpecificationNumericValue postprocessedPrecision() const
Definition bslfmt_formatspecificationparser.h:1121
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_CONSTEXPR_CPP20
Definition bsls_keyword.h:645
Definition bbldc_basicisma30360.h:112
Definition bdlat_valuetypefunctions.h:939
Definition bslfmt_formatterbase.h:426
@ e_SECTIONS_PRECISION
Definition bslfmt_formatspecificationparser.h:135
Definition bslfmt_formattercharutil.h:138
@ e_VALUE
Definition bslfmt_formatterspecificationnumericvalue.h:105
BSLS_KEYWORD_CONSTEXPR_CPP20 int value() const
Definition bslfmt_formatterspecificationnumericvalue.h:399
BSLS_KEYWORD_CONSTEXPR_CPP20 Category category() const
Return the category attribute of this object.
Definition bslfmt_formatterspecificationnumericvalue.h:416