1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/picker/picker_data.h"
17
18 #include "base/i18n/localization.h"
19
20 namespace OHOS::Ace {
21
Current()22 PickerDate PickerDate::Current()
23 {
24 PickerDate date;
25 auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
26 auto local = std::localtime(&now);
27 if (local == nullptr) {
28 LOGE("get localtime failed.");
29 return date;
30 }
31 date.SetYear(local->tm_year + 1900); // local date start from 1900
32 date.SetMonth(local->tm_mon + 1); // local month start from 0 to 11, need add one.
33 date.SetDay(local->tm_mday);
34 date.SetWeek(local->tm_wday);
35 return date;
36 }
37
GetMaxDay(uint32_t year,uint32_t month)38 uint32_t PickerDate::GetMaxDay(uint32_t year, uint32_t month)
39 {
40 if (month == 2) { // days count in february is different between leap year and other.
41 bool leapYear = IsLeapYear(year);
42 return (leapYear ? 29 : 28); // leap year's february has 29 days, other has 28 days.
43 }
44
45 switch (month) {
46 case 1: // january
47 case 3: // march
48 case 5: // may
49 case 7: // july
50 case 8: // august
51 case 10: // october
52 case 12: // december
53 return 31; // upper months has 31 days
54 default:
55 return 30; // other month has 30 days
56 }
57 }
58
IsLeapYear(uint32_t year)59 bool PickerDate::IsLeapYear(uint32_t year)
60 {
61 if (year % 100 == 0) { // special case: year can divided by 100
62 return (year % 400 == 0); // leap year equal that can divided by 400.
63 }
64
65 return (year % 4 == 0); // other case, leap year equal that can divided by 4.
66 }
67
ToString(bool jsonFormat,int32_t status) const68 std::string PickerDate::ToString(bool jsonFormat, int32_t status) const
69 {
70 if (!jsonFormat) {
71 DateTime date;
72 date.year = year_;
73 date.month = month_ ? month_ - 1 : 0; // W3C's month start from 0 to 11
74 date.day = day_;
75 return Localization::GetInstance()->FormatDateTime(date, DateTimeStyle::FULL, DateTimeStyle::NONE);
76 }
77
78 return std::string("{\"year\":") + std::to_string(year_) + ",\"month\":" + std::to_string(month_) +
79 ",\"day\":" + std::to_string(day_) + ",\"status\":" + std::to_string(status) + "}";
80 }
81
ToDays() const82 uint32_t PickerDate::ToDays() const
83 {
84 uint32_t days = 0;
85 days += day_ ? day_ - 1 : 0; // day start from 1
86 // month start from 1
87 for (uint32_t month = 1; month < month_; ++month) {
88 days += PickerDate::GetMaxDay(year_, month);
89 }
90 // year start from 1900 or 1
91 uint32_t startYear = 1900;
92 if (year_ < startYear) {
93 startYear = 1;
94 }
95 for (uint32_t year = startYear; year < year_; ++year) {
96 // leap year has 366 days, other year has 365 days.
97 days += (PickerDate::IsLeapYear(year) ? 366 : 365);
98 }
99 return days;
100 }
101
FromDays(uint32_t days)102 void PickerDate::FromDays(uint32_t days)
103 {
104 for (year_ = 1900; year_ <= 2100; ++year_) { // year start from 1900 to 2100.
105 // leap year has 366 days, other year has 365 days;
106 uint32_t daysInYear = (PickerDate::IsLeapYear(year_) ? 366 : 365);
107 if (days < daysInYear) {
108 break;
109 } else {
110 days -= daysInYear;
111 }
112 }
113
114 for (month_ = 1; month_ <= 12; ++month_) { // month start from 1 to 12
115 uint32_t daysInMonth = PickerDate::GetMaxDay(year_, month_);
116 if (days < daysInMonth) {
117 break;
118 } else {
119 days -= daysInMonth;
120 }
121 }
122
123 day_ = days + 1; // days is index start form 0 and day start form 1.
124 }
125
Current()126 PickerTime PickerTime::Current()
127 {
128 PickerTime time;
129 auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
130 auto local = std::localtime(&now);
131 if (local == nullptr) {
132 LOGE("get localtime failed.");
133 return time;
134 }
135 time.SetHour(local->tm_hour);
136 time.SetMinute(local->tm_min);
137 time.SetSecond(local->tm_sec);
138 return time;
139 }
140
ToString(bool jsonFormat,bool hasSecond,int32_t status) const141 std::string PickerTime::ToString(bool jsonFormat, bool hasSecond, int32_t status) const
142 {
143 if (!jsonFormat) {
144 if (!hasSecond) {
145 // use char ':' to split.
146 return std::to_string(hour_) + ":" + std::to_string(minute_);
147 }
148 // use char ':' to split.
149 return std::to_string(hour_) + ":" + std::to_string(minute_) + ":" + std::to_string(second_);
150 }
151
152 if (!hasSecond) {
153 // use json format chars
154 return std::string("{\"hour\":") + std::to_string(hour_) + ",\"minute\":" + std::to_string(minute_) +
155 ",\"status\":" + std::to_string(status) + "}";
156 }
157 // use json format chars
158 return std::string("{\"hour\":") + std::to_string(hour_) + ",\"minute\":" + std::to_string(minute_) +
159 ",\"second\":" + std::to_string(second_) + ",\"status\":" + std::to_string(status) + "}";
160 }
161
Current()162 PickerDateTime PickerDateTime::Current()
163 {
164 PickerDateTime dateTime;
165 dateTime.SetDate(PickerDate::Current());
166 dateTime.SetTime(PickerTime::Current());
167 return dateTime;
168 }
169
ToString(bool jsonFormat,int32_t status) const170 std::string PickerDateTime::ToString(bool jsonFormat, int32_t status) const
171 {
172 if (!jsonFormat) {
173 return date_.ToString(jsonFormat);
174 }
175
176 return std::string("{\"year\":") + std::to_string(date_.GetYear()) +
177 ",\"month\":" + std::to_string(date_.GetMonth()) +
178 ",\"day\":" + std::to_string(date_.GetDay()) +
179 ",\"hour\":" + std::to_string(time_.GetHour()) +
180 ",\"minute\":" + std::to_string(time_.GetMinute()) +
181 ",\"status\":" + std::to_string(status) + "}";
182 }
183
184 /*
185 * Lunar information in 200 years from 1900.
186 * <p>
187 * | 0 - 11(bit) | 12 - 15(bit) |
188 * month leap month
189 * If last 4bit is 1111 or 0000 means no leap month.
190 * If the last 4bit in next data is 1111, the days of leap month is 30 days,
191 * otherwise, the days of leap month is 29days.
192 */
193 const uint16_t LunarCalculator::LUNAR_INFO[] = {
194 0x6aa0, 0xbaa3, 0xab50,
195 0x4bd8, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x5554, 0x56af,
196 0x9ad0, 0x55d2, 0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0xd295, 0xb54f,
197 0xd6a0, 0xada2, 0x95b0, 0x4977, 0x497f, 0xa4b0, 0xb4b5, 0x6a50,
198 0x6d40, 0xab54, 0x2b6f, 0x9570, 0x52f2, 0x4970, 0x6566, 0xd4a0,
199 0xea50, 0x6a95, 0x5adf, 0x2b60, 0x86e3, 0x92ef, 0xc8d7, 0xc95f,
200 0xd4a0, 0xd8a6, 0xb55f, 0x56a0, 0xa5b4, 0x25df, 0x92d0, 0xd2b2,
201 0xa950, 0xb557, 0x6ca0, 0xb550, 0x5355, 0x4daf, 0xa5b0, 0x4573,
202 0x52bf, 0xa9a8, 0xe950, 0x6aa0, 0xaea6, 0xab50, 0x4b60, 0xaae4,
203 0xa570, 0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0, 0x96d0, 0x4dd5,
204 0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x95a6,
205 0x95bf, 0x49b0, 0xa974, 0xa4b0, 0xb27a, 0x6a50, 0x6d40, 0xaf46,
206 0xab60, 0x9570, 0x4af5, 0x4970, 0x64b0, 0x74a3, 0xea50, 0x6b58,
207 0x5ac0, 0xab60, 0x96d5, 0x92e0, 0xc960, 0xd954, 0xd4a0, 0xda50,
208 0x7552, 0x56a0, 0xabb7, 0x25d0, 0x92d0, 0xcab5, 0xa950, 0xb4a0,
209 0xbaa4, 0xad50, 0x55d9, 0x4ba0, 0xa5b0, 0x5176, 0x52bf, 0xa930,
210 0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260,
211 0xea65, 0xd530, 0x5aa0, 0x76a3, 0x96d0, 0x4afb, 0x4ad0, 0xa4d0,
212 0xd0b6, 0xd25f, 0xd520, 0xdd45, 0xb5a0, 0x56d0, 0x55b2, 0x49b0,
213 0xa577, 0xa4b0, 0xaa50, 0xb255, 0x6d2f, 0xada0, 0x4b63, 0x937f,
214 0x49f8, 0x4970, 0x64b0, 0x68a6, 0xea5f, 0x6b20, 0xa6c4, 0xaaef,
215 0x92e0, 0xd2e3, 0xc960, 0xd557, 0xd4a0, 0xda50, 0x5d55, 0x56a0,
216 0xa6d0, 0x55d4, 0x52d0, 0xa9b8, 0xa950, 0xb4a0, 0xb6a6, 0xad50,
217 0x55a0, 0xaba4, 0xa5b0, 0x52b0, 0xb273, 0x6930, 0x7337, 0x6aa0,
218 0xad50, 0x4b55, 0x4b6f, 0xa570, 0x54e4, 0xd260, 0xe968, 0xd520,
219 0xdaa0, 0x6aa6, 0x56df, 0x4ae0, 0xa9d4, 0xa4d0, 0xd150, 0xf252,
220 0xd520, 0xdd45, 0xb5a0, 0x56d0
221 };
222
223 bool PickerStringFormatter::inited_ = false;
224 const std::string PickerStringFormatter::empty_;
225 std::vector<std::string> PickerStringFormatter::years_; // year from 1900 to 2100,count is 201
226 std::vector<std::string> PickerStringFormatter::solarMonths_; // solar month from 1 to 12,count is 12
227 std::vector<std::string> PickerStringFormatter::solarDays_; // solar day from 1 to 31, count is 31
228 std::vector<std::string> PickerStringFormatter::lunarMonths_; // lunar month from 1 to 24, count is 24
229 std::vector<std::string> PickerStringFormatter::lunarDays_; // lunar day from 1 to 30, count is 30
230 std::vector<std::string> PickerStringFormatter::tagOrder_; // order of year month day
231
Init()232 void PickerStringFormatter::Init()
233 {
234 if (inited_) {
235 return;
236 }
237 years_.resize(201); // year from 1900 to 2100,count is 201
238 solarMonths_.resize(12); // solar month from 1 to 12,count is 12
239 solarDays_.resize(31); // solar day from 1 to 31, count is 31
240 lunarMonths_.resize(24); // lunar month from 1 to 24, count is 24
241 lunarDays_.resize(30); // lunar day from 1 to 30, count is 30
242 // init year from 1900 to 2100
243 for (uint32_t year = 1900; year <= 2100; ++year) {
244 DateTime date;
245 date.year = year;
246 years_[year - 1900] = Localization::GetInstance()->FormatDateTime(date, "y"); // index start from 0
247 }
248 // init solar month from 1 to 12
249 auto months = Localization::GetInstance()->GetMonths(true);
250 for (uint32_t month = 1; month <= 12; ++month) {
251 if (month - 1 < months.size()) {
252 solarMonths_[month - 1] = months[month - 1];
253 continue;
254 }
255 DateTime date;
256 date.month = month - 1; // W3C's month start from 0 to 11
257 solarMonths_[month - 1] = Localization::GetInstance()->FormatDateTime(date, "M"); // index start from 0
258 }
259 // init solar day from 1 to 31
260 for (uint32_t day = 1; day <= 31; ++day) {
261 DateTime date;
262 date.day = day;
263 solarDays_[day - 1] = Localization::GetInstance()->FormatDateTime(date, "d"); // index start from 0
264 }
265 // init lunar month from 1 to 24 which is 1th, 2th, ... leap 1th, leap 2th ...
266 for (uint32_t index = 1; index <= 24; ++index) {
267 uint32_t month = (index > 12 ? index - 12 : index);
268 bool isLeap = (index > 12);
269 lunarMonths_[index - 1] = Localization::GetInstance()->GetLunarMonth(month, isLeap); // index start from 0
270 }
271 // init lunar day from 1 to 30
272 for (uint32_t day = 1; day <= 30; ++day) {
273 lunarDays_[day - 1] = Localization::GetInstance()->GetLunarDay(day); // index start from 0
274 }
275 inited_ = true;
276 Localization::GetInstance()->SetOnChange([]() { PickerStringFormatter::inited_ = false; });
277 }
278
GetYear(uint32_t year)279 const std::string& PickerStringFormatter::GetYear(uint32_t year)
280 {
281 Init();
282 if (!(1900 <= year && year <= 2100)) { // year in [1900,2100]
283 return empty_;
284 }
285 return years_[year - 1900]; // index in [0, 200]
286 }
287
GetSolarMonth(uint32_t month)288 const std::string& PickerStringFormatter::GetSolarMonth(uint32_t month)
289 {
290 Init();
291 if (!(1 <= month && month <= 12)) { // solar month in [1,12]
292 return empty_;
293 }
294 return solarMonths_[month - 1]; // index in [0,11]
295 }
296
GetSolarDay(uint32_t day)297 const std::string& PickerStringFormatter::GetSolarDay(uint32_t day)
298 {
299 Init();
300 if (!(1 <= day && day <= 31)) { // solar day in [1,31]
301 return empty_;
302 }
303 return solarDays_[day - 1]; // index in [0,30]
304 }
305
GetLunarMonth(uint32_t month,bool isLeap)306 const std::string& PickerStringFormatter::GetLunarMonth(uint32_t month, bool isLeap)
307 {
308 Init();
309 uint32_t index = (isLeap ? month + 12 : month); // leap month is behind 12 index
310 if (!(1 <= index && index <= 24)) { // lunar month need in [1,24]
311 return empty_;
312 }
313 return lunarMonths_[index - 1]; // index in [0,23]
314 }
315
GetLunarDay(uint32_t day)316 const std::string& PickerStringFormatter::GetLunarDay(uint32_t day)
317 {
318 Init();
319 if (!(1 <= day && day <= 30)) { // lunar day need in [1,30]
320 return empty_;
321 }
322 return lunarDays_[day - 1]; // index in [0,29]
323 }
324
GetTagOrder()325 const std::vector<std::string>& PickerStringFormatter::GetTagOrder()
326 {
327 tagOrder_.clear();
328 Localization::GetInstance()->GetDateColumnFormatOrder(tagOrder_);
329 return tagOrder_;
330 }
331
332 } // namespace OHOS::Ace
333