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