2
#ifndef _DATE_TIME_FACET__HPP__
3
#define _DATE_TIME_FACET__HPP__
5
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
6
* Use, modification and distribution is subject to the
7
* Boost Software License, Version 1.0. (See accompanying
8
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
9
* Author: Martin Andrian, Jeff Garland, Bart Garst
10
* $Date: 2013-10-15 08:22:02 -0700 (Tue, 15 Oct 2013) $
19
#include <iterator> // i/ostreambuf_iterator
21
#include <boost/assert.hpp>
22
#include <boost/lexical_cast.hpp>
23
#include <boost/throw_exception.hpp>
24
#include <boost/range/as_literal.hpp>
25
#include <boost/algorithm/string/erase.hpp>
26
#include <boost/algorithm/string/replace.hpp>
27
#include <boost/date_time/compiler_config.hpp>
28
#include <boost/date_time/date_facet.hpp>
29
#include <boost/date_time/string_convert.hpp>
30
#include <boost/date_time/special_defs.hpp>
31
#include <boost/date_time/time_resolution_traits.hpp> // absolute_value
36
template <class CharT>
39
typedef CharT char_type;
40
static const char_type fractional_seconds_format[3]; // f
41
static const char_type fractional_seconds_or_none_format[3]; // F
42
static const char_type seconds_with_fractional_seconds_format[3]; // s
43
static const char_type seconds_format[3]; // S
44
static const char_type hours_format[3]; // H
45
static const char_type unrestricted_hours_format[3]; // O
46
static const char_type full_24_hour_time_format[3]; // T
47
static const char_type full_24_hour_time_expanded_format[9]; // HH:MM:SS
48
static const char_type short_24_hour_time_format[3]; // R
49
static const char_type short_24_hour_time_expanded_format[6]; // HH:MM
50
static const char_type standard_format[9]; // x X
51
static const char_type zone_abbrev_format[3]; // z
52
static const char_type zone_name_format[3]; // Z
53
static const char_type zone_iso_format[3]; // q
54
static const char_type zone_iso_extended_format[3]; // Q
55
static const char_type posix_zone_string_format[4]; // ZP
56
static const char_type duration_sign_negative_only[3]; // -
57
static const char_type duration_sign_always[3]; // +
58
static const char_type duration_seperator[2];
59
static const char_type negative_sign[2]; //-
60
static const char_type positive_sign[2]; //+
61
static const char_type iso_time_format_specifier[18];
62
static const char_type iso_time_format_extended_specifier[22];
63
//default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
64
static const char_type default_time_format[23];
65
// default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev
66
static const char_type default_time_input_format[24];
67
//default time_duration format is HH:MM:SS[.fff...]
68
static const char_type default_time_duration_format[11];
71
template <class CharT>
72
const typename time_formats<CharT>::char_type
73
time_formats<CharT>::fractional_seconds_format[3] = {'%','f'};
75
template <class CharT>
76
const typename time_formats<CharT>::char_type
77
time_formats<CharT>::fractional_seconds_or_none_format[3] = {'%','F'};
79
template <class CharT>
80
const typename time_formats<CharT>::char_type
81
time_formats<CharT>::seconds_with_fractional_seconds_format[3] = {'%','s'};
83
template <class CharT>
84
const typename time_formats<CharT>::char_type
85
time_formats<CharT>::seconds_format[3] = {'%','S'};
87
template <class CharT>
88
const typename time_formats<CharT>::char_type
89
time_formats<CharT>::hours_format[3] = {'%','H'};
91
template <class CharT>
92
const typename time_formats<CharT>::char_type
93
time_formats<CharT>::unrestricted_hours_format[3] = {'%','O'};
95
template <class CharT>
96
const typename time_formats<CharT>::char_type
97
time_formats<CharT>::full_24_hour_time_format[3] = {'%','T'};
99
template <class CharT>
100
const typename time_formats<CharT>::char_type
101
time_formats<CharT>::full_24_hour_time_expanded_format[9] =
102
{'%','H',':','%','M',':','%','S'};
104
template <class CharT>
105
const typename time_formats<CharT>::char_type
106
time_formats<CharT>::short_24_hour_time_format[3] = {'%','R'};
108
template <class CharT>
109
const typename time_formats<CharT>::char_type
110
time_formats<CharT>::short_24_hour_time_expanded_format[6] =
111
{'%','H',':','%','M'};
113
template <class CharT>
114
const typename time_formats<CharT>::char_type
115
//time_formats<CharT>::standard_format[5] = {'%','c',' ','%','z'};
116
time_formats<CharT>::standard_format[9] = {'%','x',' ','%','X',' ','%','z'};
118
template <class CharT>
119
const typename time_formats<CharT>::char_type
120
time_formats<CharT>::zone_abbrev_format[3] = {'%','z'};
122
template <class CharT>
123
const typename time_formats<CharT>::char_type
124
time_formats<CharT>::zone_name_format[3] = {'%','Z'};
126
template <class CharT>
127
const typename time_formats<CharT>::char_type
128
time_formats<CharT>::zone_iso_format[3] = {'%','q'};
130
template <class CharT>
131
const typename time_formats<CharT>::char_type
132
time_formats<CharT>::zone_iso_extended_format[3] ={'%','Q'};
134
template <class CharT>
135
const typename time_formats<CharT>::char_type
136
time_formats<CharT>::posix_zone_string_format[4] ={'%','Z','P'};
138
template <class CharT>
139
const typename time_formats<CharT>::char_type
140
time_formats<CharT>::duration_seperator[2] = {':'};
142
template <class CharT>
143
const typename time_formats<CharT>::char_type
144
time_formats<CharT>::negative_sign[2] = {'-'};
146
template <class CharT>
147
const typename time_formats<CharT>::char_type
148
time_formats<CharT>::positive_sign[2] = {'+'};
150
template <class CharT>
151
const typename time_formats<CharT>::char_type
152
time_formats<CharT>::duration_sign_negative_only[3] ={'%','-'};
154
template <class CharT>
155
const typename time_formats<CharT>::char_type
156
time_formats<CharT>::duration_sign_always[3] ={'%','+'};
158
template <class CharT>
159
const typename time_formats<CharT>::char_type
160
time_formats<CharT>::iso_time_format_specifier[18] =
161
{'%', 'Y', '%', 'm', '%', 'd', 'T',
162
'%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' };
164
template <class CharT>
165
const typename time_formats<CharT>::char_type
166
time_formats<CharT>::iso_time_format_extended_specifier[22] =
167
{'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ',
168
'%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'};
170
template <class CharT>
171
const typename time_formats<CharT>::char_type
172
time_formats<CharT>::default_time_format[23] =
173
{'%','Y','-','%','b','-','%','d',' ',
174
'%','H',':','%','M',':','%','S','%','F',' ','%','z'};
176
template <class CharT>
177
const typename time_formats<CharT>::char_type
178
time_formats<CharT>::default_time_input_format[24] =
179
{'%','Y','-','%','b','-','%','d',' ',
180
'%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'};
182
template <class CharT>
183
const typename time_formats<CharT>::char_type
184
time_formats<CharT>::default_time_duration_format[11] =
185
{'%','O',':','%','M',':','%','S','%','F'};
189
/*! Facet used for format-based output of time types
190
* This class provides for the use of format strings to output times. In addition
191
* to the flags for formatting date elements, the following are the allowed format flags:
192
* - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z")
193
* - %f => fractional seconds ".123456"
194
* - %F => fractional seconds or none: like frac sec but empty if frac sec == 0
195
* - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f)
196
* - %S => seconds "02"
197
* - %z => abbreviated time zone "EDT"
198
* - %Z => full time zone name "Eastern Daylight Time"
200
template <class time_type,
202
class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
204
public boost::date_time::date_facet<typename time_type::date_type , CharT, OutItrT> {
205
typedef time_formats< CharT > formats_type;
207
typedef typename time_type::date_type date_type;
208
typedef typename time_type::time_duration_type time_duration_type;
209
typedef boost::date_time::period<time_type,time_duration_type> period_type;
210
typedef boost::date_time::date_facet<typename time_type::date_type, CharT, OutItrT> base_type;
211
typedef typename base_type::string_type string_type;
212
typedef typename base_type::char_type char_type;
213
typedef typename base_type::period_formatter_type period_formatter_type;
214
typedef typename base_type::special_values_formatter_type special_values_formatter_type;
215
typedef typename base_type::date_gen_formatter_type date_gen_formatter_type;
216
static const char_type* fractional_seconds_format; // %f
217
static const char_type* fractional_seconds_or_none_format; // %F
218
static const char_type* seconds_with_fractional_seconds_format; // %s
219
static const char_type* seconds_format; // %S
220
static const char_type* hours_format; // %H
221
static const char_type* unrestricted_hours_format; // %O
222
static const char_type* standard_format; // %x X
223
static const char_type* zone_abbrev_format; // %z
224
static const char_type* zone_name_format; // %Z
225
static const char_type* zone_iso_format; // %q
226
static const char_type* zone_iso_extended_format; // %Q
227
static const char_type* posix_zone_string_format; // %ZP
228
static const char_type* duration_seperator;
229
static const char_type* duration_sign_always; // %+
230
static const char_type* duration_sign_negative_only; // %-
231
static const char_type* negative_sign; //-
232
static const char_type* positive_sign; //+
233
static const char_type* iso_time_format_specifier;
234
static const char_type* iso_time_format_extended_specifier;
236
//default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
237
static const char_type* default_time_format;
238
//default time_duration format is HH:MM:SS[.fff...]
239
static const char_type* default_time_duration_format;
240
static std::locale::id id;
242
#if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
243
std::locale::id& __get_id (void) const { return id; }
246
//! sets default formats for ptime, local_date_time, and time_duration
247
explicit time_facet(::size_t ref_arg = 0)
248
: base_type(default_time_format, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), ref_arg),
249
m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
252
//! Construct the facet with an explicitly specified format
253
explicit time_facet(const char_type* format_arg,
254
period_formatter_type period_formatter_arg = period_formatter_type(),
255
const special_values_formatter_type& special_value_formatter = special_values_formatter_type(),
256
date_gen_formatter_type dg_formatter = date_gen_formatter_type(),
257
::size_t ref_arg = 0)
258
: base_type(format_arg,
259
period_formatter_arg,
260
special_value_formatter,
263
m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format)
266
//! Changes format for time_duration
267
void time_duration_format(const char_type* const format)
269
m_time_duration_format = format;
272
virtual void set_iso_format()
274
this->m_format = iso_time_format_specifier;
276
virtual void set_iso_extended_format()
278
this->m_format = iso_time_format_extended_specifier;
281
OutItrT put(OutItrT next_arg,
282
std::ios_base& ios_arg,
284
const time_type& time_arg) const
286
if (time_arg.is_special()) {
287
return this->do_put_special(next_arg, ios_arg, fill_arg,
288
time_arg.date().as_special());
290
string_type local_format(this->m_format);
292
// %T and %R have to be replaced here since they are not standard
293
boost::algorithm::replace_all(local_format,
294
boost::as_literal(formats_type::full_24_hour_time_format),
295
boost::as_literal(formats_type::full_24_hour_time_expanded_format));
296
boost::algorithm::replace_all(local_format,
297
boost::as_literal(formats_type::short_24_hour_time_format),
298
boost::as_literal(formats_type::short_24_hour_time_expanded_format));
300
string_type frac_str;
301
if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
302
// replace %s with %S.nnn
304
fractional_seconds_as_string(time_arg.time_of_day(), false);
305
char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
307
string_type replace_string(seconds_format);
308
replace_string += sep;
309
replace_string += frac_str;
310
boost::algorithm::replace_all(local_format,
311
seconds_with_fractional_seconds_format,
314
/* NOTE: replacing posix_zone_string_format must be done BEFORE
315
* zone_name_format: "%ZP" & "%Z", if Z is checked first it will
316
* incorrectly replace a zone_name where a posix_string should go */
317
if (local_format.find(posix_zone_string_format) != string_type::npos) {
318
if(time_arg.zone_abbrev().empty()) {
319
// if zone_abbrev() returns an empty string, we want to
320
// erase posix_zone_string_format from format
321
boost::algorithm::erase_all(local_format, posix_zone_string_format);
324
boost::algorithm::replace_all(local_format,
325
posix_zone_string_format,
326
time_arg.zone_as_posix_string());
329
if (local_format.find(zone_name_format) != string_type::npos) {
330
if(time_arg.zone_name().empty()) {
331
/* TODO: this'll probably create problems if a user places
332
* the zone_*_format flag in the format with a ptime. This
333
* code removes the flag from the default formats */
335
// if zone_name() returns an empty string, we want to
336
// erase zone_name_format & one preceeding space
337
std::basic_ostringstream<char_type> ss;
338
ss << ' ' << zone_name_format;
339
boost::algorithm::erase_all(local_format, ss.str());
342
boost::algorithm::replace_all(local_format,
344
time_arg.zone_name());
347
if (local_format.find(zone_abbrev_format) != string_type::npos) {
348
if(time_arg.zone_abbrev(false).empty()) {
349
/* TODO: this'll probably create problems if a user places
350
* the zone_*_format flag in the format with a ptime. This
351
* code removes the flag from the default formats */
353
// if zone_abbrev() returns an empty string, we want to
354
// erase zone_abbrev_format & one preceeding space
355
std::basic_ostringstream<char_type> ss;
356
ss << ' ' << zone_abbrev_format;
357
boost::algorithm::erase_all(local_format, ss.str());
360
boost::algorithm::replace_all(local_format,
362
time_arg.zone_abbrev(false));
365
if (local_format.find(zone_iso_extended_format) != string_type::npos) {
366
if(time_arg.zone_name(true).empty()) {
367
/* TODO: this'll probably create problems if a user places
368
* the zone_*_format flag in the format with a ptime. This
369
* code removes the flag from the default formats */
371
// if zone_name() returns an empty string, we want to
372
// erase zone_iso_extended_format from format
373
boost::algorithm::erase_all(local_format, zone_iso_extended_format);
376
boost::algorithm::replace_all(local_format,
377
zone_iso_extended_format,
378
time_arg.zone_name(true));
382
if (local_format.find(zone_iso_format) != string_type::npos) {
383
if(time_arg.zone_abbrev(true).empty()) {
384
/* TODO: this'll probably create problems if a user places
385
* the zone_*_format flag in the format with a ptime. This
386
* code removes the flag from the default formats */
388
// if zone_abbrev() returns an empty string, we want to
389
// erase zone_iso_format from format
390
boost::algorithm::erase_all(local_format, zone_iso_format);
393
boost::algorithm::replace_all(local_format,
395
time_arg.zone_abbrev(true));
398
if (local_format.find(fractional_seconds_format) != string_type::npos) {
399
// replace %f with nnnnnnn
400
if (frac_str.empty()) {
401
frac_str = fractional_seconds_as_string(time_arg.time_of_day(), false);
403
boost::algorithm::replace_all(local_format,
404
fractional_seconds_format,
408
if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) {
409
// replace %F with nnnnnnn or nothing if fs == 0
411
fractional_seconds_as_string(time_arg.time_of_day(), true);
412
if (frac_str.size()) {
413
char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
414
string_type replace_string;
415
replace_string += sep;
416
replace_string += frac_str;
417
boost::algorithm::replace_all(local_format,
418
fractional_seconds_or_none_format,
422
boost::algorithm::erase_all(local_format,
423
fractional_seconds_or_none_format);
427
return this->do_put_tm(next_arg, ios_arg, fill_arg,
428
to_tm(time_arg), local_format);
431
//! put function for time_duration
432
OutItrT put(OutItrT next_arg,
433
std::ios_base& ios_arg,
435
const time_duration_type& time_dur_arg) const
437
if (time_dur_arg.is_special()) {
438
return this->do_put_special(next_arg, ios_arg, fill_arg,
439
time_dur_arg.get_rep().as_special());
442
string_type format(m_time_duration_format);
443
if (time_dur_arg.is_negative()) {
444
// replace %- with minus sign. Should we use the numpunct facet?
445
boost::algorithm::replace_all(format,
446
duration_sign_negative_only,
448
// remove all the %+ in the string with '-'
449
boost::algorithm::replace_all(format,
450
duration_sign_always,
453
else { //duration is positive
454
// remove all the %- combos from the string
455
boost::algorithm::erase_all(format, duration_sign_negative_only);
456
// remove all the %+ in the string with '+'
457
boost::algorithm::replace_all(format,
458
duration_sign_always,
462
// %T and %R have to be replaced here since they are not standard
463
boost::algorithm::replace_all(format,
464
boost::as_literal(formats_type::full_24_hour_time_format),
465
boost::as_literal(formats_type::full_24_hour_time_expanded_format));
466
boost::algorithm::replace_all(format,
467
boost::as_literal(formats_type::short_24_hour_time_format),
468
boost::as_literal(formats_type::short_24_hour_time_expanded_format));
471
* It is possible for a time duration to span more then 24 hours.
472
* Standard time_put::put is obliged to behave the same as strftime
473
* (See ISO 14882-2003 22.2.5.3.1 par. 1) and strftime's behavior is
474
* unspecified for the case when tm_hour field is outside 0-23 range
475
* (See ISO 9899-1999 7.23.3.5 par. 3). So we must output %H and %O
478
string_type hours_str;
479
if (format.find(unrestricted_hours_format) != string_type::npos) {
480
hours_str = hours_as_string(time_dur_arg);
481
boost::algorithm::replace_all(format, unrestricted_hours_format, hours_str);
483
// We still have to process restricted hours format specifier. In order to
484
// support parseability of durations in ISO format (%H%M%S), we'll have to
485
// restrict the stringified hours length to 2 characters.
486
if (format.find(hours_format) != string_type::npos) {
487
if (hours_str.empty())
488
hours_str = hours_as_string(time_dur_arg);
489
BOOST_ASSERT(hours_str.length() <= 2);
490
boost::algorithm::replace_all(format, hours_format, hours_str);
493
string_type frac_str;
494
if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) {
495
// replace %s with %S.nnn
497
fractional_seconds_as_string(time_dur_arg, false);
498
char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
500
string_type replace_string(seconds_format);
501
replace_string += sep;
502
replace_string += frac_str;
503
boost::algorithm::replace_all(format,
504
seconds_with_fractional_seconds_format,
507
if (format.find(fractional_seconds_format) != string_type::npos) {
508
// replace %f with nnnnnnn
509
if (!frac_str.size()) {
510
frac_str = fractional_seconds_as_string(time_dur_arg, false);
512
boost::algorithm::replace_all(format,
513
fractional_seconds_format,
517
if (format.find(fractional_seconds_or_none_format) != string_type::npos) {
518
// replace %F with nnnnnnn or nothing if fs == 0
520
fractional_seconds_as_string(time_dur_arg, true);
521
if (frac_str.size()) {
522
char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point();
523
string_type replace_string;
524
replace_string += sep;
525
replace_string += frac_str;
526
boost::algorithm::replace_all(format,
527
fractional_seconds_or_none_format,
531
boost::algorithm::erase_all(format,
532
fractional_seconds_or_none_format);
536
return this->do_put_tm(next_arg, ios_arg, fill_arg,
537
to_tm(time_dur_arg), format);
540
OutItrT put(OutItrT next, std::ios_base& ios_arg,
541
char_type fill, const period_type& p) const
543
return this->m_period_formatter.put_period(next, ios_arg, fill,p,*this);
551
fractional_seconds_as_string(const time_duration_type& time_arg,
554
typename time_duration_type::fractional_seconds_type frac_sec =
555
time_arg.fractional_seconds();
557
if (null_when_zero && (frac_sec == 0)) {
558
return string_type();
561
//make sure there is no sign
562
return integral_as_string(
563
date_time::absolute_value(frac_sec),
564
time_duration_type::num_fractional_digits());
569
hours_as_string(const time_duration_type& time_arg, int width = 2)
571
return integral_as_string(date_time::absolute_value(time_arg.hours()), width);
574
template< typename IntT >
577
integral_as_string(IntT val, int width = 2)
579
std::basic_ostringstream<char_type> ss;
580
ss.imbue(std::locale::classic()); // don't want any formatting
581
ss << std::setw(width)
582
<< std::setfill(static_cast<char_type>('0'));
583
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
584
// JDG [7/6/02 VC++ compatibility]
586
ss << _i64toa(static_cast<boost::int64_t>(val), buff, 10);
594
string_type m_time_duration_format;
598
template <class time_type, class CharT, class OutItrT>
599
std::locale::id time_facet<time_type, CharT, OutItrT>::id;
601
template <class time_type, class CharT, class OutItrT>
602
const typename time_facet<time_type, CharT, OutItrT>::char_type*
603
time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
605
template <class time_type, class CharT, class OutItrT>
606
const typename time_facet<time_type, CharT, OutItrT>::char_type*
607
time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
609
template <class time_type, class CharT, class OutItrT>
610
const typename time_facet<time_type, CharT, OutItrT>::char_type*
611
time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format =
612
time_formats<CharT>::seconds_with_fractional_seconds_format;
615
template <class time_type, class CharT, class OutItrT>
616
const typename time_facet<time_type, CharT, OutItrT>::char_type*
617
time_facet<time_type, CharT, OutItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
619
template <class time_type, class CharT, class OutItrT>
620
const typename time_facet<time_type, CharT, OutItrT>::char_type*
621
time_facet<time_type, CharT, OutItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
623
template <class time_type, class CharT, class OutItrT>
624
const typename time_facet<time_type, CharT, OutItrT>::char_type*
625
time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format;
627
template <class time_type, class CharT, class OutItrT>
628
const typename time_facet<time_type, CharT, OutItrT>::char_type*
629
time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format;
631
template <class time_type, class CharT, class OutItrT>
632
const typename time_facet<time_type, CharT, OutItrT>::char_type*
633
time_facet<time_type, CharT, OutItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
635
template <class time_type, class CharT, class OutItrT>
636
const typename time_facet<time_type, CharT, OutItrT>::char_type*
637
time_facet<time_type, CharT, OutItrT>::seconds_format = time_formats<CharT>::seconds_format;
639
template <class time_type, class CharT, class OutItrT>
640
const typename time_facet<time_type, CharT, OutItrT>::char_type*
641
time_facet<time_type, CharT, OutItrT>::hours_format = time_formats<CharT>::hours_format;
643
template <class time_type, class CharT, class OutItrT>
644
const typename time_facet<time_type, CharT, OutItrT>::char_type*
645
time_facet<time_type, CharT, OutItrT>::unrestricted_hours_format = time_formats<CharT>::unrestricted_hours_format;
647
template <class time_type, class CharT, class OutItrT>
648
const typename time_facet<time_type, CharT, OutItrT>::char_type*
649
time_facet<time_type, CharT, OutItrT>::standard_format = time_formats<CharT>::standard_format;
651
template <class time_type, class CharT, class OutItrT>
652
const typename time_facet<time_type, CharT, OutItrT>::char_type*
653
time_facet<time_type, CharT, OutItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
655
template <class time_type, class CharT, class OutItrT>
656
const typename time_facet<time_type, CharT, OutItrT>::char_type*
657
time_facet<time_type, CharT, OutItrT>::negative_sign = time_formats<CharT>::negative_sign;
659
template <class time_type, class CharT, class OutItrT>
660
const typename time_facet<time_type, CharT, OutItrT>::char_type*
661
time_facet<time_type, CharT, OutItrT>::positive_sign = time_formats<CharT>::positive_sign;
663
template <class time_type, class CharT, class OutItrT>
664
const typename time_facet<time_type, CharT, OutItrT>::char_type*
665
time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only = time_formats<CharT>::duration_sign_negative_only;
667
template <class time_type, class CharT, class OutItrT>
668
const typename time_facet<time_type, CharT, OutItrT>::char_type*
669
time_facet<time_type, CharT, OutItrT>::duration_sign_always = time_formats<CharT>::duration_sign_always;
671
template <class time_type, class CharT, class OutItrT>
672
const typename time_facet<time_type,CharT, OutItrT>::char_type*
673
time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
675
template <class time_type, class CharT, class OutItrT>
676
const typename time_facet<time_type, CharT, OutItrT>::char_type*
677
time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
679
template <class time_type, class CharT, class OutItrT>
680
const typename time_facet<time_type, CharT, OutItrT>::char_type*
681
time_facet<time_type, CharT, OutItrT>::default_time_format =
682
time_formats<CharT>::default_time_format;
684
template <class time_type, class CharT, class OutItrT>
685
const typename time_facet<time_type, CharT, OutItrT>::char_type*
686
time_facet<time_type, CharT, OutItrT>::default_time_duration_format =
687
time_formats<CharT>::default_time_duration_format;
690
//! Facet for format-based input.
693
template <class time_type,
695
class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > >
696
class time_input_facet :
697
public boost::date_time::date_input_facet<typename time_type::date_type , CharT, InItrT> {
699
typedef typename time_type::date_type date_type;
700
typedef typename time_type::time_duration_type time_duration_type;
701
typedef typename time_duration_type::fractional_seconds_type fracional_seconds_type;
702
typedef boost::date_time::period<time_type,time_duration_type> period_type;
703
typedef boost::date_time::date_input_facet<typename time_type::date_type, CharT, InItrT> base_type;
704
typedef typename base_type::duration_type date_duration_type;
705
typedef typename base_type::year_type year_type;
706
typedef typename base_type::month_type month_type;
707
typedef typename base_type::day_type day_type;
708
typedef typename base_type::string_type string_type;
709
typedef typename string_type::const_iterator const_itr;
710
typedef typename base_type::char_type char_type;
711
typedef typename base_type::format_date_parser_type format_date_parser_type;
712
typedef typename base_type::period_parser_type period_parser_type;
713
typedef typename base_type::special_values_parser_type special_values_parser_type;
714
typedef typename base_type::date_gen_parser_type date_gen_parser_type;
715
typedef typename base_type::special_values_parser_type::match_results match_results;
717
static const char_type* fractional_seconds_format; // f
718
static const char_type* fractional_seconds_or_none_format; // F
719
static const char_type* seconds_with_fractional_seconds_format; // s
720
static const char_type* seconds_format; // S
721
static const char_type* standard_format; // x X
722
static const char_type* zone_abbrev_format; // z
723
static const char_type* zone_name_format; // Z
724
static const char_type* zone_iso_format; // q
725
static const char_type* zone_iso_extended_format; // Q
726
static const char_type* duration_seperator;
727
static const char_type* iso_time_format_specifier;
728
static const char_type* iso_time_format_extended_specifier;
729
static const char_type* default_time_input_format;
730
static const char_type* default_time_duration_format;
731
static std::locale::id id;
733
//! Constructor that takes a format string for a ptime
734
explicit time_input_facet(const string_type& format, ::size_t ref_arg = 0)
735
: base_type(format, ref_arg),
736
m_time_duration_format(default_time_duration_format)
739
explicit time_input_facet(const string_type& format,
740
const format_date_parser_type& date_parser,
741
const special_values_parser_type& sv_parser,
742
const period_parser_type& per_parser,
743
const date_gen_parser_type& date_gen_parser,
744
::size_t ref_arg = 0)
751
m_time_duration_format(default_time_duration_format)
754
//! sets default formats for ptime, local_date_time, and time_duration
755
explicit time_input_facet(::size_t ref_arg = 0)
756
: base_type(default_time_input_format, ref_arg),
757
m_time_duration_format(default_time_duration_format)
760
//! Set the format for time_duration
761
void time_duration_format(const char_type* const format) {
762
m_time_duration_format = format;
764
virtual void set_iso_format()
766
this->m_format = iso_time_format_specifier;
768
virtual void set_iso_extended_format()
770
this->m_format = iso_time_format_extended_specifier;
773
InItrT get(InItrT& sitr,
775
std::ios_base& ios_arg,
776
period_type& p) const
778
p = this->m_period_parser.get_period(sitr,
782
time_duration_type::unit(),
787
//default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz]
788
//default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...]
790
InItrT get(InItrT& sitr,
792
std::ios_base& ios_arg,
793
time_duration_type& td) const
795
// skip leading whitespace
796
while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
798
bool use_current_char = false;
800
// num_get will consume the +/-, we may need a copy if special_value
802
if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
806
typedef typename time_duration_type::hour_type hour_type;
807
typedef typename time_duration_type::min_type min_type;
808
typedef typename time_duration_type::sec_type sec_type;
813
typename time_duration_type::fractional_seconds_type frac(0);
815
typedef std::num_get<CharT, InItrT> num_get;
816
if(!std::has_facet<num_get>(ios_arg.getloc())) {
817
num_get* ng = new num_get();
818
std::locale loc = std::locale(ios_arg.getloc(), ng);
822
const_itr itr(m_time_duration_format.begin());
823
while (itr != m_time_duration_format.end() && (sitr != stream_end)) {
825
if (++itr == m_time_duration_format.end()) break;
830
// A period may span more than 24 hours. In that case the format
831
// string should be composed with the unrestricted hours specifier.
832
hour = var_string_to_int<hour_type, CharT>(sitr, stream_end,
833
std::numeric_limits<hour_type>::digits10 + 1);
835
return check_special_value(sitr, stream_end, td, c);
842
hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2);
844
return check_special_value(sitr, stream_end, td, c);
851
min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2);
853
return check_special_value(sitr, stream_end, td, c);
861
sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2);
863
return check_special_value(sitr, stream_end, td, c);
867
// %s is the same as %S%f so we drop through into %f
871
// check for decimal, check special_values if missing
874
parse_frac_type(sitr, stream_end, frac);
875
// sitr will point to next expected char after this parsing
876
// is complete so no need to advance it
877
use_current_char = true;
880
return check_special_value(sitr, stream_end, td, c);
886
// check for decimal, skip if missing
889
parse_frac_type(sitr, stream_end, frac);
890
// sitr will point to next expected char after this parsing
891
// is complete so no need to advance it
892
use_current_char = true;
895
// nothing was parsed so we don't want to advance sitr
896
use_current_char = true;
901
{} // ignore what we don't understand?
904
else { // itr == '%', second consecutive
908
++itr; //advance past format specifier
910
else { //skip past chars in format and in buffer
912
// set use_current_char when sitr is already
913
// pointing at the next character to process
914
if (use_current_char) {
915
use_current_char = false;
923
td = time_duration_type(hour, min, sec, frac);
928
//! Parses a time object from the input stream
929
InItrT get(InItrT& sitr,
931
std::ios_base& ios_arg,
935
return get(sitr, stream_end, ios_arg, t, tz_str, false);
937
//! Expects a time_zone in the input stream
938
InItrT get_local_time(InItrT& sitr,
940
std::ios_base& ios_arg,
942
string_type& tz_str) const
944
return get(sitr, stream_end, ios_arg, t, tz_str, true);
949
InItrT get(InItrT& sitr,
951
std::ios_base& ios_arg,
954
bool time_is_local) const
956
// skip leading whitespace
957
while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
959
bool use_current_char = false;
960
bool use_current_format_char = false; // used whith two character flags
962
// num_get will consume the +/-, we may need a copy if special_value
964
if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) {
968
typedef typename time_duration_type::hour_type hour_type;
969
typedef typename time_duration_type::min_type min_type;
970
typedef typename time_duration_type::sec_type sec_type;
976
typename time_duration_type::fractional_seconds_type frac(0);
978
short day_of_year(0);
979
/* Initialized the following to their minimum values. These intermediate
980
* objects are used so we get specific exceptions when part of the input
982
* Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
983
year_type t_year(1400);
984
month_type t_month(1);
987
typedef std::num_get<CharT, InItrT> num_get;
988
if(!std::has_facet<num_get>(ios_arg.getloc())) {
989
num_get* ng = new num_get();
990
std::locale loc = std::locale(ios_arg.getloc(), ng);
994
const_itr itr(this->m_format.begin());
995
while (itr != this->m_format.end() && (sitr != stream_end)) {
997
if (++itr == this->m_format.end()) break;
999
// the cases are grouped by date & time flags - not alphabetical order
1005
char_type cs[3] = { '%', *itr };
1009
t_year = this->m_parser.parse_year(sitr, stream_end, s, mr);
1011
catch(std::out_of_range&) { // base class for bad_year exception
1012
if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1013
t = time_type(static_cast<special_values>(mr.current_match));
1017
throw; // rethrow bad_year
1026
char_type cs[3] = { '%', *itr };
1030
t_month = this->m_parser.parse_month(sitr, stream_end, s, mr);
1032
catch(std::out_of_range&) { // base class for bad_month exception
1033
if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1034
t = time_type(static_cast<special_values>(mr.current_match));
1038
throw; // rethrow bad_month
1041
// did m_parser already advance sitr to next char?
1042
if(mr.has_remaining()) {
1043
use_current_char = true;
1051
// weekday is not used in construction but we need to get it out of the stream
1052
char_type cs[3] = { '%', *itr };
1055
typename date_type::day_of_week_type wd(0);
1057
wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr);
1059
catch(std::out_of_range&) { // base class for bad_weekday exception
1060
if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1061
t = time_type(static_cast<special_values>(mr.current_match));
1065
throw; // rethrow bad_weekday
1068
// did m_parser already advance sitr to next char?
1069
if(mr.has_remaining()) {
1070
use_current_char = true;
1076
// code that gets julian day (from format_date_parser)
1078
day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3);
1079
if(day_of_year == -1) {
1080
if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1081
t = time_type(static_cast<special_values>(mr.current_match));
1085
// these next two lines are so we get an exception with bad input
1086
typedef typename time_type::date_type::day_of_year_type day_of_year_type;
1087
day_of_year_type t_day_of_year(day_of_year);
1093
t_day = this->m_parser.parse_day_of_month(sitr, stream_end);
1095
catch(std::out_of_range&) { // base class for exception bad_day_of_month
1097
if(this->m_sv_parser.match(sitr, stream_end, mr)) {
1098
t = time_type(static_cast<special_values>(mr.current_match));
1102
throw; // rethrow bad_day_of_month
1111
hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2);
1113
return check_special_value(sitr, stream_end, t, c);
1120
min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2);
1122
return check_special_value(sitr, stream_end, t, c);
1130
sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2);
1132
return check_special_value(sitr, stream_end, t, c);
1136
// %s is the same as %S%f so we drop through into %f
1140
// check for decimal, check SV if missing
1143
parse_frac_type(sitr, stream_end, frac);
1144
// sitr will point to next expected char after this parsing
1145
// is complete so no need to advance it
1146
use_current_char = true;
1149
return check_special_value(sitr, stream_end, t, c);
1155
// check for decimal, skip if missing
1158
parse_frac_type(sitr, stream_end, frac);
1159
// sitr will point to next expected char after this parsing
1160
// is complete so no need to advance it
1161
use_current_char = true;
1164
// nothing was parsed so we don't want to advance sitr
1165
use_current_char = true;
1175
if(time_is_local) { // skip if 't' is a ptime
1178
// skip leading whitespace
1179
while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; }
1181
while((sitr != stream_end) && (!std::isspace(*sitr))) {
1187
use_current_format_char = true;
1192
// nothing was parsed so we don't want to advance sitr
1193
use_current_char = true;
1199
{} // ignore what we don't understand?
1202
else { // itr == '%', second consecutive
1206
if(use_current_format_char) {
1207
use_current_format_char = false;
1210
++itr; //advance past format specifier
1214
else { //skip past chars in format and in buffer
1216
// set use_current_char when sitr is already
1217
// pointing at the next character to process
1218
if (use_current_char) {
1219
use_current_char = false;
1227
date_type d(not_a_date_time);
1228
if (day_of_year > 0) {
1229
d = date_type(static_cast<unsigned short>(t_year-1),12,31) + date_duration_type(day_of_year);
1232
d = date_type(t_year, t_month, t_day);
1235
time_duration_type td(hour, min, sec, frac);
1236
t = time_type(d, td);
1240
//! Helper function to check for special_value
1241
/*! First character may have been consumed during original parse
1242
* attempt. Parameter 'c' should be a copy of that character.
1243
* Throws ios_base::failure if parse fails. */
1244
template<class temporal_type>
1246
InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const
1249
if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed?
1252
this->m_sv_parser.match(sitr, stream_end, mr);
1253
if(mr.current_match == match_results::PARSE_ERROR) {
1254
std::string tmp = convert_string_type<char_type, char>(mr.cache);
1255
boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + tmp + "'"));
1256
BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr); // should never reach
1258
tt = temporal_type(static_cast<special_values>(mr.current_match));
1262
//! Helper function for parsing a fractional second type from the stream
1263
void parse_frac_type(InItrT& sitr,
1265
fracional_seconds_type& frac) const
1268
while((sitr != stream_end) && std::isdigit(*sitr)) {
1272
if(cache.size() > 0) {
1273
unsigned short precision = time_duration_type::num_fractional_digits();
1274
// input may be only the first few decimal places
1275
if(cache.size() < precision) {
1276
frac = lexical_cast<fracional_seconds_type>(cache);
1277
frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size()));
1280
// if input has too many decimal places, drop excess digits
1281
frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision));
1287
string_type m_time_duration_format;
1289
//! Helper function to adjust trailing zeros when parsing fractional digits
1290
template<class int_type>
1292
int_type decimal_adjust(int_type val, const unsigned short places) const
1294
unsigned long factor = 1;
1295
for(int i = 0; i < places; ++i){
1296
factor *= 10; // shift decimal to the right
1298
return val * factor;
1303
template <class time_type, class CharT, class InItrT>
1304
std::locale::id time_input_facet<time_type, CharT, InItrT>::id;
1306
template <class time_type, class CharT, class InItrT>
1307
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1308
time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format;
1310
template <class time_type, class CharT, class InItrT>
1311
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1312
time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format;
1314
template <class time_type, class CharT, class InItrT>
1315
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1316
time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format;
1318
template <class time_type, class CharT, class InItrT>
1319
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1320
time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format;
1322
template <class time_type, class CharT, class InItrT>
1323
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1324
time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format;
1326
template <class time_type, class CharT, class InItrT>
1327
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1328
time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format;
1330
template <class time_type, class CharT, class InItrT>
1331
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1332
time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format;
1334
template <class time_type, class CharT, class InItrT>
1335
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1336
time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format;
1338
template <class time_type, class CharT, class InItrT>
1339
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1340
time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format;
1342
template <class time_type, class CharT, class InItrT>
1343
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1344
time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator;
1346
template <class time_type, class CharT, class InItrT>
1347
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1348
time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier;
1350
template <class time_type, class CharT, class InItrT>
1351
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1352
time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier;
1354
template <class time_type, class CharT, class InItrT>
1355
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1356
time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format;
1358
template <class time_type, class CharT, class InItrT>
1359
const typename time_input_facet<time_type, CharT, InItrT>::char_type*
1360
time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format;