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