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