1 #ifndef _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___
2 #define _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___
3 
4 /* Copyright (c) 2004 CrystalClear Software, Inc.
5  * Use, modification and distribution is subject to the
6  * Boost Software License, Version 1.0. (See accompanying
7  * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
8  * Author: Jeff Garland, Bart Garst
9  * $Date$
10  */
11 
12 #include <iostream>
13 #include <string>
14 #include <vector>
15 #include <algorithm>
16 #include "boost/date_time/date_generators.hpp"
17 
18 namespace boost {
19 namespace date_time {
20 
21   //! Formats date_generators for output
22   /*! Formatting of date_generators follows specific orders for the
23    * various types of date_generators.
24    * - partial_date                     => "dd Month"
25    * - nth_day_of_the_week_in_month     => "nth weekday of month"
26    * - first_day_of_the_week_in_month   => "first weekday of month"
27    * - last_day_of_the_week_in_month    => "last weekday of month"
28    * - first_day_of_the_week_after      => "weekday after"
29    * - first_day_of_the_week_before     => "weekday before"
30    * While the order of the elements in these phrases cannot be changed,
31    * the elements themselves can be. Weekday and Month get their formats
32    * and names from the date_facet. The remaining elements are stored in
33    * the date_generator_formatter and can be customized upon construction
34    * or via a member function. The default elements are those shown in the
35    * examples above.
36    */
37   template <class date_type, class CharT, class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
38   class date_generator_formatter {
39     public:
40       typedef partial_date<date_type>          partial_date_type;
41       typedef nth_kday_of_month<date_type>     nth_kday_type;
42       typedef first_kday_of_month<date_type>   first_kday_type;
43       typedef last_kday_of_month<date_type>    last_kday_type;
44       typedef first_kday_after<date_type>      kday_after_type;
45       typedef first_kday_before<date_type>     kday_before_type;
46 
47       typedef CharT char_type;
48       typedef std::basic_string<char_type> string_type;
49       typedef std::vector<string_type> collection_type;
50       static const char_type first_string[6];
51       static const char_type second_string[7];
52       static const char_type third_string[6];
53       static const char_type fourth_string[7];
54       static const char_type fifth_string[6];
55       static const char_type last_string[5];
56       static const char_type before_string[8];
57       static const char_type after_string[6];
58       static const char_type of_string[3];
59 
60       enum phrase_elements {first=0, second, third, fourth, fifth, last,
61                          before, after, of, number_of_phrase_elements};
62 
63       //! Default format elements used
date_generator_formatter()64       date_generator_formatter()
65       {
66         phrase_strings.reserve(number_of_phrase_elements);
67         phrase_strings.push_back(string_type(first_string));
68         phrase_strings.push_back(string_type(second_string));
69         phrase_strings.push_back(string_type(third_string));
70         phrase_strings.push_back(string_type(fourth_string));
71         phrase_strings.push_back(string_type(fifth_string));
72         phrase_strings.push_back(string_type(last_string));
73         phrase_strings.push_back(string_type(before_string));
74         phrase_strings.push_back(string_type(after_string));
75         phrase_strings.push_back(string_type(of_string));
76       }
77 
78       //! Constructor that allows for a custom set of phrase elements
date_generator_formatter(const string_type & first_str,const string_type & second_str,const string_type & third_str,const string_type & fourth_str,const string_type & fifth_str,const string_type & last_str,const string_type & before_str,const string_type & after_str,const string_type & of_str)79       date_generator_formatter(const string_type& first_str,
80                                const string_type& second_str,
81                                const string_type& third_str,
82                                const string_type& fourth_str,
83                                const string_type& fifth_str,
84                                const string_type& last_str,
85                                const string_type& before_str,
86                                const string_type& after_str,
87                                const string_type& of_str)
88       {
89         phrase_strings.reserve(number_of_phrase_elements);
90         phrase_strings.push_back(first_str);
91         phrase_strings.push_back(second_str);
92         phrase_strings.push_back(third_str);
93         phrase_strings.push_back(fourth_str);
94         phrase_strings.push_back(fifth_str);
95         phrase_strings.push_back(last_str);
96         phrase_strings.push_back(before_str);
97         phrase_strings.push_back(after_str);
98         phrase_strings.push_back(of_str);
99       }
100 
101       //! Replace the set of phrase elements with those contained in new_strings
102       /*! The order of the strings in the given collection is important.
103        * They must follow:
104        *  - first, second, third, fourth, fifth, last, before, after, of.
105        *
106        * It is not necessary to send in a complete set if only a few
107        * elements are to be replaced as long as the correct beg_pos is used.
108        *
109        * Ex: To keep the default first through fifth elements, but replace
110        * the rest with a collection of:
111        *  - "final", "prior", "following", "in".
112        * The beg_pos of date_generator_formatter::last would be used.
113        */
elements(const collection_type & new_strings,phrase_elements beg_pos=first)114       void elements(const collection_type& new_strings,
115                     phrase_elements beg_pos=first)
116       {
117         if(beg_pos < number_of_phrase_elements) {
118           typename collection_type::iterator itr = phrase_strings.begin();
119           itr += beg_pos;
120           std::copy(new_strings.begin(), new_strings.end(),
121                     itr);
122                     //phrase_strings.begin());
123         }
124       }
125 
126       //!Put a partial_date => "dd Month"
127       template<class facet_type>
put_partial_date(OutItrT next,std::ios_base & a_ios,CharT a_fill,const partial_date_type & pd,const facet_type & facet) const128       OutItrT put_partial_date(OutItrT next, std::ios_base& a_ios,
129                                CharT a_fill, const partial_date_type& pd,
130                                const facet_type& facet) const
131       {
132         facet.put(next, a_ios, a_fill, pd.day());
133         next = a_fill; //TODO change this ???
134         facet.put(next, a_ios, a_fill, pd.month());
135         return next;
136       }
137 
138       //! Put an nth_day_of_the_week_in_month => "nth weekday of month"
139       template<class facet_type>
put_nth_kday(OutItrT next,std::ios_base & a_ios,CharT a_fill,const nth_kday_type & nkd,const facet_type & facet) const140       OutItrT put_nth_kday(OutItrT next, std::ios_base& a_ios,
141                            CharT a_fill, const nth_kday_type& nkd,
142                            const facet_type& facet) const
143       {
144         put_string(next, phrase_strings[nkd.nth_week() -1]);
145         next = a_fill; //TODO change this ???
146         facet.put(next, a_ios, a_fill, nkd.day_of_week());
147         next = a_fill; //TODO change this ???
148         put_string(next, string_type(of_string));
149         next = a_fill; //TODO change this ???
150         facet.put(next, a_ios, a_fill, nkd.month());
151         return next;
152       }
153 
154       //! Put a first_day_of_the_week_in_month => "first weekday of month"
155       template<class facet_type>
put_first_kday(OutItrT next,std::ios_base & a_ios,CharT a_fill,const first_kday_type & fkd,const facet_type & facet) const156       OutItrT put_first_kday(OutItrT next, std::ios_base& a_ios,
157                              CharT a_fill, const first_kday_type& fkd,
158                              const facet_type& facet) const
159       {
160         put_string(next, phrase_strings[first]);
161         next = a_fill; //TODO change this ???
162         facet.put(next, a_ios, a_fill, fkd.day_of_week());
163         next = a_fill; //TODO change this ???
164         put_string(next, string_type(of_string));
165         next = a_fill; //TODO change this ???
166         facet.put(next, a_ios, a_fill, fkd.month());
167         return next;
168       }
169 
170       //! Put a last_day_of_the_week_in_month => "last weekday of month"
171       template<class facet_type>
put_last_kday(OutItrT next,std::ios_base & a_ios,CharT a_fill,const last_kday_type & lkd,const facet_type & facet) const172       OutItrT put_last_kday(OutItrT next, std::ios_base& a_ios,
173                            CharT a_fill, const last_kday_type& lkd,
174                            const facet_type& facet) const
175       {
176         put_string(next, phrase_strings[last]);
177         next = a_fill; //TODO change this ???
178         facet.put(next, a_ios, a_fill, lkd.day_of_week());
179         next = a_fill; //TODO change this ???
180         put_string(next, string_type(of_string));
181         next = a_fill; //TODO change this ???
182         facet.put(next, a_ios, a_fill, lkd.month());
183         return next;
184       }
185 
186       //! Put a first_day_of_the_week_before => "weekday before"
187       template<class facet_type>
put_kday_before(OutItrT next,std::ios_base & a_ios,CharT a_fill,const kday_before_type & fkb,const facet_type & facet) const188       OutItrT put_kday_before(OutItrT next, std::ios_base& a_ios,
189                               CharT a_fill, const kday_before_type& fkb,
190                               const facet_type& facet) const
191       {
192         facet.put(next, a_ios, a_fill, fkb.day_of_week());
193         next = a_fill; //TODO change this ???
194         put_string(next, phrase_strings[before]);
195         return next;
196       }
197 
198       //! Put a first_day_of_the_week_after => "weekday after"
199       template<class facet_type>
put_kday_after(OutItrT next,std::ios_base & a_ios,CharT a_fill,const kday_after_type & fka,const facet_type & facet) const200       OutItrT put_kday_after(OutItrT next, std::ios_base& a_ios,
201                              CharT a_fill, const kday_after_type& fka,
202                              const facet_type& facet) const
203       {
204         facet.put(next, a_ios, a_fill, fka.day_of_week());
205         next = a_fill; //TODO change this ???
206         put_string(next, phrase_strings[after]);
207         return next;
208       }
209 
210 
211     private:
212       collection_type phrase_strings;
213 
214       //! helper function to put the various member string into stream
put_string(OutItrT next,const string_type & str) const215       OutItrT put_string(OutItrT next, const string_type& str) const
216       {
217         typename string_type::const_iterator itr = str.begin();
218         while(itr != str.end()) {
219           *next = *itr;
220           ++itr;
221           ++next;
222         }
223         return next;
224       }
225   };
226 
227   template<class date_type, class CharT, class OutItrT>
228   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
229   date_generator_formatter<date_type, CharT, OutItrT>::first_string[6] =
230     {'f','i','r','s','t'};
231   template<class date_type, class CharT, class OutItrT>
232   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
233   date_generator_formatter<date_type, CharT, OutItrT>::second_string[7] =
234     {'s','e','c','o','n','d'};
235   template<class date_type, class CharT, class OutItrT>
236   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
237   date_generator_formatter<date_type, CharT, OutItrT>::third_string[6] =
238     {'t','h','i','r','d'};
239   template<class date_type, class CharT, class OutItrT>
240   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
241   date_generator_formatter<date_type, CharT, OutItrT>::fourth_string[7] =
242     {'f','o','u','r','t','h'};
243   template<class date_type, class CharT, class OutItrT>
244   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
245   date_generator_formatter<date_type, CharT, OutItrT>::fifth_string[6] =
246     {'f','i','f','t','h'};
247   template<class date_type, class CharT, class OutItrT>
248   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
249   date_generator_formatter<date_type, CharT, OutItrT>::last_string[5] =
250     {'l','a','s','t'};
251   template<class date_type, class CharT, class OutItrT>
252   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
253   date_generator_formatter<date_type, CharT, OutItrT>::before_string[8] =
254     {'b','e','f','o','r','e'};
255   template<class date_type, class CharT, class OutItrT>
256   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
257   date_generator_formatter<date_type, CharT, OutItrT>::after_string[6] =
258     {'a','f','t','e','r'};
259   template<class date_type, class CharT, class OutItrT>
260   const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
261   date_generator_formatter<date_type, CharT, OutItrT>::of_string[3] =
262     {'o','f'};
263 } } // namespaces
264 
265 #endif // _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___
266