File indexing completed on 2025-01-30 09:35:25
0001 #ifndef DATE_TIME_TZ_DB_BASE_HPP__
0002 #define DATE_TIME_TZ_DB_BASE_HPP__
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <map>
0012 #include <vector>
0013 #include <string>
0014 #include <sstream>
0015 #include <fstream>
0016 #include <stdexcept>
0017 #include <boost/tokenizer.hpp>
0018 #include <boost/shared_ptr.hpp>
0019 #include <boost/throw_exception.hpp>
0020 #include <boost/date_time/compiler_config.hpp>
0021 #include <boost/date_time/time_zone_names.hpp>
0022 #include <boost/date_time/time_zone_base.hpp>
0023 #include <boost/date_time/time_parsing.hpp>
0024 #include <boost/algorithm/string.hpp>
0025
0026 namespace boost {
0027 namespace date_time {
0028
0029
0030 class data_not_accessible : public std::logic_error
0031 {
0032 public:
0033 data_not_accessible() :
0034 std::logic_error(std::string("Unable to locate or access the required datafile."))
0035 {}
0036 data_not_accessible(const std::string& filespec) :
0037 std::logic_error(std::string("Unable to locate or access the required datafile. Filespec: " + filespec))
0038 {}
0039 };
0040
0041
0042 class bad_field_count : public std::out_of_range
0043 {
0044 public:
0045 bad_field_count(const std::string& s) :
0046 std::out_of_range(s)
0047 {}
0048 };
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148 template<class time_zone_type, class rule_type>
0149 class tz_db_base {
0150 public:
0151
0152
0153
0154
0155
0156
0157
0158
0159 typedef char char_type;
0160
0161 typedef typename time_zone_type::base_type time_zone_base_type;
0162 typedef typename time_zone_type::time_duration_type time_duration_type;
0163 typedef time_zone_names_base<char_type> time_zone_names;
0164 typedef boost::date_time::dst_adjustment_offsets<time_duration_type> dst_adjustment_offsets;
0165 typedef std::basic_string<char_type> string_type;
0166
0167
0168 tz_db_base() {}
0169
0170
0171
0172 void load_from_stream(std::istream &in)
0173 {
0174 std::string buff;
0175 while( std::getline(in, buff)) {
0176 boost::trim_right(buff);
0177 parse_string(buff);
0178 }
0179 }
0180
0181
0182
0183 void load_from_file(const std::string& pathspec)
0184 {
0185 std::string buff;
0186
0187 std::ifstream ifs(pathspec.c_str());
0188 if(!ifs){
0189 boost::throw_exception(data_not_accessible(pathspec));
0190 }
0191 std::getline(ifs, buff);
0192 this->load_from_stream(ifs);
0193 }
0194
0195
0196
0197
0198
0199 bool add_record(const string_type& region,
0200 boost::shared_ptr<time_zone_base_type> tz)
0201 {
0202 typename map_type::value_type p(region, tz);
0203 return (m_zone_map.insert(p)).second;
0204 }
0205
0206
0207
0208
0209
0210 boost::shared_ptr<time_zone_base_type>
0211 time_zone_from_region(const string_type& region) const
0212 {
0213
0214 typename map_type::const_iterator record = m_zone_map.find(region);
0215 if(record == m_zone_map.end()){
0216 return boost::shared_ptr<time_zone_base_type>();
0217 }
0218 return record->second;
0219 }
0220
0221
0222 std::vector<std::string> region_list() const
0223 {
0224 typedef std::vector<std::string> vector_type;
0225 vector_type regions;
0226 typename map_type::const_iterator itr = m_zone_map.begin();
0227 while(itr != m_zone_map.end()) {
0228 regions.push_back(itr->first);
0229 ++itr;
0230 }
0231 return regions;
0232 }
0233
0234 private:
0235 typedef std::map<string_type, boost::shared_ptr<time_zone_base_type> > map_type;
0236 map_type m_zone_map;
0237
0238
0239 typedef typename rule_type::start_rule::week_num week_num;
0240
0241
0242
0243
0244
0245
0246 rule_type* parse_rules(const string_type& sr, const string_type& er) const
0247 {
0248
0249
0250 typedef typename rule_type::start_rule start_rule;
0251 typedef typename rule_type::end_rule end_rule;
0252
0253
0254 int s_nth = 0, s_d = 0, s_m = 0;
0255 int e_nth = 0, e_d = 0, e_m = 0;
0256 split_rule_spec(s_nth, s_d, s_m, sr);
0257 split_rule_spec(e_nth, e_d, e_m, er);
0258
0259 typename start_rule::week_num s_wn, e_wn;
0260 s_wn = get_week_num(s_nth);
0261 e_wn = get_week_num(e_nth);
0262
0263
0264 return new rule_type(start_rule(s_wn,
0265 static_cast<unsigned short>(s_d),
0266 static_cast<unsigned short>(s_m)),
0267 end_rule(e_wn,
0268 static_cast<unsigned short>(e_d),
0269 static_cast<unsigned short>(e_m)));
0270 }
0271
0272 week_num get_week_num(int nth) const
0273 {
0274 typedef typename rule_type::start_rule start_rule;
0275 switch(nth){
0276 case 1:
0277 return start_rule::first;
0278 case 2:
0279 return start_rule::second;
0280 case 3:
0281 return start_rule::third;
0282 case 4:
0283 return start_rule::fourth;
0284 case 5:
0285 case -1:
0286 return start_rule::fifth;
0287 default:
0288
0289 break;
0290 }
0291 return start_rule::fifth;
0292 }
0293
0294
0295 void split_rule_spec(int& nth, int& d, int& m, string_type rule) const
0296 {
0297 typedef boost::char_separator<char_type, std::char_traits<char_type> > char_separator_type;
0298 typedef boost::tokenizer<char_separator_type,
0299 std::basic_string<char_type>::const_iterator,
0300 std::basic_string<char_type> > tokenizer;
0301 typedef boost::tokenizer<char_separator_type,
0302 std::basic_string<char_type>::const_iterator,
0303 std::basic_string<char_type> >::iterator tokenizer_iterator;
0304
0305 const char_type sep_char[] = { ';', '\0'};
0306 char_separator_type sep(sep_char);
0307 tokenizer tokens(rule, sep);
0308
0309 if ( std::distance ( tokens.begin(), tokens.end ()) != 3 ) {
0310 std::ostringstream msg;
0311 msg << "Expecting 3 fields, got "
0312 << std::distance ( tokens.begin(), tokens.end ())
0313 << " fields in line: " << rule;
0314 boost::throw_exception(bad_field_count(msg.str()));
0315 }
0316
0317 tokenizer_iterator tok_iter = tokens.begin();
0318 nth = std::atoi(tok_iter->c_str()); ++tok_iter;
0319 d = std::atoi(tok_iter->c_str()); ++tok_iter;
0320 m = std::atoi(tok_iter->c_str());
0321 }
0322
0323
0324
0325
0326
0327
0328
0329 bool parse_string(string_type& s)
0330 {
0331 std::vector<string_type> result;
0332 typedef boost::token_iterator_generator<boost::escaped_list_separator<char_type>, string_type::const_iterator, string_type >::type token_iter_type;
0333
0334 token_iter_type i = boost::make_token_iterator<string_type>(s.begin(), s.end(),boost::escaped_list_separator<char_type>());
0335
0336 token_iter_type end;
0337 while (i != end) {
0338 result.push_back(*i);
0339 i++;
0340 }
0341
0342 enum db_fields { ID, STDABBR, STDNAME, DSTABBR, DSTNAME, GMTOFFSET,
0343 DSTADJUST, START_DATE_RULE, START_TIME, END_DATE_RULE,
0344 END_TIME, FIELD_COUNT };
0345
0346
0347 const unsigned int expected_fields = static_cast<unsigned int>(FIELD_COUNT);
0348 if (result.size() != expected_fields) {
0349 std::ostringstream msg;
0350 msg << "Expecting " << FIELD_COUNT << " fields, got "
0351 << result.size() << " fields in line: " << s;
0352 boost::throw_exception(bad_field_count(msg.str()));
0353 BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return false);
0354 }
0355
0356
0357 bool has_dst = true;
0358 if(result[DSTABBR] == std::string()){
0359 has_dst = false;
0360 }
0361
0362
0363
0364 time_zone_names names(result[STDNAME], result[STDABBR],
0365 result[DSTNAME], result[DSTABBR]);
0366
0367 time_duration_type utc_offset =
0368 str_from_delimited_time_duration<time_duration_type,char_type>(result[GMTOFFSET]);
0369
0370 dst_adjustment_offsets adjust(time_duration_type(0,0,0),
0371 time_duration_type(0,0,0),
0372 time_duration_type(0,0,0));
0373
0374 boost::shared_ptr<rule_type> rules;
0375
0376 if(has_dst){
0377 adjust = dst_adjustment_offsets(
0378 str_from_delimited_time_duration<time_duration_type,char_type>(result[DSTADJUST]),
0379 str_from_delimited_time_duration<time_duration_type,char_type>(result[START_TIME]),
0380 str_from_delimited_time_duration<time_duration_type,char_type>(result[END_TIME])
0381 );
0382
0383 rules =
0384 boost::shared_ptr<rule_type>(parse_rules(result[START_DATE_RULE],
0385 result[END_DATE_RULE]));
0386 }
0387 string_type id(result[ID]);
0388 boost::shared_ptr<time_zone_base_type> zone(new time_zone_type(names, utc_offset, adjust, rules));
0389 return (add_record(id, zone));
0390
0391 }
0392
0393 };
0394
0395 } }
0396
0397 #endif