1 /*
2  * Copyright (c) 2021 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_date_component.h"
17 
18 namespace OHOS::Ace {
19 
20 // all date should in  solar range [1900.1.31, 2100.12.31] and lunar range [1900.1.1, 2100.12.1]
21 const PickerDate PickerDateComponent::limitStartDate_(1900, 1, 31);
22 const PickerDate PickerDateComponent::limitEndDate_(2100, 12, 31);
23 
PickerDateComponent()24 PickerDateComponent::PickerDateComponent()
25 {
26     auto yearColumn = AceType::MakeRefPtr<PickerColumnComponent>();
27     yearColumn->SetColumnTag(PICKER_YEAR_COLUMN);
28     yearColumn->SetWidthRatio(3); // year:month:day = 3:2:2
29     auto monthColumn = AceType::MakeRefPtr<PickerColumnComponent>();
30     monthColumn->SetColumnTag(PICKER_MONTH_COLUMN);
31     monthColumn->SetWidthRatio(2); // year:month:day = 3:2:2
32     auto dayColumn = AceType::MakeRefPtr<PickerColumnComponent>();
33     dayColumn->SetColumnTag(PICKER_DAY_COLUMN);
34     dayColumn->SetWidthRatio(2); // year:month:day = 3:2:2
35     auto order = PickerStringFormatter::GetTagOrder();
36     if (order.size() != 3) { // has 3 columns: year month day
37         AppendColumn(yearColumn);
38         AppendColumn(monthColumn);
39         AppendColumn(dayColumn);
40     } else {
41         std::map<std::string, RefPtr<PickerColumnComponent>> tagColumns;
42         tagColumns[PICKER_YEAR_COLUMN] = yearColumn;
43         tagColumns[PICKER_MONTH_COLUMN] = monthColumn;
44         tagColumns[PICKER_DAY_COLUMN] = dayColumn;
45         for (uint32_t i = 0; i < order.size(); ++i) {
46             AppendColumn(tagColumns[order[i]]);
47         }
48     }
49     startDateLunar_ = SolarToLunar(startDateSolar_);
50     endDateLunar_ = SolarToLunar(endDateSolar_);
51 }
52 
OnTitleBuilding()53 void PickerDateComponent::OnTitleBuilding()
54 {
55     auto theme = GetTheme();
56     if (!theme) {
57         LOGE("theme is null.");
58         return;
59     }
60     SetHasTitle(theme->GetShowButtons());
61     SetHasButtons(theme->GetShowButtons());
62 
63     auto date = GetCurrentDate();
64     if (onDateChange_) {
65         onDateChange_(date);
66     }
67 
68     auto titleComponent = GetTitle();
69     if (!titleComponent) {
70         LOGE("title component is null.");
71         return;
72     }
73     titleComponent->SetData(date.ToString(false));
74 }
75 
OnColumnsBuilding()76 void PickerDateComponent::OnColumnsBuilding()
77 {
78     AdjustSolarDate(selectedDate_);
79     if (lunar_) {
80         auto lunarDate = SolarToLunar(selectedDate_);
81         LunarColumnsBuilding(lunarDate);
82     } else {
83         SolarColumnsBuilding(selectedDate_);
84     }
85 }
86 
OnSelectedSaving()87 void PickerDateComponent::OnSelectedSaving()
88 {
89     selectedDate_ = GetCurrentDate();
90 }
91 
GetSelectedObject(bool isColumnChange,const std::string & changeColumnTag,int status) const92 std::string PickerDateComponent::GetSelectedObject(bool isColumnChange,
93     const std::string& changeColumnTag, int status) const
94 {
95     auto date = selectedDate_;
96     if (isColumnChange) {
97         date = GetCurrentDate();
98     }
99     // W3C's month is between 0 to 11, need to reduce one.
100     date.SetMonth(date.GetMonth() - 1);
101     return date.ToString(true, status);
102 }
103 
OnDataLinking(const std::string & tag,bool isAdd,uint32_t index,std::vector<std::string> & resultTags)104 void PickerDateComponent::OnDataLinking(const std::string& tag, bool isAdd, uint32_t index,
105     std::vector<std::string>& resultTags)
106 {
107     if (tag == PICKER_YEAR_COLUMN) {
108         HandleYearChange(isAdd, index, resultTags);
109         return;
110     }
111 
112     if (tag == PICKER_MONTH_COLUMN) {
113         HandleMonthChange(isAdd, index, resultTags);
114         return;
115     }
116 
117     if (tag == PICKER_DAY_COLUMN) {
118         HandleDayChange(isAdd, index, resultTags);
119         return;
120     }
121 
122     LOGE("unknown tag[%{private}s] of column.", tag.c_str());
123 }
124 
125 
OnAnimationPlaying()126 void PickerDateComponent::OnAnimationPlaying()
127 {
128     auto controller = GetAnimationController();
129     if (!controller) {
130         LOGE("controller is null.");
131         return;
132     }
133 
134     controller->Play(true);
135 }
136 
GetCurrentDate() const137 PickerDate PickerDateComponent::GetCurrentDate() const
138 {
139     PickerDate result;
140     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
141     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
142     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
143     if (!yearColumn || !monthColumn || !dayColumn) {
144         LOGE("year or month or day column is null.");
145         return result;
146     }
147 
148     if (!lunar_) {
149         result.SetYear(startDateSolar_.GetYear() + yearColumn->GetCurrentIndex());
150         result.SetMonth(monthColumn->GetCurrentIndex() + 1); // month from 1 to 12, index from 0 to 11.
151         result.SetDay(dayColumn->GetCurrentIndex() + 1); // day from 1 to 31, index from 0 to 30.
152         return result;
153     }
154 
155     uint32_t lunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
156     return LunarToSolar(GetCurrentLunarDate(lunarYear));
157 }
158 
GetCurrentLunarDate(uint32_t lunarYear) const159 LunarDate PickerDateComponent::GetCurrentLunarDate(uint32_t lunarYear) const
160 {
161     LunarDate lunarResult;
162     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
163     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
164     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
165     if (!yearColumn || !monthColumn || !dayColumn) {
166         LOGE("year or month or day column is null.");
167         return lunarResult;
168     }
169 
170     uint32_t lunarLeapMonth = 0;
171     bool hasLeapMonth = GetLunarLeapMonth(lunarYear, lunarLeapMonth);
172     lunarResult.isLeapMonth = false;
173     if (!hasLeapMonth) {
174         lunarResult.month = monthColumn->GetCurrentIndex() + 1; // month from 1 to 12, index from 0 to 11
175     } else {
176         if (monthColumn->GetCurrentIndex() == lunarLeapMonth) {
177             lunarResult.isLeapMonth = true;
178             lunarResult.month = lunarLeapMonth;
179         } else if (monthColumn->GetCurrentIndex() < lunarLeapMonth) {
180             lunarResult.month = monthColumn->GetCurrentIndex() + 1; // month start from 1, index start from 0
181         } else {
182             lunarResult.month = monthColumn->GetCurrentIndex();
183         }
184     }
185     lunarResult.year = startDateLunar_.year + yearColumn->GetCurrentIndex();
186     lunarResult.day = dayColumn->GetCurrentIndex() + 1; // day start form 1, index start from 0
187     return lunarResult;
188 }
189 
HandleYearChange(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)190 void PickerDateComponent::HandleYearChange(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
191 {
192     if (lunar_) {
193         HandleLunarYearChange(isAdd, index);
194     } else {
195         HandleSolarYearChange(isAdd, index);
196     }
197     resultTags.emplace_back(PICKER_YEAR_COLUMN);
198     resultTags.emplace_back(PICKER_MONTH_COLUMN);
199     resultTags.emplace_back(PICKER_DAY_COLUMN);
200 }
201 
HandleLunarYearChange(bool isAdd,uint32_t index)202 void PickerDateComponent::HandleLunarYearChange(bool isAdd, uint32_t index)
203 {
204     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
205     if (!yearColumn || yearColumn->GetOptionCount() == 0) {
206         LOGE("year column is null or empty.");
207         return;
208     }
209 
210     uint32_t lastYearIndex = index;
211     auto optionCount = yearColumn->GetOptionCount();
212     if (isAdd) { // need reduce one index
213         lastYearIndex = optionCount != 0 ? (yearColumn->GetOptionCount() + lastYearIndex - 1) % optionCount : 0;
214     } else { // need add one index
215         lastYearIndex = optionCount != 0 ? (yearColumn->GetOptionCount() + lastYearIndex + 1) % optionCount : 0;
216     }
217     uint32_t lastLunarYear = startDateLunar_.year + lastYearIndex;
218     auto lunarDate = GetCurrentLunarDate(lastLunarYear);
219     uint32_t nowLeapMonth = 0;
220     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, nowLeapMonth);
221     if (!hasLeapMonth && lunarDate.isLeapMonth) {
222         lunarDate.isLeapMonth = false;
223     }
224     uint32_t nowMaxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
225     if (lunarDate.day > nowMaxDay) {
226         lunarDate.day = nowMaxDay;
227     }
228 
229     AdjustLunarDate(lunarDate);
230     LunarColumnsBuilding(lunarDate);
231 }
232 
HandleSolarYearChange(bool isAdd,uint32_t index)233 void PickerDateComponent::HandleSolarYearChange(bool isAdd, uint32_t index)
234 {
235     auto date = GetCurrentDate();
236 
237     bool leapYear = PickerDate::IsLeapYear(date.GetYear());
238     if (date.GetMonth() == 2 && !leapYear && date.GetDay() > 28) { // invalidate of 2th month
239         date.SetDay(28); // the max day of the 2th month of none leap year is 28
240     }
241 
242     AdjustSolarDate(date);
243     SolarColumnsBuilding(date);
244 }
245 
HandleMonthChange(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)246 void PickerDateComponent::HandleMonthChange(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
247 {
248     if (lunar_) {
249         HandleLunarMonthChange(isAdd, index);
250     } else {
251         HandleSolarMonthChange(isAdd, index);
252     }
253     resultTags.emplace_back(PICKER_YEAR_COLUMN);
254     resultTags.emplace_back(PICKER_MONTH_COLUMN);
255     resultTags.emplace_back(PICKER_DAY_COLUMN);
256 }
257 
HandleLunarMonthChange(bool isAdd,uint32_t index)258 void PickerDateComponent::HandleLunarMonthChange(bool isAdd, uint32_t index)
259 {
260     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
261     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
262     if (!yearColumn || !monthColumn) {
263         LOGE("year or month column is null.");
264         return;
265     }
266 
267     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
268     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
269     if (isAdd && index == 0) {
270         lunarDate.year = lunarDate.year + 1; // add to next year
271         if (lunarDate.year > endDateLunar_.year) {
272             lunarDate.year = startDateLunar_.year;
273         }
274     }
275     uint32_t val = monthColumn->GetOptionCount() > 0 ? monthColumn->GetOptionCount() - 1 : 0;
276     if (!isAdd && index == val) {
277         lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
278         if (lunarDate.year < startDateLunar_.year) {
279             lunarDate.year = endDateLunar_.year;
280         }
281     }
282     uint32_t lunarLeapMonth = 0;
283     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
284     if (!hasLeapMonth && lunarDate.isLeapMonth) {
285         lunarDate.isLeapMonth = false;
286     }
287     uint32_t maxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
288     if (lunarDate.day > maxDay) {
289         lunarDate.day = maxDay;
290     }
291 
292     AdjustLunarDate(lunarDate);
293     LunarColumnsBuilding(lunarDate);
294 }
295 
HandleSolarMonthChange(bool isAdd,uint32_t index)296 void PickerDateComponent::HandleSolarMonthChange(bool isAdd, uint32_t index)
297 {
298     auto date = GetCurrentDate();
299     if (isAdd && date.GetMonth() == 1) { // first month is 1
300         date.SetYear(date.GetYear() + 1); // add 1 year, the next year
301         if (date.GetYear() > endDateSolar_.GetYear()) {
302             date.SetYear(startDateSolar_.GetYear());
303         }
304     }
305     if (!isAdd && date.GetMonth() == 12) { // the last month is 12
306         uint32_t yearVal = date.GetYear() > 0 ? date.GetYear() - 1 : 0;
307         date.SetYear(yearVal); // reduce 1 year, the previous year
308         if (date.GetYear() < startDateSolar_.GetYear()) {
309             date.SetYear(endDateSolar_.GetYear());
310         }
311     }
312     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
313     if (date.GetDay() > maxDay) {
314         date.SetDay(maxDay);
315     }
316     AdjustSolarDate(date);
317     SolarColumnsBuilding(date);
318 }
319 
HandleDayChange(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)320 void PickerDateComponent::HandleDayChange(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
321 {
322     if (lunar_) {
323         HandleLunarDayChange(isAdd, index);
324     } else {
325         HandleSolarDayChange(isAdd, index);
326     }
327     resultTags.emplace_back(PICKER_YEAR_COLUMN);
328     resultTags.emplace_back(PICKER_MONTH_COLUMN);
329     resultTags.emplace_back(PICKER_DAY_COLUMN);
330 }
331 
HandleSolarDayChange(bool isAdd,uint32_t index)332 void PickerDateComponent::HandleSolarDayChange(bool isAdd, uint32_t index)
333 {
334     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
335     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
336     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
337     if (!yearColumn || !monthColumn || !dayColumn) {
338         LOGE("year or month or day column is null.");
339         return;
340     }
341 
342     auto date = GetCurrentDate();
343     if (isAdd && index == 0) {
344         date.SetMonth(date.GetMonth() + 1); // add to next month
345         if (date.GetMonth() > 12) { // invalidate month, max month is 12
346             date.SetMonth(1); // first month is 1
347             date.SetYear(date.GetYear() + 1); // add to next year
348             if (date.GetYear() > endDateSolar_.GetYear()) {
349                 date.SetYear(startDateSolar_.GetYear());
350             }
351         }
352     }
353     uint32_t val = dayColumn->GetOptionCount() > 0 ? dayColumn->GetOptionCount() - 1 : 0;
354     if (!isAdd && dayColumn->GetCurrentIndex() == val) { // last index is count - 1
355         date.SetMonth(date.GetMonth() - 1); // reduce to previous month
356         if (date.GetMonth() == 0) { // min month is 1, invalidate
357             date.SetMonth(12); // set to be the last month
358             date.SetYear(date.GetYear() - 1); // reduce to previous year
359             if (date.GetYear() < startDateSolar_.GetYear()) {
360                 date.SetYear(endDateSolar_.GetYear());
361             }
362         }
363         date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth())); // reduce to previous month's last day
364     }
365     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
366     if (date.GetDay() > maxDay) {
367         date.SetDay(maxDay);
368     }
369     AdjustSolarDate(date);
370     SolarColumnsBuilding(date);
371 }
372 
HandleLunarDayChange(bool isAdd,uint32_t index)373 void PickerDateComponent::HandleLunarDayChange(bool isAdd, uint32_t index)
374 {
375     if (isAdd) {
376         HandleAddLunarDayChange(index);
377     } else {
378         HandleReduceLunarDayChange(index);
379     }
380 }
381 
HandleAddLunarDayChange(uint32_t index)382 void PickerDateComponent::HandleAddLunarDayChange(uint32_t index)
383 {
384     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
385     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
386     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
387     if (!yearColumn || !monthColumn || !dayColumn) {
388         LOGE("year or month or day column is null.");
389         return;
390     }
391 
392     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
393     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
394     uint32_t lunarLeapMonth = 0;
395     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
396     if (index == 0) {
397         uint32_t val = monthColumn->GetOptionCount() > 0 ? monthColumn->GetOptionCount() - 1 : 0;
398         if (monthColumn->GetCurrentIndex() == val) { // max index is count - 1
399             lunarDate.year = lunarDate.year + 1; // add to next year
400             if (lunarDate.year > endDateLunar_.year) {
401                 lunarDate.year = startDateLunar_.year;
402             }
403             lunarDate.month = 1; // first month
404             lunarDate.isLeapMonth = false;
405         } else {
406             if (lunarDate.isLeapMonth) {
407                 lunarDate.month = lunarDate.month + 1; // add to next month
408                 lunarDate.isLeapMonth = false;
409             } else if (!hasLeapMonth) {
410                 lunarDate.month = lunarDate.month + 1; // add to next month
411             } else if (lunarLeapMonth == lunarDate.month) {
412                 lunarDate.isLeapMonth = true;
413             } else {
414                 lunarDate.month = lunarDate.month + 1; // add to next month
415             }
416         }
417     }
418 
419     AdjustLunarDate(lunarDate);
420     LunarColumnsBuilding(lunarDate);
421 }
422 
HandleReduceLunarDayChange(uint32_t index)423 void PickerDateComponent::HandleReduceLunarDayChange(uint32_t index)
424 {
425     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
426     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
427     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
428     if (!yearColumn || !monthColumn || !dayColumn) {
429         LOGE("year or month or day column is null.");
430         return;
431     }
432 
433     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
434     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
435     uint32_t lunarLeapMonth = 0;
436     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
437     uint32_t val = dayColumn->GetOptionCount() > 0 ? dayColumn->GetOptionCount() - 1 : 0;
438     if (dayColumn->GetCurrentIndex() == val) { // max index is count - 1
439         if (monthColumn->GetCurrentIndex() == 0) {
440             lunarDate.year = lunarDate.year - 1; // reduce to previous year
441             if (lunarDate.year < startDateLunar_.year) {
442                 lunarDate.year = endDateLunar_.year;
443             }
444             lunarDate.month = 12; // set to be previous year's max month
445             lunarDate.isLeapMonth = false;
446             if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
447                 lunarDate.isLeapMonth = true;
448             }
449             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
450         } else {
451             if (lunarDate.isLeapMonth) {
452                 lunarDate.isLeapMonth = false;
453             } else if (!hasLeapMonth) {
454                 lunarDate.month = lunarDate.month - 1; // reduce to previous month
455             } else if (lunarLeapMonth == lunarDate.month - 1) { // leap month is previous month
456                 lunarDate.isLeapMonth = true;
457                 lunarDate.month = lunarLeapMonth;
458             } else {
459                 lunarDate.month = lunarDate.month - 1; // reduce to previous month
460             }
461             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
462         }
463     }
464 
465     AdjustLunarDate(lunarDate);
466     LunarColumnsBuilding(lunarDate);
467 }
468 
GetYearFormatString(uint32_t year) const469 std::string PickerDateComponent::GetYearFormatString(uint32_t year) const
470 {
471     return PickerStringFormatter::GetYear(year);
472 }
473 
GetMonthFormatString(uint32_t month,bool isLunar,bool isLeap) const474 std::string PickerDateComponent::GetMonthFormatString(uint32_t month, bool isLunar, bool isLeap) const
475 {
476     if (isLunar) {
477         return PickerStringFormatter::GetLunarMonth(month, isLeap);
478     }
479 
480     return PickerStringFormatter::GetSolarMonth(month);
481 }
482 
GetDayFormatString(uint32_t day,bool isLunar) const483 std::string PickerDateComponent::GetDayFormatString(uint32_t day, bool isLunar) const
484 {
485     if (isLunar) {
486         return PickerStringFormatter::GetLunarDay(day);
487     }
488 
489     return PickerStringFormatter::GetSolarDay(day);
490 }
491 
OnLunarCallback(bool checked,std::vector<std::string> & resultTags)492 void PickerDateComponent::OnLunarCallback(bool checked, std::vector<std::string>& resultTags)
493 {
494     if (checked) {
495         auto solarDate = GetCurrentDate();
496         auto lunarDate = SolarToLunar(solarDate);
497         LunarColumnsBuilding(lunarDate);
498     } else {
499         auto solarDate = GetCurrentDate();
500         SolarColumnsBuilding(solarDate);
501     }
502 
503     resultTags.emplace_back(PICKER_YEAR_COLUMN);
504     resultTags.emplace_back(PICKER_MONTH_COLUMN);
505     resultTags.emplace_back(PICKER_DAY_COLUMN);
506 }
507 
SolarToLunar(const PickerDate & date) const508 LunarDate PickerDateComponent::SolarToLunar(const PickerDate& date) const
509 {
510     Date result;
511     result.year = date.GetYear();
512     result.month = date.GetMonth();
513     result.day = date.GetDay();
514     return Localization::GetInstance()->GetLunarDate(result);
515 }
516 
LunarToSolar(const LunarDate & date) const517 PickerDate PickerDateComponent::LunarToSolar(const LunarDate& date) const
518 {
519     uint32_t days = date.day > 0 ? date.day - 1 : 0; // calculate days from 1900.1.1 to this date
520     if (date.isLeapMonth) {
521         days += LunarCalculator::GetLunarMonthDays(date.year, date.month);
522     } else {
523         uint32_t leapMonth = LunarCalculator::GetLunarLeapMonth(date.year);
524         if (leapMonth < date.month) {
525             days += LunarCalculator::GetLunarLeapDays(date.year);
526         }
527     }
528     for (uint32_t month = 1; month < date.month; ++month) { // month start from 1
529         days += LunarCalculator::GetLunarMonthDays(date.year, month);
530     }
531     for (uint32_t year = 1900; year < date.year; ++year) { // year start from 1900
532         days += LunarCalculator::GetLunarYearDays(year);
533     }
534     days += 30; // days from solar's 1900.1.1 to lunar's 1900.1.1 is 30
535     PickerDate result;
536     result.FromDays(days);
537     return result;
538 }
539 
GetLunarLeapMonth(uint32_t year,uint32_t & outLeapMonth) const540 bool PickerDateComponent::GetLunarLeapMonth(uint32_t year, uint32_t& outLeapMonth) const
541 {
542     auto leapMonth = LunarCalculator::GetLunarLeapMonth(year);
543     if (leapMonth <= 0) {
544         return false;
545     }
546 
547     outLeapMonth = static_cast<uint32_t>(leapMonth);
548     return true;
549 }
550 
GetLunarMaxDay(uint32_t year,uint32_t month,bool isLeap) const551 uint32_t PickerDateComponent::GetLunarMaxDay(uint32_t year, uint32_t month, bool isLeap) const
552 {
553     if (isLeap) {
554         return static_cast<uint32_t>(LunarCalculator::GetLunarLeapDays(year));
555     } else {
556         return static_cast<uint32_t>(LunarCalculator::GetLunarMonthDays(year, month));
557     }
558 }
559 
SolarColumnsBuilding(const PickerDate & current)560 void PickerDateComponent::SolarColumnsBuilding(const PickerDate& current)
561 {
562     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
563     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
564     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
565     if (!yearColumn || !monthColumn || !dayColumn) {
566         LOGE("year or month or day column is null.");
567         return;
568     }
569 
570     auto startYear = startDateSolar_.GetYear();
571     auto endYear = endDateSolar_.GetYear();
572     auto startMonth = startDateSolar_.GetMonth();
573     auto endMonth = endDateSolar_.GetMonth();
574     auto startDay = startDateSolar_.GetDay();
575     auto endDay = endDateSolar_.GetDay();
576     if (startYear > endYear) {
577         return;
578     }
579     if (startYear == endYear && startMonth > endMonth) {
580         return;
581     }
582     if (startYear == endYear && startMonth == endMonth && startDay > endDay) {
583         return;
584     }
585     uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), current.GetMonth());
586     if (startYear < endYear) {
587         startMonth = 1;
588         endMonth = 12;
589         startDay = 1;
590         endDay = maxDay;
591     }
592     if (startYear == endYear && startMonth < endMonth) {
593         startDay = 1;
594         endDay = maxDay;
595     }
596 
597     yearColumn->ClearOption();
598     for (uint32_t year = startYear; year <= endYear; ++year) {
599         if (year == current.GetYear()) {
600             yearColumn->SetCurrentIndex(yearColumn->GetOptionCount());
601         }
602         yearColumn->AppendOption(GetYearFormatString(year));
603     }
604 
605     monthColumn->ClearOption();
606     // solar's month start form 1 to 12
607     for (uint32_t month = startMonth; month <= endMonth; month++) {
608         if (month == current.GetMonth()) {
609             monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
610         }
611         monthColumn->AppendOption(GetMonthFormatString(month, false, false));
612     }
613 
614     dayColumn->ClearOption();
615 
616     // solar's day start from 1
617     for (uint32_t day = startDay; day <= endDay; day++) {
618         if (day == current.GetDay()) {
619             dayColumn->SetCurrentIndex(dayColumn->GetOptionCount());
620         }
621         dayColumn->AppendOption(GetDayFormatString(day, false));
622     }
623 
624     lunar_ = false;
625 }
626 
LunarColumnsBuilding(const LunarDate & current)627 void PickerDateComponent::LunarColumnsBuilding(const LunarDate& current)
628 {
629     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
630     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
631     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
632     if (!yearColumn || !monthColumn || !dayColumn) {
633         LOGE("year or month or day column is null.");
634         return;
635     }
636 
637     auto startYear = startDateLunar_.year;
638     auto endYear = endDateLunar_.year;
639     auto startMonth = startDateLunar_.month;
640     auto endMonth = endDateLunar_.month;
641     auto startDay = startDateLunar_.day;
642     auto endDay = endDateLunar_.day;
643     if (startYear > endYear) {
644         return;
645     }
646     if (startYear == endYear && startMonth > endMonth) {
647         return;
648     }
649     if (startYear == endYear && startMonth == endMonth && startDay > endDay) {
650         return;
651     }
652     uint32_t maxDay = GetLunarMaxDay(current.year, current.month, current.isLeapMonth);
653     if (startYear < endYear) {
654         startMonth = 1;
655         endMonth = 12;
656         startDay = 1;
657         endDay = maxDay;
658     }
659     if (startYear == endYear && startMonth < endMonth) {
660         startDay = 1;
661         endDay = maxDay;
662     }
663 
664     yearColumn->ClearOption();
665     for (uint32_t index = startYear; index <= endYear; ++index) {
666         if (current.year == index) {
667             yearColumn->SetCurrentIndex(yearColumn->GetOptionCount());
668         }
669         yearColumn->AppendOption(GetYearFormatString(index));
670     }
671 
672     uint32_t lunarLeapMonth = 0;
673     bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
674     monthColumn->ClearOption();
675     // lunar's month start form startMonth to endMonth
676     for (uint32_t index = startMonth; index <= endMonth; ++index) {
677         if (!current.isLeapMonth && current.month == index) {
678             monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
679         }
680         monthColumn->AppendOption(GetMonthFormatString(index, true, false));
681         if (hasLeapMonth && lunarLeapMonth == index) {
682             if (current.isLeapMonth && current.month == index) {
683                 monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
684             }
685             monthColumn->AppendOption(GetMonthFormatString(index, true, true));
686         }
687     }
688 
689     dayColumn->ClearOption();
690     // lunar's day start from startDay
691     for (uint32_t index = startDay; index <= endDay; ++index) {
692         if (current.day == index) {
693             dayColumn->SetCurrentIndex(dayColumn->GetOptionCount());
694         }
695         dayColumn->AppendOption(GetDayFormatString(index, true));
696     }
697 
698     lunar_ = true;
699 }
700 
AdjustSolarDate(PickerDate & date) const701 void PickerDateComponent::AdjustSolarDate(PickerDate& date) const
702 {
703     AdjustSolarDate(date, startDateSolar_, endDateSolar_);
704 }
705 
AdjustSolarDate(PickerDate & date,const PickerDate & start,const PickerDate & end) const706 void PickerDateComponent::AdjustSolarDate(PickerDate& date, const PickerDate& start, const PickerDate& end) const
707 {
708     if (SolarDateCompare(date, start) < 0) {
709         date = start;
710         return;
711     }
712     if (SolarDateCompare(date, end) > 0) {
713         date = end;
714     }
715 }
716 
AdjustLunarDate(LunarDate & date) const717 void PickerDateComponent::AdjustLunarDate(LunarDate& date) const
718 {
719     if (LunarDateCompare(date, startDateLunar_) < 0) {
720         date = startDateLunar_;
721         return;
722     }
723     if (LunarDateCompare(date, endDateLunar_) > 0) {
724         date = endDateLunar_;
725     }
726 }
727 
SolarDateCompare(const PickerDate & left,const PickerDate & right) const728 int PickerDateComponent::SolarDateCompare(const PickerDate& left, const PickerDate& right) const
729 {
730     static const int leftEqualRight = 0; // means left = right
731     static const int leftGreatRight = 1; // means left > right
732     static const int leftLessRight = -1; // means left < right
733     if (left.GetYear() > right.GetYear()) {
734         return leftGreatRight;
735     }
736     if (left.GetYear() < right.GetYear()) {
737         return leftLessRight;
738     }
739     if (left.GetMonth() > right.GetMonth()) {
740         return leftGreatRight;
741     }
742     if (left.GetMonth() < right.GetMonth()) {
743         return leftLessRight;
744     }
745     if (left.GetDay() > right.GetDay()) {
746         return leftGreatRight;
747     }
748     if (left.GetDay() < right.GetDay()) {
749         return leftLessRight;
750     }
751     return leftEqualRight;
752 }
753 
LunarDateCompare(const LunarDate & left,const LunarDate & right) const754 int PickerDateComponent::LunarDateCompare(const LunarDate& left, const LunarDate& right) const
755 {
756     static const int leftEqualRight = 0; // means left = right
757     static const int leftGreatRight = 1; // means left > right
758     static const int leftLessRight = -1; // means left < right
759     static const double addingValue = 0.5; // adding value for leap month.
760     if (left.year > right.year) {
761         return leftGreatRight;
762     }
763     if (left.year < right.year) {
764         return leftLessRight;
765     }
766     double leftMonth = (left.isLeapMonth ? left.month + addingValue : left.month);
767     double rightMonth = (right.isLeapMonth ? right.month + addingValue : right.month);
768     if (GreatNotEqual(leftMonth, rightMonth)) {
769         return leftGreatRight;
770     }
771     if (LessNotEqual(leftMonth, rightMonth)) {
772         return leftLessRight;
773     }
774     if (left.day > right.day) {
775         return leftGreatRight;
776     }
777     if (left.day < right.day) {
778         return leftLessRight;
779     }
780     return leftEqualRight;
781 }
782 
783 } // namespace OHOS::Ace
784