Chris@16: Chris@16: #ifndef DATETIME_PERIOD_FORMATTER_HPP___ Chris@16: #define DATETIME_PERIOD_FORMATTER_HPP___ Chris@16: Chris@16: /* Copyright (c) 2002-2004 CrystalClear Software, Inc. Chris@16: * Use, modification and distribution is subject to the Chris@16: * Boost Software License, Version 1.0. (See accompanying Chris@16: * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Author: Jeff Garland, Bart Garst Chris@101: * $Date$ Chris@16: */ Chris@16: Chris@16: Chris@16: Chris@16: namespace boost { namespace date_time { Chris@16: Chris@16: Chris@16: //! Not a facet, but a class used to specify and control period formats Chris@16: /*! Provides settings for the following: Chris@16: * - period_separator -- default '/' Chris@16: * - period_open_start_delimeter -- default '[' Chris@16: * - period_open_range_end_delimeter -- default ')' Chris@16: * - period_closed_range_end_delimeter -- default ']' Chris@16: * - display_as_open_range, display_as_closed_range -- default closed_range Chris@16: * Chris@16: * Thus the default formatting for a period is as follows: Chris@16: *@code Chris@16: * [period.start()/period.last()] Chris@16: *@endcode Chris@16: * So for a typical date_period this would be Chris@16: *@code Chris@16: * [2004-Jan-04/2004-Feb-01] Chris@16: *@endcode Chris@16: * where the date formatting is controlled by the date facet Chris@16: */ Chris@16: template > > Chris@16: class period_formatter { Chris@16: public: Chris@16: typedef std::basic_string string_type; Chris@16: typedef CharT char_type; Chris@16: typedef typename std::basic_string::const_iterator const_itr_type; Chris@16: typedef std::vector > collection_type; Chris@16: Chris@16: static const char_type default_period_separator[2]; Chris@16: static const char_type default_period_start_delimeter[2]; Chris@16: static const char_type default_period_open_range_end_delimeter[2]; Chris@16: static const char_type default_period_closed_range_end_delimeter[2]; Chris@16: Chris@16: enum range_display_options { AS_OPEN_RANGE, AS_CLOSED_RANGE }; Chris@16: Chris@16: //! Constructor that sets up period formatter options -- default should suffice most cases. Chris@16: period_formatter(range_display_options range_option_in = AS_CLOSED_RANGE, Chris@16: const char_type* const period_separator = default_period_separator, Chris@16: const char_type* const period_start_delimeter = default_period_start_delimeter, Chris@16: const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter, Chris@16: const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter) : Chris@16: m_range_option(range_option_in), Chris@16: m_period_separator(period_separator), Chris@16: m_period_start_delimeter(period_start_delimeter), Chris@16: m_open_range_end_delimeter(period_open_range_end_delimeter), Chris@16: m_closed_range_end_delimeter(period_closed_range_end_delimeter) Chris@16: {} Chris@16: Chris@16: //! Puts the characters between period elements into stream -- default is / Chris@16: OutItrT put_period_separator(OutItrT& oitr) const Chris@16: { Chris@16: const_itr_type ci = m_period_separator.begin(); Chris@16: while (ci != m_period_separator.end()) { Chris@16: *oitr = *ci; Chris@16: ci++; Chris@16: } Chris@16: return oitr; Chris@16: } Chris@16: Chris@16: //! Puts the period start characters into stream -- default is [ Chris@16: OutItrT put_period_start_delimeter(OutItrT& oitr) const Chris@16: { Chris@16: const_itr_type ci = m_period_start_delimeter.begin(); Chris@16: while (ci != m_period_start_delimeter.end()) { Chris@16: *oitr = *ci; Chris@16: ci++; Chris@16: } Chris@16: return oitr; Chris@16: } Chris@16: Chris@16: //! Puts the period end characters into stream as controled by open/closed range setting. Chris@16: OutItrT put_period_end_delimeter(OutItrT& oitr) const Chris@16: { Chris@16: Chris@16: const_itr_type ci, end; Chris@16: if (m_range_option == AS_OPEN_RANGE) { Chris@16: ci = m_open_range_end_delimeter.begin(); Chris@16: end = m_open_range_end_delimeter.end(); Chris@16: } Chris@16: else { Chris@16: ci = m_closed_range_end_delimeter.begin(); Chris@16: end = m_closed_range_end_delimeter.end(); Chris@16: } Chris@16: while (ci != end) { Chris@16: *oitr = *ci; Chris@16: ci++; Chris@16: } Chris@16: return oitr; Chris@16: } Chris@16: Chris@16: range_display_options range_option() const Chris@16: { Chris@16: return m_range_option; Chris@16: } Chris@16: Chris@16: //! Reset the range_option control Chris@16: void Chris@16: range_option(range_display_options option) const Chris@16: { Chris@16: m_range_option = option; Chris@16: } Chris@16: void delimiter_strings(const string_type& , Chris@16: const string_type& , Chris@16: const string_type& , Chris@16: const string_type& ) Chris@16: { Chris@16: m_period_separator; Chris@16: m_period_start_delimeter; Chris@16: m_open_range_end_delimeter; Chris@16: m_closed_range_end_delimeter; Chris@16: } Chris@16: Chris@16: Chris@16: //! Generic code to output a period -- no matter the period type. Chris@16: /*! This generic code will output any period using a facet to Chris@16: * to output the 'elements'. For example, in the case of a date_period Chris@16: * the elements will be instances of a date which will be formatted Chris@16: * according the to setup in the passed facet parameter. Chris@16: * Chris@16: * The steps for formatting a period are always the same: Chris@16: * - put the start delimiter Chris@16: * - put start element Chris@16: * - put the separator Chris@16: * - put either last or end element depending on range settings Chris@16: * - put end delimeter depending on range settings Chris@16: * Chris@16: * Thus for a typical date period the result might look like this: Chris@16: *@code Chris@16: * Chris@16: * [March 01, 2004/June 07, 2004] <-- closed range Chris@16: * [March 01, 2004/June 08, 2004) <-- open range Chris@16: * Chris@16: *@endcode Chris@16: */ Chris@16: template Chris@16: OutItrT put_period(OutItrT next, Chris@16: std::ios_base& a_ios, Chris@16: char_type a_fill, Chris@16: const period_type& p, Chris@16: const facet_type& facet) const { Chris@16: put_period_start_delimeter(next); Chris@16: next = facet.put(next, a_ios, a_fill, p.begin()); Chris@16: put_period_separator(next); Chris@16: if (m_range_option == AS_CLOSED_RANGE) { Chris@16: facet.put(next, a_ios, a_fill, p.last()); Chris@16: } Chris@16: else { Chris@16: facet.put(next, a_ios, a_fill, p.end()); Chris@16: } Chris@16: put_period_end_delimeter(next); Chris@16: return next; Chris@16: } Chris@16: Chris@16: Chris@16: private: Chris@16: range_display_options m_range_option; Chris@16: string_type m_period_separator; Chris@16: string_type m_period_start_delimeter; Chris@16: string_type m_open_range_end_delimeter; Chris@16: string_type m_closed_range_end_delimeter; Chris@16: }; Chris@16: Chris@16: template Chris@16: const typename period_formatter::char_type Chris@16: period_formatter::default_period_separator[2] = {'/'}; Chris@16: Chris@16: template Chris@16: const typename period_formatter::char_type Chris@16: period_formatter::default_period_start_delimeter[2] = {'['}; Chris@16: Chris@16: template Chris@16: const typename period_formatter::char_type Chris@16: period_formatter::default_period_open_range_end_delimeter[2] = {')'}; Chris@16: Chris@16: template Chris@16: const typename period_formatter::char_type Chris@16: period_formatter::default_period_closed_range_end_delimeter[2] = {']'}; Chris@16: Chris@16: } } //namespace boost::date_time Chris@16: Chris@16: #endif