BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlt_dateformatter.h
Go to the documentation of this file.
1/// @file bdlt_dateformatter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlt_dateformatter.h -*-C++-*-
8#ifndef INCLUDED_BDLT_DATEFORMATTER
9#define INCLUDED_BDLT_DATEFORMATTER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlt_dateformatter bdlt_dateformatter
15/// @brief Provide `bsl::formatter` specialization for `bdlt::Date`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlt
19/// @{
20/// @addtogroup bdlt_dateformatter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlt_dateformatter-purpose"> Purpose</a>
25/// * <a href="#bdlt_dateformatter-classes"> Classes </a>
26/// * <a href="#bdlt_dateformatter-description"> Description </a>
27///
28/// # Purpose {#bdlt_dateformatter-purpose}
29/// Provide `bsl::formatter` specialization for `bdlt::Date`.
30///
31/// # Classes {#bdlt_dateformatter-classes}
32///
33/// - bdlt::DateFormatter: date specifier formatter template
34/// - bsl::formatter<bdlt::Date, t_CHAR>: specialization
35///
36/// @see bdlt_date, bdlt_formatter
37///
38/// # Description {#bdlt_dateformatter-description}
39/// This component provides `bdlt::DateFormatter` and a
40/// specialization of `bsl::formatter` that allow `bsl::format` to output
41/// values of `bdlt::Date`.
42///
43/// The formatter supports various `Date` format specifiers including:
44/// - Year: 'Y' (4-digit), 'y' (2-digit), 'C' (century)
45/// - Month: 'm' (numeric), 'b'/'h' (abbreviated name)
46/// - Day: 'd' (zero-padded), 'e' (space-padded)
47/// - Day of week: 'a' (abbreviated name), 'u'/'w' (numeric)
48/// - Day of year: 'j' (numeric)
49/// - Compound: "{}" or 'D' (default format), 'F'/'i' (ISO 8601 format)
50/// @}
51/** @} */
52/** @} */
53
54/** @addtogroup bdl
55 * @{
56 */
57/** @addtogroup bdlt
58 * @{
59 */
60/** @addtogroup bdlt_dateformatter
61 * @{
62 */
63
64#include <bdlscm_version.h>
65
66#include <bdlt_date.h>
67#include <bdlt_dayofweek.h>
68#include <bdlt_formatter.h>
69#include <bdlt_formatutil.h>
70#include <bdlt_monthofyear.h>
71
74
75#include <bsla_fallthrough.h>
76
77#include <bsls_keyword.h>
78
79#include <bsl_string_view.h>
80
81
82namespace bdlt {
83
84class DateFormatter_Cache;
85
86 // ===================
87 // class DateFormatter
88 // ===================
89
90/// This `class` provides a specifier formatter for printing `Date` objects.
91///
92/// See @ref bdlt_dateformatter
93template <class t_CHAR>
95 private:
96 // PRIVATE TYPES
99 typedef typename Util::StringView StringView;
100
101 enum {
102 k_DAY_OF_MONTH_WIDTH = 2,
103 k_DAY_OF_YEAR_WIDTH = 3,
104 k_WEEKDAY_INDEX_WIDTH = 1,
105 k_WEEKDAY_NAME_WIDTH = 3,
106 k_MONTH_INDEX_WIDTH = 2,
107 k_MONTH_NAME_WIDTH = 3,
108 k_YEAR_WIDTH = 4,
109 k_ABBREVIATED_YEAR_WIDTH = 2,
110 k_CENTURY_WIDTH = 2,
111 k_DASH_WIDTH = 1
112 };
113
114 // DATA
115 int d_fixedWidth;
116
117 // PRIVATE CLASS METHODS
118
119 /// Write the two-digit, zero-padded day of month from the specified
120 /// `value` to the specified `out` and return `out`.
121 template <class t_ITERATOR>
122 static t_ITERATOR formatDayOfMonth(t_ITERATOR out,
123 const DateFormatter_Cache& value);
124
125 /// Write the three-letter English abbreviation of the day of week from the
126 /// specified `value` to the specified `out` and return `out`.
127 template <class t_ITERATOR>
128 static t_ITERATOR formatDayOfWeek(t_ITERATOR out,
129 const DateFormatter_Cache& value);
130
131 /// Write the two-digit, zero-padded month of year from the specified
132 /// `value` to the specified `out` and return `out`.
133 template <class t_ITERATOR>
134 static t_ITERATOR formatMonthIndex(t_ITERATOR out,
135 const DateFormatter_Cache& value);
136
137 /// Write the three-letter English abbreviation of the month of year from
138 /// the specified `value` to the specified `out` and return `out`.
139 template <class t_ITERATOR>
140 static t_ITERATOR formatMonthOfYear(t_ITERATOR out,
141 const DateFormatter_Cache& value);
142
143 /// Write the four-digit, zero-padded year from the specified `value` to
144 /// the specified `out` and return `out`.
145 template <class t_ITERATOR>
146 static t_ITERATOR formatYear(t_ITERATOR out,
147 const DateFormatter_Cache& value);
148
149 public:
150 // CREATORS
151
152 /// Create an object in its default initial state.
155
156 // MANIPULATORS
157
158 /// Update this object as-if parsing `Date` in default mode.
160
161 /// Update this object as-if parsing `Date` in Iso8601 mode.
163
164 /// Examine the first character of the specified `*specInOut` and if it is
165 /// recognized as a modifier by this object, update this object's state to
166 /// reflect it and pop it off the front of `*specInOut` and return `true`,
167 /// and if not, return `false` with no modification to `*specInOut`.
169
170 /// If the first character of the specified `*specInOut` is recognized by
171 /// this specifier formatter, parse it, remove it from `*specInOut`, and
172 /// return `true`, otherwise return `false` with no modification to `*specInOut`.
173 ///
174 /// \pre The behavior is undefined if `*specInOut` is empty.
177
178 /// Read post-processed fields from the specified `spec` that are relevant
179 /// to this specifier formatter.
181
182 // ACCESSORS
183
184 /// Return the `bslfmt::FormatSpecificationParser::Sections` flags that
185 /// apply to this value type.
187
188 /// If the first character of the specified `*specInOut` is recognized by
189 /// this specifier formatter, use it to format the specified `value` to
190 /// `*outIt`, remove the character from `*specInOut`, and return `true`,
191 /// otherwise return `false` with no modification to `*specInOut`.
192 template <class t_ITERATOR>
194 t_ITERATOR *outIt,
195 const DateFormatter_Cache& value) const;
196
197 /// Format the specified `value` to the specified `out` using the default
198 /// format and return `out`.
199 template <class t_ITERATOR>
200 t_ITERATOR formatDefault(t_ITERATOR out,
201 const DateFormatter_Cache& value) const;
202
203 /// Format the specified `value` to the specified `out` using the Iso8601
204 /// format and return `out`.
205 template <class t_ITERATOR>
206 t_ITERATOR formatIso8601(t_ITERATOR out,
207 const DateFormatter_Cache& value) const;
208
209 /// Return the anticipated width of output given all the `parse*` calls
210 /// that have been happened thus far and the specified `value`.
212 int totalWidth(const DateFormatter_Cache& value) const;
213};
214
215 // =========================
216 // class DateFormatter_Cache
217 // =========================
218
219/// This `class` facilitates faster access to a `Date` object during printing
220/// by batching access to several fields in a single call during construction
221/// and caching them for quick access later.
222///
223/// See @ref bdlt_dateformatter
225 Date d_value;
226 int d_year;
227 int d_month;
228 int d_day;
229
230 public:
231 // CREATORS
232
233 /// Cache a copy the specified `value` and its `year`, `month`, and `day`
234 /// fields.
235 DateFormatter_Cache(const Date& value);
236
237 // ACCESSORS
238
239 /// Return the cached `year` field.
240 int year() const;
241
242 /// Return the cached `month` field.
243 int month() const;
244
245 /// Return the cached `day` field.
246 int day() const;
247
248 /// Call the `dayOfWeek` accessor of the cached date and return the value.
249 int dayOfWeek() const;
250
251 /// Call the `dayOfYear` accessor of the cached date and return the value.
252 int dayOfYear() const;
253};
254
255// ============================================================================
256// INLINE DEFINITIONS
257// ============================================================================
258
259 // -------------
260 // DateFormatter
261 // -------------
262
263// PRIVATE CLASS METHODS
264
265template <class t_CHAR>
266template <class t_ITERATOR>
267inline
269 t_ITERATOR out,
270 const DateFormatter_Cache& value)
271{
272 return Util::writeZeroPaddedDigits(out, value.day(), k_DAY_OF_MONTH_WIDTH);
273}
274
275template <class t_CHAR>
276template <class t_ITERATOR>
277inline
278t_ITERATOR DateFormatter<t_CHAR>::formatDayOfWeek(
279 t_ITERATOR out,
280 const DateFormatter_Cache& value)
281{
282 bsl::string_view dayOfWeekName = DayOfWeek::toAscii(
283 static_cast<DayOfWeek::Enum>(value.dayOfWeek()));
284
285 return FormatterCharUtil::outputFromChar(
286 dayOfWeekName.data(),
287 dayOfWeekName.data() + dayOfWeekName.length(),
288 out);
289}
290
291template <class t_CHAR>
292template <class t_ITERATOR>
293inline
294t_ITERATOR DateFormatter<t_CHAR>::formatMonthIndex(
295 t_ITERATOR out,
296 const DateFormatter_Cache& value)
297{
298 return Util::writeZeroPaddedDigits(out,
299 value.month(),
300 k_MONTH_INDEX_WIDTH);
301}
302
303template <class t_CHAR>
304template <class t_ITERATOR>
305inline
306t_ITERATOR DateFormatter<t_CHAR>::formatMonthOfYear(
307 t_ITERATOR out,
308 const DateFormatter_Cache& value)
309{
311 static_cast<MonthOfYear::Enum>(value.month()));
312
313 return FormatterCharUtil::outputFromChar(
314 monthName.data(),
315 monthName.data() + monthName.length(),
316 out);
317}
318
319template <class t_CHAR>
320template <class t_ITERATOR>
321inline
322t_ITERATOR DateFormatter<t_CHAR>::formatYear(t_ITERATOR out,
323 const DateFormatter_Cache& value)
324{
325 return Util::writeZeroPaddedDigits(out, value.year(), k_YEAR_WIDTH);
326}
327
328// CREATORS
329template <class t_CHAR>
332: d_fixedWidth(0)
333{}
334
335 // MANIPULATORS
336template <class t_CHAR>
339{
340 d_fixedWidth += k_YEAR_WIDTH + k_MONTH_NAME_WIDTH + k_DAY_OF_MONTH_WIDTH;
341}
342
343template <class t_CHAR>
346{
347 d_fixedWidth += k_YEAR_WIDTH + k_DASH_WIDTH + k_MONTH_INDEX_WIDTH +
348 k_DASH_WIDTH + k_DAY_OF_MONTH_WIDTH;
349}
350
351template <class t_CHAR>
354{
355 return false;
356}
357
358template <class t_CHAR>
362{
363 BSLS_ASSERT(!specInOut->empty());
364
365 switch (static_cast<char>(specInOut->front())) {
366 case 'C': {
367 d_fixedWidth += k_CENTURY_WIDTH;
368 } break;
369 case 'y': {
370 d_fixedWidth += k_ABBREVIATED_YEAR_WIDTH;
371 } break;
372 case 'Y': {
373 d_fixedWidth += k_YEAR_WIDTH;
374 } break;
375 case 'm': {
376 d_fixedWidth += k_MONTH_INDEX_WIDTH;
377 } break;
378 case 'b':
379 case 'h': {
380 d_fixedWidth += k_MONTH_NAME_WIDTH;
381 } break;
382 case 'd':
383 case 'e': {
384 d_fixedWidth += k_DAY_OF_MONTH_WIDTH;
385 } break;
386 case 'a': {
387 d_fixedWidth += k_WEEKDAY_NAME_WIDTH;
388 } break;
389 case 'u':
390 case 'w': {
391 d_fixedWidth += k_WEEKDAY_INDEX_WIDTH;
392 } break;
393 case 'j': {
394 d_fixedWidth += k_DAY_OF_YEAR_WIDTH;
395 } break;
396 case 'D': {
397 parseDefault();
398 } break;
399 case 'F': BSLA_FALLTHROUGH;
400 case 'i': {
401 parseIso8601();
402 } break;
403 default: {
404 return false; // RETURN
405 } break;
406 }
407
408 specInOut->remove_prefix(1);
409
410 return true;
411}
412
413template <class t_CHAR>
414inline
418
419// ACCESSORS
420template <class t_CHAR>
423 return 0;
424}
425
426template <class t_CHAR>
427template <class t_ITERATOR>
430 t_ITERATOR *outIt,
431 const DateFormatter_Cache& value) const
432{
433 BSLS_ASSERT_SAFE(!specInOut->empty());
434
435 switch (static_cast<char>(specInOut->front())) {
436 case 'C': {
437 *outIt = Util::writeZeroPaddedDigits(*outIt,
438 value.year() / 100,
439 k_CENTURY_WIDTH);
440 } break;
441 case 'y': {
442 *outIt = Util::writeZeroPaddedDigits(*outIt,
443 value.year() % 100,
444 k_ABBREVIATED_YEAR_WIDTH);
445 } break;
446 case 'Y': {
447 *outIt = formatYear(*outIt, value);
448 } break;
449 case 'm': {
450 *outIt = formatMonthIndex(*outIt, value);
451 } break;
452 case 'b':
453 case 'h': {
454 *outIt = formatMonthOfYear(*outIt, value);
455 } break;
456 case 'd': {
457 *outIt = formatDayOfMonth(*outIt, value);
458 } break;
459 case 'e': {
460 unsigned dom = value.day();
461 if (dom < 10) {
462 *(*outIt)++ = t_CHAR(' ');
463 *(*outIt)++ = t_CHAR('0' + dom);
464 }
465 else {
466 *outIt = Util::writeZeroPaddedDigits(*outIt,
467 value.day(),
468 k_DAY_OF_MONTH_WIDTH);
469 }
470 } break;
471 case 'a': {
472 *outIt = formatDayOfWeek(*outIt, value);
473 } break;
474 case 'u': {
475 // 1 digit day of week, starts with Monday == 1
476
477 unsigned dow = value.dayOfWeek();
478
479 // we have "Sunday is 1", we want "Monday is 1"
480
481 dow = (dow + 7 - 2) % 7 + 1; // Monday is 1
482 *(*outIt)++ = t_CHAR('0' + dow);
483 } break;
484 case 'w': {
485 unsigned dow = value.dayOfWeek();
486
487 // we have "Sunday is 1", we want "Sunday is 0"
488
489 --dow; // Sunday is 0
490 *(*outIt)++ = t_CHAR('0' + dow);
491 } break;
492 case 'j': {
493 *outIt = Util::writeZeroPaddedDigits(*outIt,
494 value.dayOfYear(),
495 k_DAY_OF_YEAR_WIDTH);
496 } break;
497 case 'D': {
498 *outIt = formatDefault(*outIt, value);
499 } break;
500 case 'F': BSLA_FALLTHROUGH;
501 case 'i': {
502 *outIt = formatIso8601(*outIt, value);
503 } break;
504 default: {
505 return false; // RETURN
506 } break;
507 }
508
509 specInOut->remove_prefix(1);
510
511 return true;
512}
513
514template <class t_CHAR>
515template <class t_ITERATOR>
516inline
518 t_ITERATOR out,
519 const DateFormatter_Cache& value) const
520{
521 out = formatDayOfMonth(out, value);
522 out = formatMonthOfYear(out, value);
523 out = formatYear(out, value);
524 return out;
525}
526
527template <class t_CHAR>
528template <class t_ITERATOR>
529inline
531 t_ITERATOR out,
532 const DateFormatter_Cache& value) const
533{
534 out = formatYear(out, value);
535 *out++ = t_CHAR('-');
536 out = formatMonthIndex(out, value);
537 *out++ = t_CHAR('-');
538 out = formatDayOfMonth(out, value);
539 return out;
540}
541
542template <class t_CHAR>
545 const DateFormatter_Cache&) const
546{
547 return d_fixedWidth;
548}
549
550 // -------------------
551 // DateFormatter_Cache
552 // -------------------
553
554// CREATORS
555inline
557: d_value(value)
558{
559 value.getYearMonthDay(&d_year, &d_month, &d_day);
560}
561
562// ACCESSORS
563inline
565{
566 return d_year;
567}
568
569inline
571{
572 return d_month;
573}
574
575inline
577{
578 return d_day;
579}
580
581inline
583{
584 return d_value.dayOfWeek();
585}
586
587inline
589{
590 return d_value.dayOfYear();
591}
592
593} // close package namespace
594
595
596namespace bsl {
597
598/// This type implements the formatter logic specific for `Date` objects.
599template <class t_CHAR>
600class formatter<BloombergLP::bdlt::Date, t_CHAR> {
601 // PRIVATE TYPES
602 typedef BloombergLP::bdlt::Date Date;
603 typedef BloombergLP::bdlt::DateFormatter_Cache FormatCache;
604 typedef BloombergLP::bdlt::Formatter<
605 BloombergLP::bdlt::DateFormatter, t_CHAR> Formatter;
606 // DATA
607 Formatter d_formatter;
608
609 public:
610 /// Parse and validate the specification string stored in the specified
611 /// `parseContext`. Return an end iterator of the parsed range. Throw
612 /// `bsl::format_error`, in the event of failure.
613 template <class t_PARSE_CONTEXT>
614 BSLS_KEYWORD_CONSTEXPR_CPP20 typename t_PARSE_CONTEXT::iterator parse(
615 t_PARSE_CONTEXT& context)
616 {
617 return d_formatter.parse(context);
618 }
619
620 /// Format the value in the specified `value` parameter according to the
621 /// specification stored as a result of a previous call to the `parse`
622 /// method, and write the result to the iterator accessed by calling the
623 /// `out()` method on the specified `formatContext` parameter. Return an
624 /// end iterator of the output range.
625 template <class t_FORMAT_CONTEXT>
626 typename t_FORMAT_CONTEXT::iterator format(
627 const Date& value,
628 t_FORMAT_CONTEXT& formatContext) const
629 {
630 return d_formatter.format(FormatCache(value), formatContext);
631 }
632};
633
634} // close namespace bsl
635
636#endif
637
638// ----------------------------------------------------------------------------
639// Copyright 2026 Bloomberg Finance L.P.
640//
641// Licensed under the Apache License, Version 2.0 (the "License");
642// you may not use this file except in compliance with the License.
643// You may obtain a copy of the License at
644//
645// http://www.apache.org/licenses/LICENSE-2.0
646//
647// Unless required by applicable law or agreed to in writing, software
648// distributed under the License is distributed on an "AS IS" BASIS,
649// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
650// See the License for the specific language governing permissions and
651// limitations under the License.
652// ----------------------------- END-OF-FILE ----------------------------------
653
654/** @} */
655/** @} */
656/** @} */
Definition bdlt_dateformatter.h:224
DateFormatter_Cache(const Date &value)
Definition bdlt_dateformatter.h:556
int month() const
Return the cached month field.
Definition bdlt_dateformatter.h:570
int dayOfWeek() const
Call the dayOfWeek accessor of the cached date and return the value.
Definition bdlt_dateformatter.h:582
int dayOfYear() const
Call the dayOfYear accessor of the cached date and return the value.
Definition bdlt_dateformatter.h:588
int day() const
Return the cached day field.
Definition bdlt_dateformatter.h:576
int year() const
Return the cached year field.
Definition bdlt_dateformatter.h:564
Definition bdlt_dateformatter.h:94
BSLS_KEYWORD_CONSTEXPR_CPP20 void parseDefault()
Update this object as-if parsing Date in default mode.
Definition bdlt_dateformatter.h:338
void postprocess(const bslfmt::FormatSpecificationParser< t_CHAR > &spec)
Definition bdlt_dateformatter.h:415
bool formatNextSpecifier(bsl::basic_string_view< t_CHAR > *specInOut, t_ITERATOR *outIt, const DateFormatter_Cache &value) const
Definition bdlt_dateformatter.h:428
BSLS_KEYWORD_CONSTEXPR_CPP20 int totalWidth(const DateFormatter_Cache &value) const
Definition bdlt_dateformatter.h:544
t_ITERATOR formatDefault(t_ITERATOR out, const DateFormatter_Cache &value) const
Definition bdlt_dateformatter.h:517
BSLS_KEYWORD_CONSTEXPR_CPP20 bool parseNextModifier(StringView *specInOut)
Definition bdlt_dateformatter.h:353
BSLS_KEYWORD_CONSTEXPR_CPP20 bool parseNextSpecifier(bsl::basic_string_view< t_CHAR > *specInOut)
Definition bdlt_dateformatter.h:360
BSLS_KEYWORD_CONSTEXPR_CPP20 DateFormatter()
Create an object in its default initial state.
Definition bdlt_dateformatter.h:331
BSLS_KEYWORD_CONSTEXPR_CPP20 void parseIso8601()
Update this object as-if parsing Date in Iso8601 mode.
Definition bdlt_dateformatter.h:345
t_ITERATOR formatIso8601(t_ITERATOR out, const DateFormatter_Cache &value) const
Definition bdlt_dateformatter.h:530
BSLS_KEYWORD_CONSTEXPR_CPP20 int extraSections() const
Definition bdlt_dateformatter.h:422
Definition bdlt_date.h:294
void getYearMonthDay(int *year, int *month, int *day) const
Definition bdlt_date.h:983
int dayOfYear() const
Return the day of the year in the range [1 .. 366] of this date.
Definition bdlt_date.h:968
DayOfWeek::Enum dayOfWeek() const
Definition bdlt_date.h:961
Definition bdlt_formatutil.h:87
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 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_dateformatter.h:614
t_FORMAT_CONTEXT::iterator format(const Date &value, t_FORMAT_CONTEXT &formatContext) const
Definition bdlt_dateformatter.h:626
Definition bslfmt_formatspecificationparser.h:151
#define BSLA_FALLTHROUGH
Definition bsla_fallthrough.h:188
#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
Enum
Enumerated day-of-week values.
Definition bdlt_dayofweek.h:125
static const char * toAscii(Enum dayOfWeek)
static const char * toAscii(MonthOfYear::Enum value)
Enum
Define the list of month-of-year values.
Definition bdlt_monthofyear.h:138
Definition bslfmt_formatterbase.h:426
Definition bslfmt_formattercharutil.h:138