• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) {
206         LOGE("year column is null.");
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     if (!isAdd && index == monthColumn->GetOptionCount() - 1) {
276         lunarDate.year = lunarDate.year - 1; // reduce to previous year
277         if (lunarDate.year < startDateLunar_.year) {
278             lunarDate.year = endDateLunar_.year;
279         }
280     }
281     uint32_t lunarLeapMonth = 0;
282     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
283     if (!hasLeapMonth && lunarDate.isLeapMonth) {
284         lunarDate.isLeapMonth = false;
285     }
286     uint32_t maxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
287     if (lunarDate.day > maxDay) {
288         lunarDate.day = maxDay;
289     }
290 
291     AdjustLunarDate(lunarDate);
292     LunarColumnsBuilding(lunarDate);
293 }
294 
HandleSolarMonthChange(bool isAdd,uint32_t index)295 void PickerDateComponent::HandleSolarMonthChange(bool isAdd, uint32_t index)
296 {
297     auto date = GetCurrentDate();
298     if (isAdd && date.GetMonth() == 1) { // first month is 1
299         date.SetYear(date.GetYear() + 1); // add 1 year, the next year
300         if (date.GetYear() > endDateSolar_.GetYear()) {
301             date.SetYear(startDateSolar_.GetYear());
302         }
303     }
304     if (!isAdd && date.GetMonth() == 12) { // the last month is 12
305         date.SetYear(date.GetYear() - 1); // reduce 1 year, the previous year
306         if (date.GetYear() < startDateSolar_.GetYear()) {
307             date.SetYear(endDateSolar_.GetYear());
308         }
309     }
310     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
311     if (date.GetDay() > maxDay) {
312         date.SetDay(maxDay);
313     }
314     AdjustSolarDate(date);
315     SolarColumnsBuilding(date);
316 }
317 
HandleDayChange(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)318 void PickerDateComponent::HandleDayChange(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
319 {
320     if (lunar_) {
321         HandleLunarDayChange(isAdd, index);
322     } else {
323         HandleSolarDayChange(isAdd, index);
324     }
325     resultTags.emplace_back(PICKER_YEAR_COLUMN);
326     resultTags.emplace_back(PICKER_MONTH_COLUMN);
327     resultTags.emplace_back(PICKER_DAY_COLUMN);
328 }
329 
HandleSolarDayChange(bool isAdd,uint32_t index)330 void PickerDateComponent::HandleSolarDayChange(bool isAdd, uint32_t index)
331 {
332     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
333     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
334     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
335     if (!yearColumn || !monthColumn || !dayColumn) {
336         LOGE("year or month or day column is null.");
337         return;
338     }
339 
340     auto date = GetCurrentDate();
341     if (isAdd && index == 0) {
342         date.SetMonth(date.GetMonth() + 1); // add to next month
343         if (date.GetMonth() > 12) { // invalidate month, max month is 12
344             date.SetMonth(1); // first month is 1
345             date.SetYear(date.GetYear() + 1); // add to next year
346             if (date.GetYear() > endDateSolar_.GetYear()) {
347                 date.SetYear(startDateSolar_.GetYear());
348             }
349         }
350     }
351     if (!isAdd && dayColumn->GetCurrentIndex() == dayColumn->GetOptionCount() - 1) { // last index is count - 1
352         date.SetMonth(date.GetMonth() - 1); // reduce to previous month
353         if (date.GetMonth() == 0) { // min month is 1, invalidate
354             date.SetMonth(12); // set to be the last month
355             date.SetYear(date.GetYear() - 1); // reduce to previous year
356             if (date.GetYear() < startDateSolar_.GetYear()) {
357                 date.SetYear(endDateSolar_.GetYear());
358             }
359         }
360         date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth())); // reduce to previous month's last day
361     }
362     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
363     if (date.GetDay() > maxDay) {
364         date.SetDay(maxDay);
365     }
366     AdjustSolarDate(date);
367     SolarColumnsBuilding(date);
368 }
369 
HandleLunarDayChange(bool isAdd,uint32_t index)370 void PickerDateComponent::HandleLunarDayChange(bool isAdd, uint32_t index)
371 {
372     if (isAdd) {
373         HandleAddLunarDayChange(index);
374     } else {
375         HandleReduceLunarDayChange(index);
376     }
377 }
378 
HandleAddLunarDayChange(uint32_t index)379 void PickerDateComponent::HandleAddLunarDayChange(uint32_t index)
380 {
381     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
382     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
383     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
384     if (!yearColumn || !monthColumn || !dayColumn) {
385         LOGE("year or month or day column is null.");
386         return;
387     }
388 
389     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
390     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
391     uint32_t lunarLeapMonth = 0;
392     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
393     if (index == 0) {
394         if (monthColumn->GetCurrentIndex() == monthColumn->GetOptionCount() - 1) { // max index is count - 1
395             lunarDate.year = lunarDate.year + 1; // add to next year
396             if (lunarDate.year > endDateLunar_.year) {
397                 lunarDate.year = startDateLunar_.year;
398             }
399             lunarDate.month = 1; // first month
400             lunarDate.isLeapMonth = false;
401         } else {
402             if (lunarDate.isLeapMonth) {
403                 lunarDate.month = lunarDate.month + 1; // add to next month
404                 lunarDate.isLeapMonth = false;
405             } else if (!hasLeapMonth) {
406                 lunarDate.month = lunarDate.month + 1; // add to next month
407             } else if (lunarLeapMonth == lunarDate.month) {
408                 lunarDate.isLeapMonth = true;
409             } else {
410                 lunarDate.month = lunarDate.month + 1; // add to next month
411             }
412         }
413     }
414 
415     AdjustLunarDate(lunarDate);
416     LunarColumnsBuilding(lunarDate);
417 }
418 
HandleReduceLunarDayChange(uint32_t index)419 void PickerDateComponent::HandleReduceLunarDayChange(uint32_t index)
420 {
421     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
422     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
423     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
424     if (!yearColumn || !monthColumn || !dayColumn) {
425         LOGE("year or month or day column is null.");
426         return;
427     }
428 
429     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
430     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
431     uint32_t lunarLeapMonth = 0;
432     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
433     if (dayColumn->GetCurrentIndex() == dayColumn->GetOptionCount() - 1) { // max index is count - 1
434         if (monthColumn->GetCurrentIndex() == 0) {
435             lunarDate.year = lunarDate.year - 1; // reduce to previous year
436             if (lunarDate.year < startDateLunar_.year) {
437                 lunarDate.year = endDateLunar_.year;
438             }
439             lunarDate.month = 12; // set to be previous year's max month
440             lunarDate.isLeapMonth = false;
441             if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
442                 lunarDate.isLeapMonth = true;
443             }
444             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
445         } else {
446             if (lunarDate.isLeapMonth) {
447                 lunarDate.isLeapMonth = false;
448             } else if (!hasLeapMonth) {
449                 lunarDate.month = lunarDate.month - 1; // reduce to previous month
450             } else if (lunarLeapMonth == lunarDate.month - 1) { // leap month is previous month
451                 lunarDate.isLeapMonth = true;
452                 lunarDate.month = lunarLeapMonth;
453             } else {
454                 lunarDate.month = lunarDate.month - 1; // reduce to previous month
455             }
456             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
457         }
458     }
459 
460     AdjustLunarDate(lunarDate);
461     LunarColumnsBuilding(lunarDate);
462 }
463 
GetYearFormatString(uint32_t year) const464 std::string PickerDateComponent::GetYearFormatString(uint32_t year) const
465 {
466     return PickerStringFormatter::GetYear(year);
467 }
468 
GetMonthFormatString(uint32_t month,bool isLunar,bool isLeap) const469 std::string PickerDateComponent::GetMonthFormatString(uint32_t month, bool isLunar, bool isLeap) const
470 {
471     if (isLunar) {
472         return PickerStringFormatter::GetLunarMonth(month, isLeap);
473     }
474 
475     return PickerStringFormatter::GetSolarMonth(month);
476 }
477 
GetDayFormatString(uint32_t day,bool isLunar) const478 std::string PickerDateComponent::GetDayFormatString(uint32_t day, bool isLunar) const
479 {
480     if (isLunar) {
481         return PickerStringFormatter::GetLunarDay(day);
482     }
483 
484     return PickerStringFormatter::GetSolarDay(day);
485 }
486 
OnLunarCallback(bool checked,std::vector<std::string> & resultTags)487 void PickerDateComponent::OnLunarCallback(bool checked, std::vector<std::string>& resultTags)
488 {
489     if (checked) {
490         auto solarDate = GetCurrentDate();
491         auto lunarDate = SolarToLunar(solarDate);
492         LunarColumnsBuilding(lunarDate);
493     } else {
494         auto solarDate = GetCurrentDate();
495         SolarColumnsBuilding(solarDate);
496     }
497 
498     resultTags.emplace_back(PICKER_YEAR_COLUMN);
499     resultTags.emplace_back(PICKER_MONTH_COLUMN);
500     resultTags.emplace_back(PICKER_DAY_COLUMN);
501 }
502 
SolarToLunar(const PickerDate & date) const503 LunarDate PickerDateComponent::SolarToLunar(const PickerDate& date) const
504 {
505     Date result;
506     result.year = date.GetYear();
507     result.month = date.GetMonth();
508     result.day = date.GetDay();
509     return Localization::GetInstance()->GetLunarDate(result);
510 }
511 
LunarToSolar(const LunarDate & date) const512 PickerDate PickerDateComponent::LunarToSolar(const LunarDate& date) const
513 {
514     uint32_t days = date.day - 1; // calculate days from 1900.1.1 to this date
515     if (date.isLeapMonth) {
516         days += LunarCalculator::GetLunarMonthDays(date.year, date.month);
517     } else {
518         uint32_t leapMonth = LunarCalculator::GetLunarLeapMonth(date.year);
519         if (leapMonth < date.month) {
520             days += LunarCalculator::GetLunarLeapDays(date.year);
521         }
522     }
523     for (uint32_t month = 1; month < date.month; ++month) { // month start from 1
524         days += LunarCalculator::GetLunarMonthDays(date.year, month);
525     }
526     for (uint32_t year = 1900; year < date.year; ++year) { // year start from 1900
527         days += LunarCalculator::GetLunarYearDays(year);
528     }
529     days += 30; // days from solar's 1900.1.1 to lunar's 1900.1.1 is 30
530     PickerDate result;
531     result.FromDays(days);
532     return result;
533 }
534 
GetLunarLeapMonth(uint32_t year,uint32_t & outLeapMonth) const535 bool PickerDateComponent::GetLunarLeapMonth(uint32_t year, uint32_t& outLeapMonth) const
536 {
537     auto leapMonth = LunarCalculator::GetLunarLeapMonth(year);
538     if (leapMonth <= 0) {
539         return false;
540     }
541 
542     outLeapMonth = static_cast<uint32_t>(leapMonth);
543     return true;
544 }
545 
GetLunarMaxDay(uint32_t year,uint32_t month,bool isLeap) const546 uint32_t PickerDateComponent::GetLunarMaxDay(uint32_t year, uint32_t month, bool isLeap) const
547 {
548     if (isLeap) {
549         return static_cast<uint32_t>(LunarCalculator::GetLunarLeapDays(year));
550     } else {
551         return static_cast<uint32_t>(LunarCalculator::GetLunarMonthDays(year, month));
552     }
553 }
554 
SolarColumnsBuilding(const PickerDate & current)555 void PickerDateComponent::SolarColumnsBuilding(const PickerDate& current)
556 {
557     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
558     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
559     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
560     if (!yearColumn || !monthColumn || !dayColumn) {
561         LOGE("year or month or day column is null.");
562         return;
563     }
564 
565     auto startYear = startDateSolar_.GetYear();
566     auto endYear = endDateSolar_.GetYear();
567     auto startMonth = startDateSolar_.GetMonth();
568     auto endMonth = endDateSolar_.GetMonth();
569     auto startDay = startDateSolar_.GetDay();
570     auto endDay = endDateSolar_.GetDay();
571     if (startYear > endYear) {
572         return;
573     }
574     if (startYear == endYear && startMonth > endMonth) {
575         return;
576     }
577     if (startYear == endYear && startMonth == endMonth && startDay > endDay) {
578         return;
579     }
580     uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), current.GetMonth());
581     if (startYear < endYear) {
582         startMonth = 1;
583         endMonth = 12;
584         startDay = 1;
585         endDay = maxDay;
586     }
587     if (startYear == endYear && startMonth < endMonth) {
588         startDay = 1;
589         endDay = maxDay;
590     }
591 
592     yearColumn->ClearOption();
593     for (uint32_t year = startYear; year <= endYear; ++year) {
594         if (year == current.GetYear()) {
595             yearColumn->SetCurrentIndex(yearColumn->GetOptionCount());
596         }
597         yearColumn->AppendOption(GetYearFormatString(year));
598     }
599 
600     monthColumn->ClearOption();
601     // solar's month start form 1 to 12
602     for (uint32_t month = startMonth; month <= endMonth; month++) {
603         if (month == current.GetMonth()) {
604             monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
605         }
606         monthColumn->AppendOption(GetMonthFormatString(month, false, false));
607     }
608 
609     dayColumn->ClearOption();
610 
611     // solar's day start from 1
612     for (uint32_t day = startDay; day <= endDay; day++) {
613         if (day == current.GetDay()) {
614             dayColumn->SetCurrentIndex(dayColumn->GetOptionCount());
615         }
616         dayColumn->AppendOption(GetDayFormatString(day, false));
617     }
618 
619     lunar_ = false;
620 }
621 
LunarColumnsBuilding(const LunarDate & current)622 void PickerDateComponent::LunarColumnsBuilding(const LunarDate& current)
623 {
624     auto yearColumn = GetColumn(PICKER_YEAR_COLUMN);
625     auto monthColumn = GetColumn(PICKER_MONTH_COLUMN);
626     auto dayColumn = GetColumn(PICKER_DAY_COLUMN);
627     if (!yearColumn || !monthColumn || !dayColumn) {
628         LOGE("year or month or day column is null.");
629         return;
630     }
631 
632     auto startYear = startDateLunar_.year;
633     auto endYear = endDateLunar_.year;
634     auto startMonth = startDateLunar_.month;
635     auto endMonth = endDateLunar_.month;
636     auto startDay = startDateLunar_.day;
637     auto endDay = endDateLunar_.day;
638     if (startYear > endYear) {
639         return;
640     }
641     if (startYear == endYear && startMonth > endMonth) {
642         return;
643     }
644     if (startYear == endYear && startMonth == endMonth && startDay > endDay) {
645         return;
646     }
647     uint32_t maxDay = GetLunarMaxDay(current.year, current.month, current.isLeapMonth);
648     if (startYear < endYear) {
649         startMonth = 1;
650         endMonth = 12;
651         startDay = 1;
652         endDay = maxDay;
653     }
654     if (startYear == endYear && startMonth < endMonth) {
655         startDay = 1;
656         endDay = maxDay;
657     }
658 
659     yearColumn->ClearOption();
660     for (uint32_t index = startYear; index <= endYear; ++index) {
661         if (current.year == index) {
662             yearColumn->SetCurrentIndex(yearColumn->GetOptionCount());
663         }
664         yearColumn->AppendOption(GetYearFormatString(index));
665     }
666 
667     uint32_t lunarLeapMonth = 0;
668     bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
669     monthColumn->ClearOption();
670     // lunar's month start form startMonth to endMonth
671     for (uint32_t index = startMonth; index <= endMonth; ++index) {
672         if (!current.isLeapMonth && current.month == index) {
673             monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
674         }
675         monthColumn->AppendOption(GetMonthFormatString(index, true, false));
676         if (hasLeapMonth && lunarLeapMonth == index) {
677             if (current.isLeapMonth && current.month == index) {
678                 monthColumn->SetCurrentIndex(monthColumn->GetOptionCount());
679             }
680             monthColumn->AppendOption(GetMonthFormatString(index, true, true));
681         }
682     }
683 
684 
685     dayColumn->ClearOption();
686     // lunar's day start from startDay
687     for (uint32_t index = startDay; index <= endDay; ++index) {
688         if (current.day == index) {
689             dayColumn->SetCurrentIndex(dayColumn->GetOptionCount());
690         }
691         dayColumn->AppendOption(GetDayFormatString(index, true));
692     }
693 
694     lunar_ = true;
695 }
696 
AdjustSolarDate(PickerDate & date) const697 void PickerDateComponent::AdjustSolarDate(PickerDate& date) const
698 {
699     AdjustSolarDate(date, startDateSolar_, endDateSolar_);
700 }
701 
AdjustSolarDate(PickerDate & date,const PickerDate & start,const PickerDate & end) const702 void PickerDateComponent::AdjustSolarDate(PickerDate& date, const PickerDate& start, const PickerDate& end) const
703 {
704     if (SolarDateCompare(date, start) < 0) {
705         date = start;
706         return;
707     }
708     if (SolarDateCompare(date, end) > 0) {
709         date = end;
710     }
711 }
712 
AdjustLunarDate(LunarDate & date) const713 void PickerDateComponent::AdjustLunarDate(LunarDate& date) const
714 {
715     if (LunarDateCompare(date, startDateLunar_) < 0) {
716         date = startDateLunar_;
717         return;
718     }
719     if (LunarDateCompare(date, endDateLunar_) > 0) {
720         date = endDateLunar_;
721     }
722 }
723 
SolarDateCompare(const PickerDate & left,const PickerDate & right) const724 int PickerDateComponent::SolarDateCompare(const PickerDate& left, const PickerDate& right) const
725 {
726     static const int leftEqualRight = 0; // means left = right
727     static const int leftGreatRight = 1; // means left > right
728     static const int leftLessRight = -1; // means left < right
729     if (left.GetYear() > right.GetYear()) {
730         return leftGreatRight;
731     }
732     if (left.GetYear() < right.GetYear()) {
733         return leftLessRight;
734     }
735     if (left.GetMonth() > right.GetMonth()) {
736         return leftGreatRight;
737     }
738     if (left.GetMonth() < right.GetMonth()) {
739         return leftLessRight;
740     }
741     if (left.GetDay() > right.GetDay()) {
742         return leftGreatRight;
743     }
744     if (left.GetDay() < right.GetDay()) {
745         return leftLessRight;
746     }
747     return leftEqualRight;
748 }
749 
LunarDateCompare(const LunarDate & left,const LunarDate & right) const750 int PickerDateComponent::LunarDateCompare(const LunarDate& left, const LunarDate& right) const
751 {
752     static const int leftEqualRight = 0; // means left = right
753     static const int leftGreatRight = 1; // means left > right
754     static const int leftLessRight = -1; // means left < right
755     static const double addingValue = 0.5; // adding value for leap month.
756     if (left.year > right.year) {
757         return leftGreatRight;
758     }
759     if (left.year < right.year) {
760         return leftLessRight;
761     }
762     double leftMonth = (left.isLeapMonth ? left.month + addingValue : left.month);
763     double rightMonth = (right.isLeapMonth ? right.month + addingValue : right.month);
764     if (GreatNotEqual(leftMonth, rightMonth)) {
765         return leftGreatRight;
766     }
767     if (LessNotEqual(leftMonth, rightMonth)) {
768         return leftLessRight;
769     }
770     if (left.day > right.day) {
771         return leftGreatRight;
772     }
773     if (left.day < right.day) {
774         return leftLessRight;
775     }
776     return leftEqualRight;
777 }
778 
779 } // namespace OHOS::Ace
780