]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/locale/src/icu/date_time.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / locale / src / icu / date_time.cpp
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/locale/date_time_facet.hpp>
10 #include <boost/locale/date_time.hpp>
11 #include <boost/locale/formatting.hpp>
12 #include "all_generator.hpp"
13
14 #include <boost/thread.hpp>
15 #include <unicode/calendar.h>
16 #include <unicode/gregocal.h>
17 #include <unicode/utypes.h>
18
19 #include <memory>
20 #include <math.h>
21
22 #include "cdata.hpp"
23 #include "uconv.hpp"
24 #include "time_zone.hpp"
25
26 #include <iostream>
27
28
29 namespace boost {
30 namespace locale {
31 namespace impl_icu {
32
33 static void check_and_throw_dt(UErrorCode &e)
34 {
35 if(U_FAILURE(e)) {
36 date_time_error(u_errorName(e));
37 }
38 }
39 using period::marks::period_mark;
40
41 static UCalendarDateFields to_icu(period::marks::period_mark f)
42 {
43 using namespace period::marks;
44
45 switch(f) {
46 case era: return UCAL_ERA;
47 case year: return UCAL_YEAR;
48 case extended_year: return UCAL_EXTENDED_YEAR;
49 case month: return UCAL_MONTH;
50 case day: return UCAL_DATE;
51 case day_of_year: return UCAL_DAY_OF_YEAR;
52 case day_of_week: return UCAL_DAY_OF_WEEK;
53 case day_of_week_in_month: return UCAL_DAY_OF_WEEK_IN_MONTH;
54 case day_of_week_local: return UCAL_DOW_LOCAL;
55 case hour: return UCAL_HOUR_OF_DAY;
56 case hour_12: return UCAL_HOUR;
57 case am_pm: return UCAL_AM_PM;
58 case minute: return UCAL_MINUTE;
59 case second: return UCAL_SECOND;
60 case week_of_year: return UCAL_WEEK_OF_YEAR;
61 case week_of_month: return UCAL_WEEK_OF_MONTH;
62 default:
63 throw std::invalid_argument("Invalid date_time period type");
64 }
65 }
66
67
68 class calendar_impl : public abstract_calendar {
69 public:
70
71 calendar_impl(cdata const &dat)
72 {
73 UErrorCode err=U_ZERO_ERROR;
74 calendar_.reset(icu::Calendar::createInstance(dat.locale,err));
75 check_and_throw_dt(err);
76 #if U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM < 402
77 // workaround old/invalid data, it should be 4 in general
78 calendar_->setMinimalDaysInFirstWeek(4);
79 #endif
80 encoding_ = dat.encoding;
81 }
82 calendar_impl(calendar_impl const &other)
83 {
84 calendar_.reset(other.calendar_->clone());
85 encoding_ = other.encoding_;
86 }
87
88 calendar_impl *clone() const
89 {
90 return new calendar_impl(*this);
91 }
92
93 void set_value(period::marks::period_mark p,int value)
94 {
95 calendar_->set(to_icu(p),int32_t(value));
96 }
97
98 int get_value(period::marks::period_mark p,value_type type) const
99 {
100 UErrorCode err=U_ZERO_ERROR;
101 int v=0;
102 if(p==period::marks::first_day_of_week) {
103 guard l(lock_);
104 v=calendar_->getFirstDayOfWeek(err);
105 }
106 else {
107 UCalendarDateFields uper=to_icu(p);
108 guard l(lock_);
109 switch(type) {
110 case absolute_minimum:
111 v=calendar_->getMinimum(uper);
112 break;
113 case actual_minimum:
114 v=calendar_->getActualMinimum(uper,err);
115 break;
116 case greatest_minimum:
117 v=calendar_->getGreatestMinimum(uper);
118 break;
119 case current:
120 v=calendar_->get(uper,err);
121 break;
122 case least_maximum:
123 v=calendar_->getLeastMaximum(uper);
124 break;
125 case actual_maximum:
126 v=calendar_->getActualMaximum(uper,err);
127 break;
128 case absolute_maximum:
129 v=calendar_->getMaximum(uper);
130 break;
131 }
132 }
133 check_and_throw_dt(err);
134 return v;
135 }
136
137 virtual void set_time(posix_time const &p)
138 {
139 double utime = p.seconds * 1000.0 + p.nanoseconds / 1000000.0;
140 UErrorCode code=U_ZERO_ERROR;
141 calendar_->setTime(utime,code);
142 check_and_throw_dt(code);
143 }
144 virtual void normalize()
145 {
146 // Can't call complete() explicitly (protected)
147 // calling get wich calls complete
148 UErrorCode code=U_ZERO_ERROR;
149 calendar_->get(UCAL_YEAR,code);
150 check_and_throw_dt(code);
151 }
152 virtual posix_time get_time() const
153 {
154
155 UErrorCode code=U_ZERO_ERROR;
156 double rtime = 0;
157 {
158 guard l(lock_);
159 rtime = calendar_->getTime(code);
160 }
161 check_and_throw_dt(code);
162 rtime/=1000.0;
163 double secs = floor(rtime);
164 posix_time res;
165 res.seconds = static_cast<int64_t>(secs);
166 res.nanoseconds = static_cast<uint32_t>((rtime - secs) / 1e9);
167 if(res.nanoseconds > 999999999)
168 res.nanoseconds = 999999999;
169 return res;
170 }
171 virtual void set_option(calendar_option_type opt,int /*v*/)
172 {
173 switch(opt) {
174 case is_gregorian:
175 throw date_time_error("is_gregorian is not settable options for calendar");
176 case is_dst:
177 throw date_time_error("is_dst is not settable options for calendar");
178 default:
179 ;
180 }
181 }
182 virtual int get_option(calendar_option_type opt) const
183 {
184 switch(opt) {
185 case is_gregorian:
186 return dynamic_cast<icu::GregorianCalendar const *>(calendar_.get())!=0;
187 case is_dst:
188 {
189 guard l(lock_);
190 UErrorCode err = U_ZERO_ERROR;
191 bool res = ( calendar_->inDaylightTime(err) != 0 );
192 check_and_throw_dt(err);
193 return res;
194 }
195 default:
196 return 0;
197 }
198 }
199 virtual void adjust_value(period::marks::period_mark p,update_type u,int difference)
200 {
201 UErrorCode err=U_ZERO_ERROR;
202 switch(u) {
203 case move:
204 calendar_->add(to_icu(p),difference,err);
205 break;
206 case roll:
207 calendar_->roll(to_icu(p),difference,err);
208 break;
209 }
210 check_and_throw_dt(err);
211 }
212 virtual int difference(abstract_calendar const *other_ptr,period::marks::period_mark p) const
213 {
214 UErrorCode err=U_ZERO_ERROR;
215 double other_time = 0;
216 //
217 // fieldDifference has side effect of moving calendar (WTF?)
218 // So we clone it for performing this operation
219 //
220 std::auto_ptr<icu::Calendar> self(calendar_->clone());
221
222 calendar_impl const *other_cal=dynamic_cast<calendar_impl const *>(other_ptr);
223 if(other_cal){
224 guard l(other_cal->lock_);
225 other_time = other_cal->calendar_->getTime(err);
226 check_and_throw_dt(err);
227 }
228 else {
229 posix_time p = other_ptr->get_time();
230 other_time = p.seconds * 1000.0 + p.nanoseconds / 1000000.0;
231 }
232
233 int diff = self->fieldDifference(other_time,to_icu(p),err);
234
235 check_and_throw_dt(err);
236 return diff;
237 }
238 virtual void set_timezone(std::string const &tz)
239 {
240 calendar_->adoptTimeZone(get_time_zone(tz));
241 }
242 virtual std::string get_timezone() const
243 {
244 icu::UnicodeString tz;
245 calendar_->getTimeZone().getID(tz);
246 icu_std_converter<char> cvt(encoding_);
247 return cvt.std(tz);
248 }
249 virtual bool same(abstract_calendar const *other) const
250 {
251 calendar_impl const *oc=dynamic_cast<calendar_impl const *>(other);
252 if(!oc)
253 return false;
254 return calendar_->isEquivalentTo(*oc->calendar_)!=0;
255 }
256
257 private:
258 typedef boost::unique_lock<boost::mutex> guard;
259 mutable boost::mutex lock_;
260 std::string encoding_;
261 hold_ptr<icu::Calendar> calendar_;
262 };
263
264 class icu_calendar_facet : public calendar_facet {
265 public:
266 icu_calendar_facet(cdata const &d,size_t refs = 0) :
267 calendar_facet(refs),
268 data_(d)
269 {
270 }
271 virtual abstract_calendar *create_calendar() const
272 {
273 return new calendar_impl(data_);
274 }
275 private:
276 cdata data_;
277 };
278
279 std::locale create_calendar(std::locale const &in,cdata const &d)
280 {
281 return std::locale(in,new icu_calendar_facet(d));
282 }
283
284 } // impl_icu
285 } // locale
286 } // boost
287
288
289
290 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
291