1 // 2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 // 8 #define BOOST_LOCALE_SOURCE 9 #include <boost/config.hpp> 10 #ifdef BOOST_MSVC 11 # pragma warning(disable : 4996) 12 #endif 13 #include <locale> 14 #include <string> 15 #include <ios> 16 #include <boost/locale/date_time_facet.hpp> 17 #include <boost/locale/date_time.hpp> 18 #include <boost/locale/hold_ptr.hpp> 19 #include <stdlib.h> 20 #include <ctime> 21 #include <memory> 22 #include <algorithm> 23 #include <limits> 24 25 #include "timezone.hpp" 26 #include "gregorian.hpp" 27 28 namespace boost { 29 namespace locale { 30 namespace util { 31 namespace { 32 is_leap(int year)33 int is_leap(int year) 34 { 35 if(year % 400 == 0) 36 return 1; 37 if(year % 100 == 0) 38 return 0; 39 if(year % 4 == 0) 40 return 1; 41 return 0; 42 } 43 days_in_month(int year,int month)44 int days_in_month(int year,int month) 45 { 46 static const int tbl[2][12] = { 47 { 31,28,31,30,31,30,31,31,30,31,30,31 }, 48 { 31,29,31,30,31,30,31,31,30,31,30,31 } 49 }; 50 return tbl[is_leap(year)][month - 1]; 51 } 52 days_from_0(int year)53 inline int days_from_0(int year) 54 { 55 year--; 56 return 365 * year + (year / 400) - (year/100) + (year / 4); 57 } 58 days_from_1970(int year)59 int days_from_1970(int year) 60 { 61 static const int days_from_0_to_1970 = days_from_0(1970); 62 return days_from_0(year) - days_from_0_to_1970; 63 } 64 days_from_1jan(int year,int month,int day)65 int days_from_1jan(int year,int month,int day) 66 { 67 static const int days[2][12] = { 68 { 0,31,59,90,120,151,181,212,243,273,304,334 }, 69 { 0,31,60,91,121,152,182,213,244,274,305,335 } 70 }; 71 return days[is_leap(year)][month-1] + day - 1; 72 } 73 internal_timegm(std::tm const * t)74 std::time_t internal_timegm(std::tm const *t) 75 { 76 int year = t->tm_year + 1900; 77 int month = t->tm_mon; 78 if(month > 11) { 79 year += month/12; 80 month %= 12; 81 } 82 else if(month < 0) { 83 int years_diff = (-month + 11)/12; 84 year -= years_diff; 85 month+=12 * years_diff; 86 } 87 month++; 88 int day = t->tm_mday; 89 int day_of_year = days_from_1jan(year,month,day); 90 int days_since_epoch = days_from_1970(year) + day_of_year; 91 92 std::time_t seconds_in_day = 3600 * 24; 93 std::time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; 94 95 return result; 96 } 97 98 } // anon 99 100 101 102 103 namespace { 104 105 // Locale dependent data 106 comparator(char const * left,char const * right)107 bool comparator(char const *left,char const *right) 108 { 109 return strcmp(left,right) < 0; 110 } 111 112 // 113 // Ref: CLDR 1.9 common/supplemental/supplementalData.xml 114 // 115 // monday - default 116 // fri - MV 117 // sat - AE AF BH DJ DZ EG ER ET IQ IR JO KE KW LY MA OM QA SA SD SO SY TN YE 118 // sun - AR AS AZ BW CA CN FO GE GL GU HK IL IN JM JP KG KR LA MH MN MO MP MT NZ PH PK SG TH TT TW UM US UZ VI ZW 119 // 120 first_day_of_week(char const * terr)121 int first_day_of_week(char const *terr) { 122 static char const * const sat[] = { 123 "AE","AF","BH","DJ","DZ","EG","ER","ET","IQ","IR", 124 "JO","KE","KW","LY","MA","OM","QA","SA","SD","SO", 125 "SY","TN","YE" 126 }; 127 static char const * const sunday[] = { 128 "AR","AS","AZ","BW","CA","CN","FO","GE","GL","GU", 129 "HK","IL","IN","JM","JP","KG","KR","LA","MH","MN", 130 "MO","MP","MT","NZ","PH","PK","SG","TH","TT","TW", 131 "UM","US","UZ","VI","ZW" 132 }; 133 if(strcmp(terr,"MV") == 0) 134 return 5; // fri 135 if(std::binary_search<char const * const *>(sat,sat+sizeof(sat)/(sizeof(sat[0])),terr,comparator)) 136 return 6; // sat 137 if(std::binary_search<char const * const *>(sunday,sunday+sizeof(sunday)/(sizeof(sunday[0])),terr,comparator)) 138 return 0; // sun 139 // default 140 return 1; // mon 141 } 142 } 143 144 class gregorian_calendar : public abstract_calendar { 145 public: 146 gregorian_calendar(std::string const & terr)147 gregorian_calendar(std::string const &terr) 148 { 149 first_day_of_week_ = first_day_of_week(terr.c_str()); 150 time_ = std::time(0); 151 is_local_ = true; 152 tzoff_ = 0; 153 from_time(time_); 154 } 155 156 /// 157 /// Make a polymorphic copy of the calendar 158 /// clone() const159 virtual gregorian_calendar *clone() const 160 { 161 return new gregorian_calendar(*this); 162 } 163 164 /// 165 /// Set specific \a value for period \a p, note not all values are settable. 166 /// set_value(period::marks::period_mark p,int value)167 virtual void set_value(period::marks::period_mark p,int value) 168 { 169 using namespace period::marks; 170 switch(p) { 171 case era: ///< Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1] 172 return; 173 case year: ///< Year, it is calendar specific 174 case extended_year: ///< Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1. 175 tm_updated_.tm_year = value - 1900; 176 break; 177 case month: 178 tm_updated_.tm_mon = value; 179 break; 180 case day: 181 tm_updated_.tm_mday = value; 182 break; 183 case hour: ///< 24 clock hour [0..23] 184 tm_updated_.tm_hour = value; 185 break; 186 case hour_12: ///< 12 clock hour [0..11] 187 tm_updated_.tm_hour = tm_updated_.tm_hour / 12 * 12 + value; 188 break; 189 case am_pm: ///< am or pm marker, [0..1] 190 tm_updated_.tm_hour = 12 * value + tm_updated_.tm_hour % 12; 191 break; 192 case minute: ///< minute [0..59] 193 tm_updated_.tm_min = value; 194 break; 195 case second: 196 tm_updated_.tm_sec = value; 197 break; 198 case day_of_year: 199 normalize(); 200 tm_updated_.tm_mday += (value - (tm_updated_.tm_yday + 1)); 201 break; 202 case day_of_week: ///< Day of week, starting from Sunday, [1..7] 203 if(value < 1) // make sure it is positive 204 value += (-value / 7) * 7 + 7; 205 // convert to local DOW 206 value = (value - 1 - first_day_of_week_ + 14) % 7 + 1; 207 // fall throght 208 case day_of_week_local: ///< Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7] 209 normalize(); 210 tm_updated_.tm_mday += (value - 1) - (tm_updated_.tm_wday - first_day_of_week_ + 7) % 7; 211 break; 212 case day_of_week_in_month: ///< Original number of the day of the week in month. (1st sunday, 2nd sunday etc) 213 case week_of_year: ///< The week number in the year, 4 is the minimal number of days to be in month 214 case week_of_month: ///< The week number withing current month 215 { 216 normalize(); 217 int current_week = get_value(p,current); 218 int diff = 7 * (value - current_week); 219 tm_updated_.tm_mday += diff; 220 } 221 break; 222 case period::marks::first_day_of_week: ///< For example Sunday in US, Monday in France 223 default: 224 return; 225 } 226 normalized_ = false; 227 } 228 normalize()229 void normalize() 230 { 231 if(!normalized_) { 232 std::tm val = tm_updated_; 233 val.tm_isdst = -1; 234 val.tm_wday = -1; // indecator of error 235 std::time_t point = -1; 236 if(is_local_) { 237 point = std::mktime(&val); 238 if(point == static_cast<std::time_t>(-1)){ 239 #ifndef BOOST_WINDOWS 240 // windows does not handle negative time_t, under other plaforms 241 // it may be actually valid value in 1969-12-31 23:59:59 242 // so we check that a filed was updated - does not happen in case of error 243 if(val.tm_wday == -1) 244 #endif 245 { 246 throw date_time_error("boost::locale::gregorian_calendar: invalid time"); 247 } 248 } 249 } 250 else { 251 point = internal_timegm(&val); 252 #ifdef BOOST_WINDOWS 253 // Windows uses TLS, thread safe 254 std::tm *revert_point = 0; 255 if(point < 0 || (revert_point = gmtime(&point)) == 0) 256 throw date_time_error("boost::locale::gregorian_calendar time is out of range"); 257 val = *revert_point; 258 #else 259 if(!gmtime_r(&point,&val)) 260 throw date_time_error("boost::locale::gregorian_calendar invalid time"); 261 #endif 262 263 } 264 265 time_ = point - tzoff_; 266 tm_ = val; 267 tm_updated_ = val; 268 normalized_ = true; 269 } 270 } 271 get_week_number(int day,int wday) const272 int get_week_number(int day,int wday) const 273 { 274 /// 275 /// This is the number of days that are considered withing 276 /// period such that the week belongs there 277 /// 278 static const int days_in_full_week = 4; 279 280 281 // Alaways use local week start 282 int current_dow = (wday - first_day_of_week_ + 7) % 7; 283 // Calculate local week day of Jan 1st. 284 int first_week_day = (current_dow + 700 - day) % 7; 285 // adding something big devidable by 7 286 287 int start_of_period_in_weeks; 288 if(first_week_day < days_in_full_week) { 289 start_of_period_in_weeks = - first_week_day; 290 } 291 else { 292 start_of_period_in_weeks = 7 - first_week_day; 293 } 294 int week_number_in_days = day - start_of_period_in_weeks; 295 if(week_number_in_days < 0) 296 return -1; 297 return week_number_in_days / 7 + 1; 298 } 299 300 /// 301 /// Get specific value for period \a p according to a value_type \a v 302 /// get_value(period::marks::period_mark p,value_type v) const303 virtual int get_value(period::marks::period_mark p,value_type v) const 304 { 305 using namespace period::marks; 306 switch(p) { 307 case era: 308 return 1; 309 case year: 310 case extended_year: 311 switch(v) { 312 case absolute_minimum: 313 case greatest_minimum: 314 case actual_minimum: 315 #ifdef BOOST_WINDOWS 316 return 1970; // Unix epoch windows can't handle negative time_t 317 #else 318 if(sizeof(std::time_t) == 4) 319 return 1901; // minimal year with 32 bit time_t 320 else 321 return 1; 322 #endif 323 case absolute_maximum: 324 case least_maximum: 325 case actual_maximum: 326 if(sizeof(std::time_t) == 4) 327 return 2038; // Y2K38 - maximal with 32 bit time_t 328 else 329 return std::numeric_limits<int>::max(); 330 case current: 331 return tm_.tm_year + 1900; 332 }; 333 break; 334 case month: 335 switch(v) { 336 case absolute_minimum: 337 case greatest_minimum: 338 case actual_minimum: 339 return 0; 340 case absolute_maximum: 341 case least_maximum: 342 case actual_maximum: 343 return 11; 344 case current: 345 return tm_.tm_mon; 346 }; 347 break; 348 case day: 349 switch(v) { 350 case absolute_minimum: 351 case greatest_minimum: 352 case actual_minimum: 353 return 1; 354 case absolute_maximum: 355 return 31; 356 case least_maximum: 357 return 28; 358 case actual_maximum: 359 return days_in_month(tm_.tm_year + 1900,tm_.tm_mon + 1); 360 case current: 361 return tm_.tm_mday; 362 }; 363 break; 364 case day_of_year: ///< The number of day in year, starting from 1 365 switch(v) { 366 case absolute_minimum: 367 case greatest_minimum: 368 case actual_minimum: 369 return 1; 370 case absolute_maximum: 371 return 366; 372 case least_maximum: 373 return 365; 374 case actual_maximum: 375 return is_leap(tm_.tm_year + 1900) ? 366 : 365; 376 case current: 377 return tm_.tm_yday + 1; 378 } 379 break; 380 case day_of_week: ///< Day of week, starting from Sunday, [1..7] 381 switch(v) { 382 case absolute_minimum: 383 case greatest_minimum: 384 case actual_minimum: 385 return 1; 386 case absolute_maximum: 387 case least_maximum: 388 case actual_maximum: 389 return 7; 390 case current: 391 return tm_.tm_wday + 1; 392 } 393 break; 394 case day_of_week_local: ///< Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7] 395 switch(v) { 396 case absolute_minimum: 397 case greatest_minimum: 398 case actual_minimum: 399 return 1; 400 case absolute_maximum: 401 case least_maximum: 402 case actual_maximum: 403 return 7; 404 case current: 405 return (tm_.tm_wday - first_day_of_week_ + 7) % 7 + 1; 406 } 407 break; 408 case hour: ///< 24 clock hour [0..23] 409 switch(v) { 410 case absolute_minimum: 411 case greatest_minimum: 412 case actual_minimum: 413 return 0; 414 case absolute_maximum: 415 case least_maximum: 416 case actual_maximum: 417 return 23; 418 case current: 419 return tm_.tm_hour; 420 } 421 break; 422 case hour_12: ///< 12 clock hour [0..11] 423 switch(v) { 424 case absolute_minimum: 425 case greatest_minimum: 426 case actual_minimum: 427 return 0; 428 case absolute_maximum: 429 case least_maximum: 430 case actual_maximum: 431 return 11; 432 case current: 433 return tm_.tm_hour % 12; 434 } 435 break; 436 case am_pm: ///< am or pm marker, [0..1] 437 switch(v) { 438 case absolute_minimum: 439 case greatest_minimum: 440 case actual_minimum: 441 return 0; 442 case absolute_maximum: 443 case least_maximum: 444 case actual_maximum: 445 return 1; 446 case current: 447 return tm_.tm_hour >= 12 ? 1 : 0; 448 } 449 break; 450 case minute: ///< minute [0..59] 451 switch(v) { 452 case absolute_minimum: 453 case greatest_minimum: 454 case actual_minimum: 455 return 0; 456 case absolute_maximum: 457 case least_maximum: 458 case actual_maximum: 459 return 59; 460 case current: 461 return tm_.tm_min; 462 } 463 break; 464 case second: ///< second [0..59] 465 switch(v) { 466 case absolute_minimum: 467 case greatest_minimum: 468 case actual_minimum: 469 return 0; 470 case absolute_maximum: 471 case least_maximum: 472 case actual_maximum: 473 return 59; 474 case current: 475 return tm_.tm_sec; 476 } 477 break; 478 case period::marks::first_day_of_week: ///< For example Sunday in US, Monday in France 479 return first_day_of_week_ + 1; 480 481 case week_of_year: ///< The week number in the year 482 switch(v) { 483 case absolute_minimum: 484 case greatest_minimum: 485 case actual_minimum: 486 return 1; 487 case absolute_maximum: 488 return 53; 489 case least_maximum: 490 return 52; 491 case actual_maximum: 492 { 493 int year = tm_.tm_year + 1900; 494 int end_of_year_days = (is_leap(year) ? 366 : 365) - 1; 495 int dow_of_end_of_year = (end_of_year_days - tm_.tm_yday + tm_.tm_wday) % 7; 496 return get_week_number(end_of_year_days,dow_of_end_of_year); 497 } 498 case current: 499 { 500 int val = get_week_number(tm_.tm_yday,tm_.tm_wday); 501 if(val < 0) 502 return 53; 503 return val; 504 } 505 } 506 case week_of_month: ///< The week number withing current month 507 switch(v) { 508 case absolute_minimum: 509 case greatest_minimum: 510 case actual_minimum: 511 return 1; 512 case absolute_maximum: 513 return 5; 514 case least_maximum: 515 return 4; 516 case actual_maximum: 517 { 518 int end_of_month_days = days_in_month(tm_.tm_year + 1900,tm_.tm_mon + 1); 519 int dow_of_end_of_month = (end_of_month_days - tm_.tm_mday + tm_.tm_wday) % 7; 520 return get_week_number(end_of_month_days,dow_of_end_of_month); 521 } 522 case current: 523 { 524 int val = get_week_number(tm_.tm_mday,tm_.tm_wday); 525 if(val < 0) 526 return 5; 527 return val; 528 } 529 } 530 531 case day_of_week_in_month: ///< Original number of the day of the week in month. 532 switch(v) { 533 case absolute_minimum: 534 case greatest_minimum: 535 case actual_minimum: 536 return 1; 537 case absolute_maximum: 538 return 5; 539 case least_maximum: 540 return 4; 541 case actual_maximum: 542 if(tm_.tm_mon == 1 && !is_leap(tm_.tm_year + 1900)) { 543 // only in february in non leap year is 28 days, the rest 544 // conver more then 4 weeks 545 return 4; 546 } 547 return 5; 548 case current: 549 return (tm_.tm_mday - 1) / 7 + 1; 550 default: 551 ; 552 } 553 default: 554 ; 555 } 556 return 0; 557 558 } 559 560 /// 561 /// Set current time point 562 /// set_time(posix_time const & p)563 virtual void set_time(posix_time const &p) 564 { 565 from_time(static_cast<std::time_t>(p.seconds)); 566 } get_time() const567 virtual posix_time get_time() const 568 { 569 posix_time pt = { time_, 0}; 570 return pt; 571 } 572 573 /// 574 /// Set option for calendar, for future use 575 /// set_option(calendar_option_type opt,int)576 virtual void set_option(calendar_option_type opt,int /*v*/) 577 { 578 switch(opt) { 579 case is_gregorian: 580 throw date_time_error("is_gregorian is not settable options for calendar"); 581 case is_dst: 582 throw date_time_error("is_dst is not settable options for calendar"); 583 default: 584 ; 585 } 586 } 587 /// 588 /// Get option for calendar, currently only check if it is Gregorian calendar 589 /// get_option(calendar_option_type opt) const590 virtual int get_option(calendar_option_type opt) const 591 { 592 switch(opt) { 593 case is_gregorian: 594 return 1; 595 case is_dst: 596 return tm_.tm_isdst == 1; 597 default: 598 return 0; 599 }; 600 } 601 602 /// 603 /// Adjust period's \a p value by \a difference items using a update_type \a u. 604 /// Note: not all values are adjustable 605 /// adjust_value(period::marks::period_mark p,update_type u,int difference)606 virtual void adjust_value(period::marks::period_mark p,update_type u,int difference) 607 { 608 switch(u) { 609 case move: 610 { 611 using namespace period::marks; 612 switch(p) { 613 case year: ///< Year, it is calendar specific 614 case extended_year: ///< Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1. 615 tm_updated_.tm_year +=difference; 616 break; 617 case month: 618 tm_updated_.tm_mon +=difference; 619 break; 620 case day: 621 case day_of_year: 622 case day_of_week: ///< Day of week, starting from Sunday, [1..7] 623 case day_of_week_local: ///< Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7] 624 tm_updated_.tm_mday +=difference; 625 break; 626 case hour: ///< 24 clock hour [0..23] 627 case hour_12: ///< 12 clock hour [0..11] 628 tm_updated_.tm_hour += difference; 629 break; 630 case am_pm: ///< am or pm marker, [0..1] 631 tm_updated_.tm_hour += 12 * difference; 632 break; 633 case minute: ///< minute [0..59] 634 tm_updated_.tm_min += difference; 635 break; 636 case second: 637 tm_updated_.tm_sec += difference; 638 break; 639 case week_of_year: ///< The week number in the year 640 case week_of_month: ///< The week number withing current month 641 case day_of_week_in_month: ///< Original number of the day of the week in month. 642 tm_updated_.tm_mday +=difference * 7; 643 break; 644 default: 645 ; // Not all values are adjustable 646 } 647 normalized_ = false; 648 normalize(); 649 } 650 break; 651 case roll: 652 { // roll 653 int cur_min = get_value(p,actual_minimum); 654 int cur_max = get_value(p,actual_maximum); 655 int max_diff = cur_max - cur_min + 1; 656 if(max_diff > 0) { 657 int value = get_value(p,current); 658 int addon = 0; 659 if(difference < 0) 660 addon = ((-difference/max_diff) + 1) * max_diff; 661 value = (value - cur_min + difference + addon) % max_diff + cur_min; 662 set_value(p,value); 663 normalize(); 664 } 665 } 666 default: 667 ; 668 } 669 } 670 get_diff(period::marks::period_mark p,int diff,gregorian_calendar const * other) const671 int get_diff(period::marks::period_mark p,int diff,gregorian_calendar const *other) const 672 { 673 if(diff == 0) 674 return 0; 675 hold_ptr<gregorian_calendar> self(clone()); 676 self->adjust_value(p,move,diff); 677 if(diff > 0){ 678 if(self->time_ > other->time_) 679 return diff - 1; 680 else 681 return diff; 682 } 683 else { 684 if(self->time_ < other->time_) 685 return diff + 1; 686 else 687 return diff; 688 } 689 } 690 691 /// 692 /// Calculate the difference between this calendar and \a other in \a p units 693 /// difference(abstract_calendar const * other_cal,period::marks::period_mark p) const694 virtual int difference(abstract_calendar const *other_cal,period::marks::period_mark p) const 695 { 696 hold_ptr<gregorian_calendar> keeper; 697 gregorian_calendar const *other = dynamic_cast<gregorian_calendar const *>(other_cal); 698 if(!other) { 699 keeper.reset(clone()); 700 keeper->set_time(other_cal->get_time()); 701 other = keeper.get(); 702 } 703 704 int factor = 1; // for weeks vs days handling 705 706 using namespace period::marks; 707 switch(p) { 708 case era: 709 return 0; 710 case year: 711 case extended_year: 712 { 713 int diff = other->tm_.tm_year - tm_.tm_year; 714 return get_diff(period::marks::year,diff,other); 715 } 716 case month: 717 { 718 int diff = 12 * (other->tm_.tm_year - tm_.tm_year) 719 + other->tm_.tm_mon - tm_.tm_mon; 720 return get_diff(period::marks::month,diff,other); 721 } 722 case day_of_week_in_month: 723 case week_of_month: 724 case week_of_year: 725 factor = 7; 726 // fall 727 case day: 728 case day_of_year: 729 case day_of_week: 730 case day_of_week_local: 731 { 732 int diff = other->tm_.tm_yday - tm_.tm_yday; 733 if(other->tm_.tm_year != tm_.tm_year) { 734 diff += days_from_0(other->tm_.tm_year + 1900) - 735 days_from_0(tm_.tm_year + 1900); 736 } 737 return get_diff(period::marks::day,diff,other) / factor; 738 } 739 case am_pm: 740 return static_cast<int>( (other->time_ - time_) / (3600*12) ); 741 case hour: 742 case hour_12: 743 return static_cast<int>( (other->time_ - time_) / 3600 ); 744 case minute: 745 return static_cast<int>( (other->time_ - time_) / 60 ); 746 case second: 747 return static_cast<int>( other->time_ - time_ ); 748 default: 749 return 0; 750 }; 751 } 752 753 /// 754 /// Set time zone, empty - use system 755 /// set_timezone(std::string const & tz)756 virtual void set_timezone(std::string const &tz) 757 { 758 if(tz.empty()) { 759 is_local_ = true; 760 tzoff_ = 0; 761 } 762 else { 763 is_local_ = false; 764 tzoff_ = parse_tz(tz); 765 } 766 from_time(time_); 767 time_zone_name_ = tz; 768 } get_timezone() const769 virtual std::string get_timezone() const 770 { 771 return time_zone_name_; 772 } 773 same(abstract_calendar const * other) const774 virtual bool same(abstract_calendar const *other) const 775 { 776 gregorian_calendar const *gcal = dynamic_cast<gregorian_calendar const *>(other); 777 if(!gcal) 778 return false; 779 return 780 gcal->tzoff_ == tzoff_ 781 && gcal->is_local_ == is_local_ 782 && gcal->first_day_of_week_ == first_day_of_week_; 783 } 784 ~gregorian_calendar()785 virtual ~gregorian_calendar() 786 { 787 } 788 789 private: 790 from_time(std::time_t point)791 void from_time(std::time_t point) 792 { 793 std::time_t real_point = point + tzoff_; 794 std::tm *t = 0; 795 #ifdef BOOST_WINDOWS 796 // Windows uses TLS, thread safe 797 t = is_local_ ? localtime(&real_point) : gmtime(&real_point); 798 #else 799 std::tm tmp_tm; 800 t = is_local_ ? localtime_r(&real_point,&tmp_tm) : gmtime_r(&real_point,&tmp_tm); 801 #endif 802 if(!t) { 803 throw date_time_error("boost::locale::gregorian_calendar: invalid time point"); 804 } 805 tm_ = *t; 806 tm_updated_ = *t; 807 normalized_ = true; 808 time_ = point; 809 } 810 int first_day_of_week_; 811 std::time_t time_; 812 std::tm tm_; 813 std::tm tm_updated_; 814 bool normalized_; 815 bool is_local_; 816 int tzoff_; 817 std::string time_zone_name_; 818 819 }; 820 create_gregorian_calendar(std::string const & terr)821 abstract_calendar *create_gregorian_calendar(std::string const &terr) 822 { 823 return new gregorian_calendar(terr); 824 } 825 826 class gregorian_facet : public calendar_facet { 827 public: gregorian_facet(std::string const & terr,size_t refs=0)828 gregorian_facet(std::string const &terr,size_t refs = 0) : 829 calendar_facet(refs), 830 terr_(terr) 831 { 832 } create_calendar() const833 virtual abstract_calendar *create_calendar() const 834 { 835 return create_gregorian_calendar(terr_); 836 } 837 private: 838 std::string terr_; 839 }; 840 install_gregorian_calendar(std::locale const & in,std::string const & terr)841 std::locale install_gregorian_calendar(std::locale const &in,std::string const &terr) 842 { 843 return std::locale(in,new gregorian_facet(terr)); 844 } 845 846 847 } // util 848 } // locale 849 } //boost 850 851 852 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 853