Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/date_time/time_parsing.hpp @ 66

Last change on this file since 66 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 10.6 KB
Line 
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/10/23 20:15:06 $
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, class char_type>
46  inline
47  time_duration
48  str_from_delimited_time_duration(const std::basic_string<char_type>& 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    typedef typename std::basic_string<char_type>::traits_type traits_type;
57    typedef boost::char_separator<char_type, traits_type> char_separator_type;
58    typedef boost::tokenizer<char_separator_type,
59                             typename std::basic_string<char_type>::const_iterator,
60                             std::basic_string<char_type> > tokenizer;
61    typedef typename boost::tokenizer<char_separator_type,
62                             typename std::basic_string<char_type>::const_iterator,
63                             typename std::basic_string<char_type> >::iterator tokenizer_iterator;
64   
65    char_type sep_chars[5] = {'-',':',',','.'};
66    char_separator_type sep(sep_chars);
67    tokenizer tok(s,sep);
68    for(tokenizer_iterator beg=tok.begin(); beg!=tok.end();++beg){
69      switch(pos) {
70      case 0: {
71        hour = boost::lexical_cast<int>(*beg);
72        break;
73      }
74      case 1: {
75        min = boost::lexical_cast<unsigned short>(*beg);
76        break;
77      }
78      case 2: {
79        sec = boost::lexical_cast<unsigned short>(*beg);
80        break;
81      };
82      case 3: {
83        int digits = static_cast<int>(beg->length());
84        //Works around a bug in MSVC 6 library that does not support
85        //operator>> thus meaning lexical_cast will fail to compile.
86#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
87        // msvc wouldn't compile 'time_duration::num_fractional_digits()'
88        // (required template argument list) as a workaround a temp
89        // time_duration object was used
90        time_duration td(hour,min,sec,fs);
91        int precision = td.num_fractional_digits();
92        // _atoi64 is an MS specific function
93        if(digits >= precision) {
94          // drop excess digits
95          fs = _atoi64(beg->substr(0, precision).c_str());
96        }
97        else {
98          fs = _atoi64(beg->c_str());
99        }
100#else
101        int precision = time_duration::num_fractional_digits();
102        if(digits >= precision) {
103          // drop excess digits
104          fs = boost::lexical_cast<boost::int64_t>(beg->substr(0, precision));
105        }
106        else {
107          fs = boost::lexical_cast<boost::int64_t>(*beg);
108        }
109#endif
110        if(digits < precision){
111          // trailing zeros get dropped from the string,
112          // "1:01:01.1" would yield .000001 instead of .100000
113          // the power() compensates for the missing decimal places
114          fs *= power(10, precision - digits); 
115        }
116       
117        break;
118      }
119      }//switch
120      pos++;
121    }
122    if(is_neg) {
123      return -time_duration(hour, min, sec, fs);
124    }
125    else {
126      return time_duration(hour, min, sec, fs);
127    }
128  }
129 
130  //! Creates a time_duration object from a delimited string
131  /*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
132   * If the number of fractional digits provided is greater than the
133   * precision of the time duration type then the extra digits are
134   * truncated.
135   *
136   * A negative duration will be created if the first character in
137   * string is a '-', all other '-' will be treated as delimiters.
138   * Accepted delimiters are "-:,.".
139   */
140  template<class time_duration>
141  inline
142  time_duration
143  parse_delimited_time_duration(const std::string& s)
144  {
145    return str_from_delimited_time_duration<time_duration,char>(s);
146  }
147
148  //! Utility function to split appart string
149  inline
150  bool 
151  split(const std::string& s,
152        char sep,
153        std::string& first,
154        std::string& second)
155  {
156    int sep_pos = static_cast<int>(s.find(sep));
157    first = s.substr(0,sep_pos);
158    second = s.substr(sep_pos+1);
159    return true;
160  }
161
162
163  template<class time_type>
164  inline
165  time_type
166  parse_delimited_time(const std::string& s, char sep)
167  {
168    typedef typename time_type::time_duration_type time_duration;
169    typedef typename time_type::date_type date_type;
170
171    //split date/time on a unique delimiter char such as ' ' or 'T'
172    std::string date_string, tod_string;
173    split(s, sep, date_string, tod_string);
174    //call parse_date with first string
175    date_type d = parse_date<date_type>(date_string);
176    //call parse_time_duration with remaining string
177    time_duration td = parse_delimited_time_duration<time_duration>(tod_string);
178    //construct a time
179    return time_type(d, td);
180
181  }
182
183  //! Parse time duration part of an iso time of form: [-]hhmmss[.fff...] (eg: 120259.123 is 12 hours, 2 min, 59 seconds, 123000 microseconds)
184  template<class time_duration>
185  inline
186  time_duration
187  parse_undelimited_time_duration(const std::string& s)
188  {
189    int precision = 0;
190    {
191      // msvc wouldn't compile 'time_duration::num_fractional_digits()'
192      // (required template argument list) as a workaround, a temp
193      // time_duration object was used
194      time_duration tmp(0,0,0,1);
195      precision = tmp.num_fractional_digits();
196    }
197    // 'precision+1' is so we grab all digits, plus the decimal
198    int offsets[] = {2,2,2, precision+1};
199    int pos = 0, sign = 0;
200    int hours = 0;
201    short min=0, sec=0;
202    boost::int64_t fs=0;
203    // increment one position if the string was "signed"
204    if(s.at(sign) == '-')
205    {
206      ++sign;
207    }
208    // stlport choked when passing s.substr() to tokenizer
209    // using a new string fixed the error
210    std::string remain = s.substr(sign);
211    /* We do not want the offset_separator to wrap the offsets, we
212     * will never want to  process more than:
213     * 2 char, 2 char, 2 char, frac_sec length.
214     * We *do* want the offset_separator to give us a partial for the
215     * last characters if there were not enough provided in the input string. */
216    bool wrap_off = false;
217    bool ret_part = true;
218    boost::offset_separator osf(offsets, offsets+4, wrap_off, ret_part); 
219    typedef boost::tokenizer<boost::offset_separator,
220                             std::basic_string<char>::const_iterator,
221                             std::basic_string<char> > tokenizer;
222    typedef boost::tokenizer<boost::offset_separator,
223                             std::basic_string<char>::const_iterator,
224                             std::basic_string<char> >::iterator tokenizer_iterator;
225    tokenizer tok(remain, osf);
226    for(tokenizer_iterator ti=tok.begin(); ti!=tok.end();++ti){
227      switch(pos) {
228        case 0: 
229          {
230            hours = boost::lexical_cast<int>(*ti); 
231            break;
232          }
233        case 1: 
234          {
235            min = boost::lexical_cast<short>(*ti); 
236            break;
237          }
238        case 2: 
239          {
240            sec = boost::lexical_cast<short>(*ti); 
241            break;
242          }
243        case 3:
244          {
245            std::string char_digits(ti->substr(1)); // digits w/no decimal
246            int digits = static_cast<int>(char_digits.length());
247           
248            //Works around a bug in MSVC 6 library that does not support
249            //operator>> thus meaning lexical_cast will fail to compile.
250#if (defined(BOOST_MSVC) && (_MSC_VER <= 1200))  // 1200 == VC++ 6.0
251            // _atoi64 is an MS specific function
252            if(digits >= precision) {
253              // drop excess digits
254              fs = _atoi64(char_digits.substr(0, precision).c_str());
255            }
256            else if(digits == 0) {
257              fs = 0; // just in case _atoi64 doesn't like an empty string
258            }
259            else {
260              fs = _atoi64(char_digits.c_str());
261            }
262#else
263            if(digits >= precision) {
264              // drop excess digits
265              fs = boost::lexical_cast<boost::int64_t>(char_digits.substr(0, precision));
266            }
267            else if(digits == 0) {
268              fs = 0; // lexical_cast doesn't like empty strings
269            }
270            else {
271              fs = boost::lexical_cast<boost::int64_t>(char_digits);
272            }
273#endif
274            if(digits < precision){
275              // trailing zeros get dropped from the string,
276              // "1:01:01.1" would yield .000001 instead of .100000
277              // the power() compensates for the missing decimal places
278              fs *= power(10, precision - digits); 
279            }
280           
281            break;
282          }
283      };
284      pos++;
285    }
286    if(sign) {
287      return -time_duration(hours, min, sec, fs);
288    }
289    else {
290      return time_duration(hours, min, sec, fs);
291    }
292  }
293
294  //! Parse time string of form YYYYMMDDThhmmss where T is delimeter between date and time
295  template<class time_type>
296  inline
297  time_type
298  parse_iso_time(const std::string& s, char sep)
299  {
300    typedef typename time_type::time_duration_type time_duration;
301    typedef typename time_type::date_type date_type;
302
303    //split date/time on a unique delimiter char such as ' ' or 'T'
304    std::string date_string, tod_string;
305    split(s, sep, date_string, tod_string);
306    //call parse_date with first string
307    date_type d = parse_undelimited_date<date_type>(date_string);
308    //call parse_time_duration with remaining string
309    time_duration td = parse_undelimited_time_duration<time_duration>(tod_string);
310    //construct a time
311    return time_type(d, td);
312  }
313
314
315
316} }//namespace date_time
317
318
319
320
321#endif
Note: See TracBrowser for help on using the repository browser.