ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

856 lines
33 KiB

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