Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / date_time / time_parsing.hpp
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
18 namespace boost {
19 namespace 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