• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 namespace {
22 constexpr uint32_t MAX_YEAR = 5000;
23 constexpr uint32_t MAX_MONTH = 12;
24 }
25 
Current()26 PickerDate PickerDate::Current()
27 {
28     PickerDate date;
29     auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
30     auto local = std::localtime(&now);
31     if (local == nullptr) {
32         LOGE("get localtime failed.");
33         return date;
34     }
35     date.SetYear(local->tm_year + 1900); // local date start from 1900
36     date.SetMonth(local->tm_mon + 1);    // local month start from 0 to 11, need add one.
37     date.SetDay(local->tm_mday);
38     date.SetWeek(local->tm_wday);
39     return date;
40 }
41 
GetMaxDay(uint32_t year,uint32_t month)42 uint32_t PickerDate::GetMaxDay(uint32_t year, uint32_t month)
43 {
44     if (month == 2) { // days count in february is different between leap year and other.
45         bool leapYear = IsLeapYear(year);
46         return (leapYear ? 29 : 28); // leap year's february has 29 days, other has 28 days.
47     }
48 
49     switch (month) {
50         case 1:        // january
51         case 3:        // march
52         case 5:        // may
53         case 7:        // july
54         case 8:        // august
55         case 10:       // october
56         case 12:       // december
57             return 31; // upper months has 31 days
58         default:
59             return 30; // other month has 30 days
60     }
61 }
62 
IsLeapYear(uint32_t year)63 bool PickerDate::IsLeapYear(uint32_t year)
64 {
65     if (year % 100 == 0) {        // special case: year can divided by 100
66         return (year % 400 == 0); // leap year equal that can divided by 400.
67     }
68 
69     return (year % 4 == 0); // other case, leap year equal that can divided by 4.
70 }
71 
AdjustDateToRange(const PickerDate & date,const PickerDate & start,const PickerDate & end)72 PickerDate PickerDate::AdjustDateToRange(const PickerDate& date, const PickerDate& start, const PickerDate& end)
73 {
74     PickerDate adjustedDate = date;
75     if (start.ToDays() > date.ToDays()) {
76         adjustedDate = start;
77     } else if (end.GetYear() > 0 && end.ToDays() < date.ToDays()) {
78         adjustedDate = end;
79     }
80     return adjustedDate;
81 }
82 
IsDateInRange(const PickerDate & date,const PickerDate & start,const PickerDate & end)83 bool PickerDate::IsDateInRange(const PickerDate& date, const PickerDate& start, const PickerDate& end)
84 {
85     if (start.GetYear() > 0 &&
86         (date.GetYear() < start.GetYear() ||
87             (date.GetYear() == start.GetYear() &&
88                 (date.GetMonth() < start.GetMonth() ||
89                     (date.GetMonth() == start.GetMonth() && date.GetDay() < start.GetDay()))))) {
90         return false;
91     }
92     if (end.GetYear() > 0 &&
93         (date.GetYear() > end.GetYear() ||
94             (date.GetYear() == end.GetYear() &&
95                 (date.GetMonth() > end.GetMonth() ||
96                     (date.GetMonth() == end.GetMonth() && date.GetDay() > end.GetDay()))))) {
97         return false;
98     }
99     return true;
100 }
101 
ToString(bool jsonFormat,int32_t status) const102 std::string PickerDate::ToString(bool jsonFormat, int32_t status) const
103 {
104     if (!jsonFormat) {
105         DateTime date;
106         date.year = year_;
107         date.month = month_ ? month_ - 1 : 0; // W3C's month start from 0 to 11
108         date.day = day_;
109         return Localization::GetInstance()->FormatDateTime(date, DateTimeStyle::FULL, DateTimeStyle::NONE);
110     }
111 
112     return std::string("{\"year\":") + std::to_string(year_) + ",\"month\":" + std::to_string(month_) +
113            ",\"day\":" + std::to_string(day_) + ",\"status\":" + std::to_string(status) + "}";
114 }
115 
ToDays() const116 uint32_t PickerDate::ToDays() const
117 {
118     uint32_t days = 0;
119     days += day_ ? day_ - 1 : 0; // day start from 1
120     // month start from 1
121     for (uint32_t month = 1; month < month_; ++month) {
122         days += PickerDate::GetMaxDay(year_, month);
123     }
124     // year start from 1900 or 1
125     uint32_t startYear = 1900;
126     if (year_ < startYear) {
127         startYear = 1;
128     }
129     for (uint32_t year = startYear; year < year_; ++year) {
130         // leap year has 366 days, other year has 365 days.
131         days += (PickerDate::IsLeapYear(year) ? 366 : 365);
132     }
133     return days;
134 }
135 
FromDays(uint32_t days)136 void PickerDate::FromDays(uint32_t days)
137 {
138     for (year_ = 1900; year_ <= 2100; ++year_) { // year start from 1900 to 2100.
139         // leap year has 366 days, other year has 365 days;
140         uint32_t daysInYear = (PickerDate::IsLeapYear(year_) ? 366 : 365);
141         if (days < daysInYear) {
142             break;
143         } else {
144             days -= daysInYear;
145         }
146     }
147 
148     for (month_ = 1; month_ <= 12; ++month_) { // month start from 1 to 12
149         uint32_t daysInMonth = PickerDate::GetMaxDay(year_, month_);
150         if (days < daysInMonth) {
151             break;
152         } else {
153             days -= daysInMonth;
154         }
155     }
156 
157     day_ = days + 1; // days is index start form 0 and day start form 1.
158 }
159 
comparePickerDateRange(const std::pair<PickerDate,PickerDate> & pair,const std::pair<PickerDate,PickerDate> & other)160 bool comparePickerDateRange(
161     const std::pair<PickerDate, PickerDate>& pair, const std::pair<PickerDate, PickerDate>& other)
162 {
163     if (pair.first == other.first) {
164         return pair.second < other.second;
165     }
166     return pair.first < other.first;
167 }
168 
SortAndMergeDisabledDateRange(std::vector<std::pair<PickerDate,PickerDate>> & disableDateRange)169 void PickerDate::SortAndMergeDisabledDateRange(std::vector<std::pair<PickerDate, PickerDate>>& disableDateRange)
170 {
171     if (disableDateRange.empty()) {
172         return;
173     }
174     std::sort(disableDateRange.begin(), disableDateRange.end(), comparePickerDateRange);
175     std::vector<std::pair<PickerDate, PickerDate>> mergedRange;
176     for (const auto& range : disableDateRange) {
177         if (!mergedRange.empty() && range.first.ToDays() <= (mergedRange.back().second.ToDays() + 1)) {
178             mergedRange.back().second =
179                 mergedRange.back().second < range.second ? range.second : mergedRange.back().second;
180         } else {
181             mergedRange.push_back(range);
182         }
183     }
184     disableDateRange.clear();
185     disableDateRange = mergedRange;
186 }
187 
GetAvailableNextDay(const PickerDate & date,const PickerDate & start,const PickerDate & end,std::vector<std::pair<PickerDate,PickerDate>> & disableDateRange,bool isAdd)188 PickerDate PickerDate::GetAvailableNextDay(const PickerDate& date, const PickerDate& start, const PickerDate& end,
189     std::vector<std::pair<PickerDate, PickerDate>>& disableDateRange, bool isAdd)
190 {
191     PickerDate retDate = PickerDate(0, 0, 0);
192     if ((end.GetYear() != 0 && end < date) || (start.GetYear() != 0 && date < start)) {
193         return retDate;
194     }
195     if (isAdd) {
196         for (const auto& range : disableDateRange) {
197             if (range.first <= date && date <= range.second) {
198                 return end.GetYear() != 0 && end < range.second ? retDate : NextDay(range.second);
199             }
200         }
201         return date;
202     } else {
203         for (const auto& range : disableDateRange) {
204             if (range.first <= date && date <= range.second) {
205                 return start.GetYear() != 0 && range.first < start ? retDate : PrevDay(range.first);
206             }
207         }
208         return date;
209     }
210 }
211 
PrevDay(const PickerDate & dateObj)212 PickerDate PickerDate::PrevDay(const PickerDate& dateObj)
213 {
214     PickerDate date = dateObj;
215     if (date.GetDay() > 1) {
216         date.SetDay(date.GetDay() - 1);
217         return date;
218     }
219     if (date.GetMonth() == 1) {
220         date.SetMonth(MAX_MONTH);
221         auto getYear = date.GetYear();
222         date.SetYear(date.GetYear() == 1 ? MAX_YEAR : (getYear > 0 ? getYear - 1 : 0));
223     } else {
224         auto getMonth = date.GetMonth();
225         date.SetMonth(getMonth > 0 ? getMonth - 1 : 0);
226     }
227     date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth()));
228     return date;
229 }
230 
NextDay(const PickerDate & dateObj)231 PickerDate PickerDate::NextDay(const PickerDate& dateObj)
232 {
233     PickerDate date = dateObj;
234     auto maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
235     if (maxDay > date.GetDay()) {
236         date.SetDay(date.GetDay() + 1);
237         return date;
238     }
239     date.SetDay(1);
240     if (date.GetMonth() < MAX_MONTH) {
241         date.SetMonth(date.GetMonth() + 1);
242         return date;
243     }
244     date.SetMonth(1);
245     date.SetYear(date.GetYear() == MAX_YEAR ? 1 : date.GetYear() + 1);
246     return date;
247 }
248 
Current()249 PickerTime PickerTime::Current()
250 {
251     PickerTime time;
252     auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
253     auto local = std::localtime(&now);
254     if (local == nullptr) {
255         LOGE("get localtime failed.");
256         return time;
257     }
258     time.SetHour(local->tm_hour);
259     time.SetMinute(local->tm_min);
260     time.SetSecond(local->tm_sec);
261     return time;
262 }
263 
ToString(bool jsonFormat,bool hasSecond,int32_t status) const264 std::string PickerTime::ToString(bool jsonFormat, bool hasSecond, int32_t status) const
265 {
266     if (!jsonFormat) {
267         if (!hasSecond) {
268             // use char ':' to split.
269             return std::to_string(hour_) + ":" + std::to_string(minute_);
270         }
271         // use char ':' to split.
272         return std::to_string(hour_) + ":" + std::to_string(minute_) + ":" + std::to_string(second_);
273     }
274 
275     if (!hasSecond) {
276         // use json format chars
277         return std::string("{\"hour\":") + std::to_string(hour_) + ",\"minute\":" + std::to_string(minute_) +
278             ",\"status\":" + std::to_string(status) + "}";
279     }
280     // use json format chars
281     return std::string("{\"hour\":") + std::to_string(hour_) + ",\"minute\":" + std::to_string(minute_) +
282             ",\"second\":" + std::to_string(second_) + ",\"status\":" + std::to_string(status) + "}";
283 }
284 
ToMinutes() const285 uint32_t PickerTime::ToMinutes() const
286 {
287     constexpr static uint32_t minInHour = 60;
288     return minute_ + hour_ * minInHour;
289 }
290 
Current()291 PickerDateTime PickerDateTime::Current()
292 {
293     PickerDateTime dateTime;
294     dateTime.SetDate(PickerDate::Current());
295     dateTime.SetTime(PickerTime::Current());
296     return dateTime;
297 }
298 
ToString(bool jsonFormat,int32_t status) const299 std::string PickerDateTime::ToString(bool jsonFormat, int32_t status) const
300 {
301     if (!jsonFormat) {
302         return date_.ToString(jsonFormat);
303     }
304 
305     return std::string("{\"year\":") + std::to_string(date_.GetYear()) +
306            ",\"month\":" + std::to_string(date_.GetMonth()) +
307            ",\"day\":" + std::to_string(date_.GetDay()) +
308            ",\"hour\":" + std::to_string(time_.GetHour()) +
309            ",\"minute\":" + std::to_string(time_.GetMinute()) +
310            ",\"status\":" + std::to_string(status) + "}";
311 }
312 
313 /*
314  * Lunar information in 200 years from 1900.
315  * <p>
316  * | 0 - 11(bit) | 12 - 15(bit) |
317  * month      leap month
318  * If last 4bit is 1111 or 0000 means no leap month.
319  * If the last 4bit in next data is 1111, the days of leap month is 30 days,
320  * otherwise, the days of leap month is 29days.
321  */
322 const uint16_t LunarCalculator::LUNAR_INFO[] = {
323     0x6aa0, 0xbaa3, 0xab50,
324     0x4bd8, 0x4ae0, 0xa570, 0x54d5, 0xd260, 0xd950, 0x5554, 0x56af,
325     0x9ad0, 0x55d2, 0x4ae0, 0xa5b6, 0xa4d0, 0xd250, 0xd295, 0xb54f,
326     0xd6a0, 0xada2, 0x95b0, 0x4977, 0x497f, 0xa4b0, 0xb4b5, 0x6a50,
327     0x6d40, 0xab54, 0x2b6f, 0x9570, 0x52f2, 0x4970, 0x6566, 0xd4a0,
328     0xea50, 0x6a95, 0x5adf, 0x2b60, 0x86e3, 0x92ef, 0xc8d7, 0xc95f,
329     0xd4a0, 0xd8a6, 0xb55f, 0x56a0, 0xa5b4, 0x25df, 0x92d0, 0xd2b2,
330     0xa950, 0xb557, 0x6ca0, 0xb550, 0x5355, 0x4daf, 0xa5b0, 0x4573,
331     0x52bf, 0xa9a8, 0xe950, 0x6aa0, 0xaea6, 0xab50, 0x4b60, 0xaae4,
332     0xa570, 0x5260, 0xf263, 0xd950, 0x5b57, 0x56a0, 0x96d0, 0x4dd5,
333     0x4ad0, 0xa4d0, 0xd4d4, 0xd250, 0xd558, 0xb540, 0xb6a0, 0x95a6,
334     0x95bf, 0x49b0, 0xa974, 0xa4b0, 0xb27a, 0x6a50, 0x6d40, 0xaf46,
335     0xab60, 0x9570, 0x4af5, 0x4970, 0x64b0, 0x74a3, 0xea50, 0x6b58,
336     0x5ac0, 0xab60, 0x96d5, 0x92e0, 0xc960, 0xd954, 0xd4a0, 0xda50,
337     0x7552, 0x56a0, 0xabb7, 0x25d0, 0x92d0, 0xcab5, 0xa950, 0xb4a0,
338     0xbaa4, 0xad50, 0x55d9, 0x4ba0, 0xa5b0, 0x5176, 0x52bf, 0xa930,
339     0x7954, 0x6aa0, 0xad50, 0x5b52, 0x4b60, 0xa6e6, 0xa4e0, 0xd260,
340     0xea65, 0xd530, 0x5aa0, 0x76a3, 0x96d0, 0x4afb, 0x4ad0, 0xa4d0,
341     0xd0b6, 0xd25f, 0xd520, 0xdd45, 0xb5a0, 0x56d0, 0x55b2, 0x49b0,
342     0xa577, 0xa4b0, 0xaa50, 0xb255, 0x6d2f, 0xada0, 0x4b63, 0x937f,
343     0x49f8, 0x4970, 0x64b0, 0x68a6, 0xea5f, 0x6b20, 0xa6c4, 0xaaef,
344     0x92e0, 0xd2e3, 0xc960, 0xd557, 0xd4a0, 0xda50, 0x5d55, 0x56a0,
345     0xa6d0, 0x55d4, 0x52d0, 0xa9b8, 0xa950, 0xb4a0, 0xb6a6, 0xad50,
346     0x55a0, 0xaba4, 0xa5b0, 0x52b0, 0xb273, 0x6930, 0x7337, 0x6aa0,
347     0xad50, 0x4b55, 0x4b6f, 0xa570, 0x54e4, 0xd260, 0xe968, 0xd520,
348     0xdaa0, 0x6aa6, 0x56df, 0x4ae0, 0xa9d4, 0xa4d0, 0xd150, 0xf252,
349     0xd520, 0xdd45, 0xb5a0, 0x56d0
350 };
351 
352 bool PickerStringFormatter::inited_ = false;
353 const std::string PickerStringFormatter::empty_;
354 std::vector<std::string> PickerStringFormatter::years_; // year from 1900 to 2100,count is 201
355 std::vector<std::string> PickerStringFormatter::solarMonths_; // solar month from 1 to 12,count is 12
356 std::vector<std::string> PickerStringFormatter::solarDays_; // solar day from 1 to 31, count is 31
357 std::vector<std::string> PickerStringFormatter::lunarMonths_; // lunar month from 1 to 24, count is 24
358 std::vector<std::string> PickerStringFormatter::lunarDays_; // lunar day from 1 to 30, count is 30
359 std::vector<std::string> PickerStringFormatter::tagOrder_; // order of year month day
360 
Init()361 void PickerStringFormatter::Init()
362 {
363     if (inited_) {
364         return;
365     }
366     years_.resize(201); // year from 1900 to 2100,count is 201
367     solarMonths_.resize(12); // solar month from 1 to 12,count is 12
368     solarDays_.resize(31); // solar day from 1 to 31, count is 31
369     lunarMonths_.resize(24); // lunar month from 1 to 24, count is 24
370     lunarDays_.resize(30); // lunar day from 1 to 30, count is 30
371     // init year from 1900 to 2100
372     for (uint32_t year = 1900; year <= 2100; ++year) {
373         DateTime date;
374         date.year = year;
375         years_[year - 1900] = Localization::GetInstance()->FormatDateTime(date, "y"); // index start from 0
376     }
377     // init solar month from 1 to 12
378     auto months = Localization::GetInstance()->GetMonths(true);
379     for (uint32_t month = 1; month <= 12; ++month) {
380         if (month - 1 < months.size()) {
381             solarMonths_[month - 1] = months[month - 1];
382             continue;
383         }
384         DateTime date;
385         date.month = month - 1; // W3C's month start from 0 to 11
386         solarMonths_[month - 1] = Localization::GetInstance()->FormatDateTime(date, "M"); // index start from 0
387     }
388     // init solar day from 1 to 31
389     for (uint32_t day = 1; day <= 31; ++day) {
390         DateTime date;
391         date.day = day;
392         solarDays_[day - 1] = Localization::GetInstance()->FormatDateTime(date, "d"); // index start from 0
393     }
394     // init lunar month from 1 to 24 which is 1th, 2th, ... leap 1th, leap 2th ...
395     for (uint32_t index = 1; index <= 24; ++index) {
396         uint32_t month = (index > 12 ? index - 12 : index);
397         bool isLeap = (index > 12);
398         lunarMonths_[index - 1] = Localization::GetInstance()->GetLunarMonth(month, isLeap); // index start from 0
399     }
400     // init lunar day from 1 to 30
401     for (uint32_t day = 1; day <= 30; ++day) {
402         lunarDays_[day - 1] = Localization::GetInstance()->GetLunarDay(day); // index start from 0
403     }
404     inited_ = true;
405     Localization::GetInstance()->SetOnChange([]() { PickerStringFormatter::inited_ = false; });
406 }
407 
GetYear(uint32_t year)408 const std::string& PickerStringFormatter::GetYear(uint32_t year)
409 {
410     Init();
411     if (!(1900 <= year && year <= 2100)) { // year in [1900,2100]
412         return empty_;
413     }
414     return years_[year - 1900]; // index in [0, 200]
415 }
416 
GetSolarMonth(uint32_t month)417 const std::string& PickerStringFormatter::GetSolarMonth(uint32_t month)
418 {
419     Init();
420     if (!(1 <= month && month <= 12)) { // solar month in [1,12]
421         return empty_;
422     }
423     return solarMonths_[month - 1]; // index in [0,11]
424 }
425 
GetSolarDay(uint32_t day)426 const std::string& PickerStringFormatter::GetSolarDay(uint32_t day)
427 {
428     Init();
429     if (!(1 <= day && day <= 31)) { // solar day in [1,31]
430         return empty_;
431     }
432     return solarDays_[day - 1]; // index in [0,30]
433 }
434 
GetLunarMonth(uint32_t month,bool isLeap)435 const std::string& PickerStringFormatter::GetLunarMonth(uint32_t month, bool isLeap)
436 {
437     Init();
438     uint32_t index = (isLeap ? month + 12 : month); // leap month is behind 12 index
439     if (!(1 <= index && index <= 24)) { // lunar month need in [1,24]
440         return empty_;
441     }
442     return lunarMonths_[index - 1]; // index in [0,23]
443 }
444 
GetLunarDay(uint32_t day)445 const std::string& PickerStringFormatter::GetLunarDay(uint32_t day)
446 {
447     Init();
448     if (!(1 <= day && day <= 30)) { // lunar day need in [1,30]
449         return empty_;
450     }
451     return lunarDays_[day - 1]; // index in [0,29]
452 }
453 
GetTagOrder()454 const std::vector<std::string>& PickerStringFormatter::GetTagOrder()
455 {
456     tagOrder_.clear();
457     Localization::GetInstance()->GetDateColumnFormatOrder(tagOrder_);
458     return tagOrder_;
459 }
460 
461 } // namespace OHOS::Ace
462