source: NonGTP/Boost/boost/date_time/time_parsing.hpp @ 857

Revision 857, 9.3 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]1#ifndef _DATE_TIME_TIME_PARSING_HPP___
2#define _DATE_TIME_TIME_PARSING_HPP___
3
4/* Copyright (c) 2002,2003,2005 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 or http://www.boost.org/LICENSE-1.0)
8 * Author: Jeff Garland, Bart Garst
9 * $Date: 2005/07/19 11:17:32 $
10 */
11
12#include "boost/tokenizer.hpp"
13#include "boost/lexical_cast.hpp"
14#include "boost/date_time/date_parsing.hpp"
15#include "boost/cstdint.hpp"
16#include <iostream>
17
18namespace boost {
19namespace date_time {
20
21  //! computes exponential math like 2^8 => 256, only works with positive integers
22  //Not general purpose, but needed b/c std::pow is not available
23  //everywehere. Hasn't been tested with negatives and zeros
24  template<class int_type>
25  inline
26  int_type power(int_type base, int_type exponent)
27  {
28    int_type result = 1;
29    for(int i = 0; i < exponent; ++i){
30      result *= base;
31    }
32    return result;
33  }
34 
35  //! Creates a time_duration object from a delimited string
36  /*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
37   * If the number of fractional digits provided is greater than the
38   * precision of the time duration type then the extra digits are
39   * truncated.
40   *
41   * A negative duration will be created if the first character in
42   * string is a '-', all other '-' will be treated as delimiters.
43   * Accepted delimiters are "-:,.".
44   */
45  template<class time_duration>
46  inline
47  time_duration
48  parse_delimited_time_duration(const std::string& s)
49  {
50    unsigned short min=0, sec =0;
51    int hour =0;
52    bool is_neg = (s.at(0) == '-');
53    boost::int64_t fs=0;
54    int pos = 0;
55   
56    char_separator<char> sep("-:,.");
57    tokenizer<char_separator<char> > tok(s,sep);
58    for(tokenizer<char_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg){
59      switch(pos) {
60      case 0: {
61        hour = boost::lexical_cast<int>(*beg);
62        break;
63      }
64      case 1: {
65        min = boost::lexical_cast<unsigned short>(*beg);
66        break;
67      }
68      case 2: {
69        sec = boost::lexical_cast<unsigned short>(*beg);
70        break;
71      };
72      case 3: {
73        int digits = static_cast<int>(beg->length());
74        //Works around a bug in MSVC 6 library that does not support
75        //operator>> thus meaning lexical_cast will fail to compile.
76#if (defined(BOOST_MSVC) && (_MSC_VER <= 1200))  // 1200 == VC++ 6.0
77        // msvc wouldn't compile 'time_duration::num_fractional_digits()'
78        // (required template argument list) as a workaround a temp
79        // time_duration object was used
80        time_duration td(hour,min,sec,fs);
81        int precision = td.num_fractional_digits();
82        // _atoi64 is an MS specific function
83        if(digits >= precision) {
84          // drop excess digits
85          fs = _atoi64(beg->substr(0, precision).c_str());
86        }
87        else {
88          fs = _atoi64(beg->c_str());
89        }
90#else
91        int precision = time_duration::num_fractional_digits();
92        if(digits >= precision) {
93          // drop excess digits
94          fs = boost::lexical_cast<boost::int64_t>(beg->substr(0, precision));
95        }
96        else {
97          fs = boost::lexical_cast<boost::int64_t>(*beg);
98        }
99#endif
100        if(digits < precision){
101          // trailing zeros get dropped from the string,
102          // "1:01:01.1" would yield .000001 instead of .100000
103          // the power() compensates for the missing decimal places
104          fs *= power(10, precision - digits);
105        }
106       
107        break;
108      }
109      }//switch
110      pos++;
111    }
112    if(is_neg) {
113      return -time_duration(hour, min, sec, fs);
114    }
115    else {
116      return time_duration(hour, min, sec, fs);
117    }
118  }
119
120  //! Utility function to split appart string
121  inline
122  bool
123  split(const std::string& s,
124        char sep,
125        std::string& first,
126        std::string& second)
127  {
128    int sep_pos = static_cast<int>(s.find(sep));
129    first = s.substr(0,sep_pos);
130    second = s.substr(sep_pos+1);
131    return true;
132  }
133
134
135  template<class time_type>
136  inline
137  time_type
138  parse_delimited_time(const std::string& s, char sep)
139  {
140    typedef typename time_type::time_duration_type time_duration;
141    typedef typename time_type::date_type date_type;
142
143    //split date/time on a unique delimiter char such as ' ' or 'T'
144    std::string date_string, tod_string;
145    split(s, sep, date_string, tod_string);
146    //call parse_date with first string
147    date_type d = parse_date<date_type>(date_string);
148    //call parse_time_duration with remaining string
149    time_duration td = parse_delimited_time_duration<time_duration>(tod_string);
150    //construct a time
151    return time_type(d, td);
152
153  }
154
155  //! Parse time duration part of an iso time of form: [-]hhmmss[.fff...] (eg: 120259.123 is 12 hours, 2 min, 59 seconds, 123000 microseconds)
156  template<class time_duration>
157  inline
158  time_duration
159  parse_undelimited_time_duration(const std::string& s)
160  {
161    int precision = 0;
162    {
163      // msvc wouldn't compile 'time_duration::num_fractional_digits()'
164      // (required template argument list) as a workaround, a temp
165      // time_duration object was used
166      time_duration tmp(0,0,0,1);
167      precision = tmp.num_fractional_digits();
168    }
169    // 'precision+1' is so we grab all digits, plus the decimal
170    int offsets[] = {2,2,2, precision+1};
171    int pos = 0, sign = 0;
172    int hours = 0;
173    short min=0, sec=0;
174    boost::int64_t fs=0;
175    // increment one position if the string was "signed"
176    if(s.at(sign) == '-')
177    {
178      ++sign;
179    }
180    // stlport choked when passing s.substr() to tokenizer
181    // using a new string fixed the error
182    std::string remain = s.substr(sign);
183    /* We do not want the offset_separator to wrap the offsets, we
184     * will never want to  process more than:
185     * 2 char, 2 char, 2 char, frac_sec length.
186     * We *do* want the offset_separator to give us a partial for the
187     * last characters if there were not enough provided in the input string. */
188    bool wrap_off = false;
189    bool ret_part = true;
190    boost::offset_separator osf(offsets, offsets+4, wrap_off, ret_part);
191    boost::tokenizer<boost::offset_separator> tok(remain, osf);
192    for(boost::tokenizer<boost::offset_separator>::iterator ti=tok.begin(); ti!=tok.end();++ti){
193      switch(pos) {
194        case 0:
195          {
196            hours = boost::lexical_cast<int>(*ti);
197            break;
198          }
199        case 1:
200          {
201            min = boost::lexical_cast<short>(*ti);
202            break;
203          }
204        case 2:
205          {
206            sec = boost::lexical_cast<short>(*ti);
207            break;
208          }
209        case 3:
210          {
211            std::string char_digits(ti->substr(1)); // digits w/no decimal
212            int digits = static_cast<int>(char_digits.length());
213           
214            //Works around a bug in MSVC 6 library that does not support
215            //operator>> thus meaning lexical_cast will fail to compile.
216#if (defined(BOOST_MSVC) && (_MSC_VER <= 1200))  // 1200 == VC++ 6.0
217            // _atoi64 is an MS specific function
218            if(digits >= precision) {
219              // drop excess digits
220              fs = _atoi64(char_digits.substr(0, precision).c_str());
221            }
222            else if(digits == 0) {
223              fs = 0; // just in case _atoi64 doesn't like an empty string
224            }
225            else {
226              fs = _atoi64(char_digits.c_str());
227            }
228#else
229            if(digits >= precision) {
230              // drop excess digits
231              fs = boost::lexical_cast<boost::int64_t>(char_digits.substr(0, precision));
232            }
233            else if(digits == 0) {
234              fs = 0; // lexical_cast doesn't like empty strings
235            }
236            else {
237              fs = boost::lexical_cast<boost::int64_t>(char_digits);
238            }
239#endif
240            if(digits < precision){
241              // trailing zeros get dropped from the string,
242              // "1:01:01.1" would yield .000001 instead of .100000
243              // the power() compensates for the missing decimal places
244              fs *= power(10, precision - digits);
245            }
246           
247            break;
248          }
249      };
250      pos++;
251    }
252    if(sign) {
253      return -time_duration(hours, min, sec, fs);
254    }
255    else {
256      return time_duration(hours, min, sec, fs);
257    }
258  }
259
260  //! Parse time string of form YYYYMMDDThhmmss where T is delimeter between date and time
261  template<class time_type>
262  inline
263  time_type
264  parse_iso_time(const std::string& s, char sep)
265  {
266    typedef typename time_type::time_duration_type time_duration;
267    typedef typename time_type::date_type date_type;
268
269    //split date/time on a unique delimiter char such as ' ' or 'T'
270    std::string date_string, tod_string;
271    split(s, sep, date_string, tod_string);
272    //call parse_date with first string
273    date_type d = parse_undelimited_date<date_type>(date_string);
274    //call parse_time_duration with remaining string
275    time_duration td = parse_undelimited_time_duration<time_duration>(tod_string);
276    //construct a time
277    return time_type(d, td);
278  }
279
280
281
282} }//namespace date_time
283
284
285
286
287#endif
Note: See TracBrowser for help on using the repository browser.