1 
2 #ifndef DATETIME_PERIOD_FORMATTER_HPP___
3 #define DATETIME_PERIOD_FORMATTER_HPP___
4 
5 /* Copyright (c) 2002-2004 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: Jeff Garland, Bart Garst
10  * $Date$
11  */
12 
13 #include <iosfwd>
14 #include <string>
15 #include <vector>
16 #include <iterator>
17 
18 namespace boost { namespace date_time {
19 
20 
21   //! Not a facet, but a class used to specify and control period formats
22   /*! Provides settings for the following:
23    *   - period_separator -- default '/'
24    *   - period_open_start_delimeter -- default '['
25    *   - period_open_range_end_delimeter -- default ')'
26    *   - period_closed_range_end_delimeter -- default ']'
27    *   - display_as_open_range, display_as_closed_range -- default closed_range
28    *
29    *  Thus the default formatting for a period is as follows:
30    *@code
31    *  [period.start()/period.last()]
32    *@endcode
33    *  So for a typical date_period this would be
34    *@code
35    *  [2004-Jan-04/2004-Feb-01]
36    *@endcode
37    * where the date formatting is controlled by the date facet
38    */
39   template <class CharT, class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
40   class period_formatter {
41   public:
42     typedef std::basic_string<CharT> string_type;
43     typedef CharT                    char_type;
44     typedef typename std::basic_string<char_type>::const_iterator const_itr_type;
45     typedef std::vector<std::basic_string<CharT> > collection_type;
46 
47     static const char_type default_period_separator[2];
48     static const char_type default_period_start_delimeter[2];
49     static const char_type default_period_open_range_end_delimeter[2];
50     static const char_type default_period_closed_range_end_delimeter[2];
51 
52     enum range_display_options { AS_OPEN_RANGE, AS_CLOSED_RANGE };
53 
54     //! Constructor that sets up period formatter options -- default should suffice most cases.
period_formatter(range_display_options range_option_in=AS_CLOSED_RANGE,const char_type * const period_separator=default_period_separator,const char_type * const period_start_delimeter=default_period_start_delimeter,const char_type * const period_open_range_end_delimeter=default_period_open_range_end_delimeter,const char_type * const period_closed_range_end_delimeter=default_period_closed_range_end_delimeter)55     period_formatter(range_display_options range_option_in = AS_CLOSED_RANGE,
56                      const char_type* const period_separator = default_period_separator,
57                      const char_type* const period_start_delimeter = default_period_start_delimeter,
58                      const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter,
59                      const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter) :
60       m_range_option(range_option_in),
61       m_period_separator(period_separator),
62       m_period_start_delimeter(period_start_delimeter),
63       m_open_range_end_delimeter(period_open_range_end_delimeter),
64       m_closed_range_end_delimeter(period_closed_range_end_delimeter)
65     {}
66 
67     //! Puts the characters between period elements into stream -- default is /
put_period_separator(OutItrT & oitr) const68     OutItrT put_period_separator(OutItrT& oitr) const
69     {
70       const_itr_type ci = m_period_separator.begin();
71       while (ci != m_period_separator.end()) {
72         *oitr = *ci;
73         ci++;
74       }
75       return oitr;
76     }
77 
78     //! Puts the period start characters into stream -- default is [
put_period_start_delimeter(OutItrT & oitr) const79     OutItrT put_period_start_delimeter(OutItrT& oitr) const
80     {
81       const_itr_type ci = m_period_start_delimeter.begin();
82       while (ci != m_period_start_delimeter.end()) {
83         *oitr = *ci;
84         ci++;
85       }
86       return oitr;
87     }
88 
89     //! Puts the period end characters into stream as controled by open/closed range setting.
put_period_end_delimeter(OutItrT & oitr) const90     OutItrT put_period_end_delimeter(OutItrT& oitr) const
91     {
92 
93       const_itr_type ci, end;
94       if (m_range_option == AS_OPEN_RANGE) {
95         ci = m_open_range_end_delimeter.begin();
96         end = m_open_range_end_delimeter.end();
97       }
98       else {
99         ci = m_closed_range_end_delimeter.begin();
100         end = m_closed_range_end_delimeter.end();
101       }
102       while (ci != end) {
103         *oitr = *ci;
104         ci++;
105       }
106       return oitr;
107     }
108 
range_option() const109     range_display_options range_option() const
110     {
111       return m_range_option;
112     }
113 
114     //! Reset the range_option control
115     void
range_option(range_display_options option) const116     range_option(range_display_options option) const
117     {
118       m_range_option = option;
119     }
120 
121     //! Change the delimiter strings
delimiter_strings(const string_type & separator,const string_type & start_delim,const string_type & open_end_delim,const string_type & closed_end_delim)122     void delimiter_strings(const string_type& separator,
123                            const string_type& start_delim,
124                            const string_type& open_end_delim,
125                            const string_type& closed_end_delim)
126     {
127         m_period_separator = separator;
128         m_period_start_delimeter = start_delim;
129         m_open_range_end_delimeter = open_end_delim;
130         m_closed_range_end_delimeter = closed_end_delim;
131     }
132 
133     //! Generic code to output a period -- no matter the period type.
134     /*! This generic code will output any period using a facet to
135      *  to output the 'elements'.  For example, in the case of a date_period
136      *  the elements will be instances of a date which will be formatted
137      *  according the to setup in the passed facet parameter.
138      *
139      *  The steps for formatting a period are always the same:
140      *  - put the start delimiter
141      *  - put start element
142      *  - put the separator
143      *  - put either last or end element depending on range settings
144      *  - put end delimeter depending on range settings
145      *
146      *  Thus for a typical date period the result might look like this:
147      *@code
148      *
149      *    [March 01, 2004/June 07, 2004]   <-- closed range
150      *    [March 01, 2004/June 08, 2004)   <-- open range
151      *
152      *@endcode
153      */
154     template<class period_type, class facet_type>
put_period(OutItrT next,std::ios_base & a_ios,char_type a_fill,const period_type & p,const facet_type & facet) const155     OutItrT put_period(OutItrT next,
156                        std::ios_base& a_ios,
157                        char_type a_fill,
158                        const period_type& p,
159                        const facet_type& facet) const {
160       put_period_start_delimeter(next);
161       next = facet.put(next, a_ios, a_fill, p.begin());
162       put_period_separator(next);
163       if (m_range_option == AS_CLOSED_RANGE) {
164         facet.put(next, a_ios, a_fill, p.last());
165       }
166       else {
167         facet.put(next, a_ios, a_fill, p.end());
168       }
169       put_period_end_delimeter(next);
170       return next;
171     }
172 
173 
174   private:
175     range_display_options m_range_option;
176     string_type m_period_separator;
177     string_type m_period_start_delimeter;
178     string_type m_open_range_end_delimeter;
179     string_type m_closed_range_end_delimeter;
180   };
181 
182   template <class CharT, class OutItrT>
183   const typename period_formatter<CharT, OutItrT>::char_type
184   period_formatter<CharT, OutItrT>::default_period_separator[2] = {'/'};
185 
186   template <class CharT, class OutItrT>
187   const typename period_formatter<CharT, OutItrT>::char_type
188   period_formatter<CharT, OutItrT>::default_period_start_delimeter[2] = {'['};
189 
190   template <class CharT, class OutItrT>
191   const typename period_formatter<CharT, OutItrT>::char_type
192   period_formatter<CharT, OutItrT>::default_period_open_range_end_delimeter[2] = {')'};
193 
194   template <class CharT, class OutItrT>
195   const typename period_formatter<CharT, OutItrT>::char_type
196   period_formatter<CharT, OutItrT>::default_period_closed_range_end_delimeter[2] = {']'};
197 
198  } } //namespace boost::date_time
199 
200 #endif
201