1/*
2 Copyright (c) 2002 Carlos Moro <cfmoro@correo.uniovi.es>
3 Copyright (c) 2002 Hans Petter Bieker <bieker@kde.org>
4 Copyright 2007, 2008, 2009, 2010 John Layt <john@layt.net>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "kcalendarsystem.h"
23#include "kcalendarsystemprivate_p.h"
24
25#include "kdebug.h"
26#include "kconfiggroup.h"
27
28#include <QtCore/QDateTime>
29
30#include "kdatetime.h"
31#include "kdatetimeformatter_p.h"
32#include "kdatetimeparser_p.h"
33#include "kcalendarera_p.h"
34#include "kcalendarsystemcoptic_p.h"
35#include "kcalendarsystemethiopian_p.h"
36#include "kcalendarsystemgregorian_p.h"
37#include "kcalendarsystemhebrew_p.h"
38#include "kcalendarsystemindiannational_p.h"
39#include "kcalendarsystemislamiccivil_p.h"
40#include "kcalendarsystemjalali_p.h"
41#include "kcalendarsystemjapanese_p.h"
42#include "kcalendarsystemjulian_p.h"
43#include "kcalendarsystemminguo_p.h"
44#include "kcalendarsystemqdate_p.h"
45#include "kcalendarsystemthai_p.h"
46
47KCalendarSystem *KCalendarSystem::create(const QString &calendarType, const KLocale *locale)
48{
49 return create(calendarSystem(calendarType), locale);
50}
51
52KCalendarSystem *KCalendarSystem::create(const QString &calendarType, KSharedConfig::Ptr config,
53 const KLocale *locale)
54{
55 return create(calendarSystem(calendarType), config, locale);
56}
57
58QStringList KCalendarSystem::calendarSystems()
59{
60 QStringList lst;
61
62 lst.append(QLatin1String("coptic"));
63 lst.append(QLatin1String("ethiopian"));
64 lst.append(QLatin1String("gregorian"));
65 lst.append(QLatin1String("gregorian-proleptic"));
66 lst.append(QLatin1String("hebrew"));
67 lst.append(QLatin1String("hijri"));
68 lst.append(QLatin1String("indian-national"));
69 lst.append(QLatin1String("jalali"));
70 lst.append(QLatin1String("japanese"));
71 lst.append(QLatin1String("julian"));
72 lst.append(QLatin1String("minguo"));
73 lst.append(QLatin1String("thai"));
74
75 return lst;
76}
77
78QString KCalendarSystem::calendarLabel(const QString &calendarType)
79{
80 if (calendarSystemsList().contains(calendarSystem(calendarType))) {
81 return KCalendarSystem::calendarLabel(KCalendarSystem::calendarSystem(calendarType));
82 } else {
83 return ki18nc("@item Calendar system", "Invalid Calendar Type").toString(KGlobal::locale());
84 }
85}
86
87KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem, const KLocale *locale)
88{
89 return create(calendarSystem, KSharedConfig::Ptr(), locale);
90}
91
92KCalendarSystem *KCalendarSystem::create(KLocale::CalendarSystem calendarSystem,
93 KSharedConfig::Ptr config,
94 const KLocale *locale)
95{
96 switch (calendarSystem) {
97 case KLocale::QDateCalendar:
98 return new KCalendarSystemQDate(config, locale);
99 case KLocale::CopticCalendar:
100 return new KCalendarSystemCoptic(config, locale);
101 case KLocale::EthiopianCalendar:
102 return new KCalendarSystemEthiopian(config, locale);
103 case KLocale::GregorianCalendar:
104 return new KCalendarSystemGregorian(config, locale);
105 case KLocale::HebrewCalendar:
106 return new KCalendarSystemHebrew(config, locale);
107 case KLocale::IndianNationalCalendar:
108 return new KCalendarSystemIndianNational(config, locale);
109 case KLocale::IslamicCivilCalendar:
110 return new KCalendarSystemIslamicCivil(config, locale);
111 case KLocale::JalaliCalendar:
112 return new KCalendarSystemJalali(config, locale);
113 case KLocale::JapaneseCalendar:
114 return new KCalendarSystemJapanese(config, locale);
115 case KLocale::JulianCalendar:
116 return new KCalendarSystemJulian(config, locale);
117 case KLocale::MinguoCalendar:
118 return new KCalendarSystemMinguo(config, locale);
119 case KLocale::ThaiCalendar:
120 return new KCalendarSystemThai(config, locale);
121 default:
122 return new KCalendarSystemQDate(config, locale);
123 }
124}
125
126QList<KLocale::CalendarSystem> KCalendarSystem::calendarSystemsList()
127{
128 QList<KLocale::CalendarSystem> list;
129
130 list.append(KLocale::QDateCalendar);
131 list.append(KLocale::CopticCalendar);
132 list.append(KLocale::EthiopianCalendar);
133 list.append(KLocale::GregorianCalendar);
134 list.append(KLocale::HebrewCalendar);
135 list.append(KLocale::IslamicCivilCalendar);
136 list.append(KLocale::IndianNationalCalendar);
137 list.append(KLocale::JalaliCalendar);
138 list.append(KLocale::JapaneseCalendar);
139 list.append(KLocale::JulianCalendar);
140 list.append(KLocale::MinguoCalendar);
141 list.append(KLocale::ThaiCalendar);
142
143 return list;
144}
145
146QString KCalendarSystem::calendarLabel(KLocale::CalendarSystem calendarSystem, const KLocale *locale)
147{
148 switch (calendarSystem) {
149 case KLocale::QDateCalendar:
150 return ki18nc("@item Calendar system", "Gregorian").toString(locale);
151 case KLocale::CopticCalendar:
152 return ki18nc("@item Calendar system", "Coptic").toString(locale);
153 case KLocale::EthiopianCalendar:
154 return ki18nc("@item Calendar system", "Ethiopian").toString(locale);
155 case KLocale::GregorianCalendar:
156 return ki18nc("@item Calendar system", "Gregorian (Proleptic)").toString(locale);
157 case KLocale::HebrewCalendar:
158 return ki18nc("@item Calendar system", "Hebrew").toString(locale);
159 case KLocale::IslamicCivilCalendar:
160 return ki18nc("@item Calendar system", "Islamic / Hijri (Civil)").toString(locale);
161 case KLocale::IndianNationalCalendar:
162 return ki18nc("@item Calendar system", "Indian National").toString(locale);
163 case KLocale::JalaliCalendar:
164 return ki18nc("@item Calendar system", "Jalali").toString(locale);
165 case KLocale::JapaneseCalendar:
166 return ki18nc("@item Calendar system", "Japanese").toString(locale);
167 case KLocale::JulianCalendar:
168 return ki18nc("@item Calendar system", "Julian").toString(locale);
169 case KLocale::MinguoCalendar:
170 return ki18nc("@item Calendar system", "Taiwanese").toString(locale);
171 case KLocale::ThaiCalendar:
172 return ki18nc("@item Calendar system", "Thai").toString(locale);
173 }
174
175 return ki18nc("@item Calendar system", "Invalid Calendar Type").toString(locale);
176}
177
178KLocale::CalendarSystem KCalendarSystem::calendarSystemForCalendarType(const QString &calendarType )
179{
180 return calendarSystem( calendarType );
181}
182
183KLocale::CalendarSystem KCalendarSystem::calendarSystem(const QString &calendarType )
184{
185 if (calendarType == QLatin1String("coptic")) {
186 return KLocale::CopticCalendar;
187 } else if (calendarType == QLatin1String("ethiopian")) {
188 return KLocale::EthiopianCalendar;
189 } else if (calendarType == QLatin1String("gregorian")) {
190 return KLocale::QDateCalendar;
191 } else if (calendarType == QLatin1String("gregorian-proleptic")) {
192 return KLocale::GregorianCalendar;
193 } else if (calendarType == QLatin1String("hebrew")) {
194 return KLocale::HebrewCalendar;
195 } else if (calendarType == QLatin1String("hijri")) {
196 return KLocale::IslamicCivilCalendar;
197 } else if (calendarType == QLatin1String("indian-national")) {
198 return KLocale::IndianNationalCalendar;
199 } else if (calendarType == QLatin1String("jalali")) {
200 return KLocale::JalaliCalendar;
201 } else if (calendarType == QLatin1String("japanese")) {
202 return KLocale::JapaneseCalendar;
203 } else if (calendarType == QLatin1String("julian")) {
204 return KLocale::JulianCalendar;
205 } else if (calendarType == QLatin1String("minguo")) {
206 return KLocale::MinguoCalendar;
207 } else if (calendarType == QLatin1String("thai")) {
208 return KLocale::ThaiCalendar;
209 } else {
210 return KLocale::QDateCalendar;
211 }
212}
213
214QString KCalendarSystem::calendarType(KLocale::CalendarSystem calendarSystem)
215{
216 if (calendarSystem == KLocale::QDateCalendar) {
217 return QLatin1String("gregorian");
218 } else if (calendarSystem == KLocale::CopticCalendar) {
219 return QLatin1String("coptic");
220 } else if (calendarSystem == KLocale::EthiopianCalendar) {
221 return QLatin1String("ethiopian");
222 } else if (calendarSystem == KLocale::GregorianCalendar) {
223 return QLatin1String("gregorian-proleptic");
224 } else if (calendarSystem == KLocale::HebrewCalendar) {
225 return QLatin1String("hebrew");
226 } else if (calendarSystem == KLocale::IndianNationalCalendar) {
227 return QLatin1String("indian-national");
228 } else if (calendarSystem == KLocale::IslamicCivilCalendar) {
229 return QLatin1String("hijri");
230 } else if (calendarSystem == KLocale::JalaliCalendar) {
231 return QLatin1String("jalali");
232 } else if (calendarSystem == KLocale::JapaneseCalendar) {
233 return QLatin1String("japanese");
234 } else if (calendarSystem == KLocale::JulianCalendar) {
235 return QLatin1String("julian");
236 } else if (calendarSystem == KLocale::MinguoCalendar) {
237 return QLatin1String("minguo");
238 } else if (calendarSystem == KLocale::ThaiCalendar) {
239 return QLatin1String("thai");
240 } else {
241 return QLatin1String("gregorian");
242 }
243}
244
245// Shared d pointer base class definitions
246
247KCalendarSystemPrivate::KCalendarSystemPrivate(KCalendarSystem *q_ptr)
248 : q(q_ptr),
249 m_eraList(0),
250 m_shortYearWindowStartYear(2000)
251{
252}
253
254KCalendarSystemPrivate::~KCalendarSystemPrivate()
255{
256 delete m_eraList;
257}
258
259// Dummy version using Gregorian as an example
260// This method MUST be re-implemented in any new Calendar System
261KLocale::CalendarSystem KCalendarSystemPrivate::calendarSystem() const
262{
263 return KLocale::QDateCalendar;
264}
265
266// Dummy version as an example, remember to translate (see Gregorian for example)
267// Add the Era's in chronological order, from earliest to latest
268// This method MUST be re-implemented in any new Calendar System
269void KCalendarSystemPrivate::loadDefaultEraList()
270{
271 addEra('-', 1, q->epoch().addDays(-1), -1, q->earliestValidDate(), QLatin1String("Before KDE"), QLatin1String("BK"), QLatin1String("%Ey %EC"));
272 addEra('+', 1, q->epoch(), 1, q->latestValidDate(), QLatin1String("Anno KDE"), QLatin1String("AK"), QLatin1String("%Ey %EC"));
273}
274
275// Dummy version using Gregorian as an example
276// This method MUST be re-implemented in any new Calendar System
277int KCalendarSystemPrivate::monthsInYear(int year) const
278{
279 Q_UNUSED(year)
280 return 12;
281}
282
283// Dummy version using Gregorian as an example
284// This method MUST be re-implemented in any new Calendar System
285int KCalendarSystemPrivate::daysInMonth(int year, int month) const
286{
287 if (month == 2) {
288 if (isLeapYear(year)) {
289 return 29;
290 } else {
291 return 28;
292 }
293 }
294
295 if (month == 4 || month == 6 || month == 9 || month == 11) {
296 return 30;
297 }
298
299 return 31;
300}
301
302// Dummy version using Gregorian as an example
303// This method MUST be re-implemented in any new Calendar System
304int KCalendarSystemPrivate::daysInYear(int year) const
305{
306 if (isLeapYear(year)) {
307 return 366;
308 } else {
309 return 365;
310 }
311}
312
313// Dummy version using Gregorian as an example
314// This method MUST be re-implemented in any new Calendar System
315int KCalendarSystemPrivate::daysInWeek() const
316{
317 return 7;
318}
319
320// Dummy version using Gregorian as an example
321// This method MUST be re-implemented in any new Calendar System
322bool KCalendarSystemPrivate::isLeapYear(int year) const
323{
324 if (year < 1) {
325 year = year + 1;
326 }
327
328 if (year % 4 == 0) {
329 if (year % 100 != 0) {
330 return true;
331 } else if (year % 400 == 0) {
332 return true;
333 }
334 }
335
336 return false;
337}
338
339// Dummy version using Gregorian as an example
340// This method MUST be re-implemented in any new Calendar System
341bool KCalendarSystemPrivate::hasLeapMonths() const
342{
343 return false;
344}
345
346// Dummy version using Gregorian as an example
347// This method MUST be re-implemented in any new Calendar System
348bool KCalendarSystemPrivate::hasYearZero() const
349{
350 return false;
351}
352
353// Dummy version using Gregorian as an example
354// This method MUST be re-implemented in any new Calendar System
355int KCalendarSystemPrivate::maxDaysInWeek() const
356{
357 return 7;
358}
359
360// Dummy version using Gregorian as an example
361// This method MUST be re-implemented in any new Calendar System
362int KCalendarSystemPrivate::maxMonthsInYear() const
363{
364 return 12;
365}
366
367// Convenince, faster than calling year( ealiestValidDate() ),
368// needed in fake-virtual functions so don't remove
369// Dummy version using Gregorian as an example
370// This method MUST be re-implemented in any new Calendar System
371int KCalendarSystemPrivate::earliestValidYear() const
372{
373 return -4712;
374}
375
376// Convenince, faster than calling year( latestValidDate() ),
377// needed in fake-virtual functions so don't remove
378// Dummy version using Gregorian as an example
379// This method MUST be re-implemented in any new Calendar System
380int KCalendarSystemPrivate::latestValidYear() const
381{
382 return 9999;
383}
384
385// Dummy version
386// This method MUST be re-implemented in any new Calendar System
387QString KCalendarSystemPrivate::monthName(int month, int year, KLocale::DateTimeComponentFormat format, bool possessive) const
388{
389 Q_UNUSED(month);
390 Q_UNUSED(year);
391 Q_UNUSED(format);
392 Q_UNUSED(possessive);
393 return QString();
394}
395
396// Dummy version
397// This method MUST be re-implemented in any new Calendar System
398QString KCalendarSystemPrivate::weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const
399{
400 Q_UNUSED(weekDay);
401 Q_UNUSED(format);
402 return QString();
403}
404
405// Reimplement if special maths handling required, e.g. Hebrew.
406int KCalendarSystemPrivate::week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum) const
407{
408 int y, m, d;
409 q->julianDayToDate(date.toJulianDay(), y, m, d);
410
411 switch (weekNumberSystem) {
412 case KLocale::IsoWeekNumber:
413 return isoWeekNumber(date, yearNum);
414 case KLocale::FirstFullWeek:
415 return regularWeekNumber(date, locale()->weekStartDay(), 0, yearNum);
416 case KLocale::FirstPartialWeek:
417 return regularWeekNumber(date, locale()->weekStartDay(), 1, yearNum);
418 case KLocale::SimpleWeek:
419 return simpleWeekNumber(date, yearNum);
420 case KLocale::DefaultWeekNumber:
421 default:
422 return week(date, locale()->weekNumberSystem(), yearNum);
423 }
424}
425
426// Reimplement if special maths handling required, e.g. Hebrew.
427int KCalendarSystemPrivate::isoWeekNumber(const QDate &date, int *yearNum) const
428{
429 int y, m, d;
430 q->julianDayToDate(date.toJulianDay(), y, m, d);
431
432 QDate firstDayWeek1, lastDay;
433 int week;
434 int weekDay1, dayOfWeek1InYear;
435
436 // let's guess 1st day of 1st week
437 firstDayWeek1 = firstDayOfYear(y);
438 weekDay1 = dayOfWeek(firstDayWeek1);
439
440 // iso 8601: week 1 is the first containing thursday and week starts on monday
441 if (weekDay1 > 4 /*Thursday*/) {
442 firstDayWeek1 = q->addDays(firstDayWeek1 , daysInWeek() - weekDay1 + 1); // next monday
443 }
444
445 dayOfWeek1InYear = dayOfYear(firstDayWeek1);
446
447 // our date in prev year's week
448 if (dayOfYear(date) < dayOfWeek1InYear) {
449 if (yearNum) {
450 *yearNum = addYears(y, - 1);
451 }
452 return isoWeeksInYear(addYears(y, - 1));
453 }
454
455 // let's check if its last week belongs to next year
456 lastDay = lastDayOfYear(y);
457
458 // if our date is in last week && 1st week in next year has thursday
459 if ((dayOfYear(date) >= daysInYear(y) - dayOfWeek(lastDay) + 1)
460 && dayOfWeek(lastDay) < 4) {
461 if (yearNum) {
462 * yearNum = addYears(y, 1);
463 }
464 week = 1;
465 } else {
466 // To calculate properly the number of weeks from day a to x let's make a day 1 of week
467 if (weekDay1 < 5) {
468 firstDayWeek1 = q->addDays(firstDayWeek1, -(weekDay1 - 1));
469 }
470
471 if (yearNum) {
472 * yearNum = y;
473 }
474
475 week = firstDayWeek1.daysTo(date) / daysInWeek() + 1;
476 }
477
478 return week;
479}
480
481// Reimplement if special maths handling required, e.g. Hebrew.
482int KCalendarSystemPrivate::regularWeekNumber(const QDate &date, int weekStartDay, int firstWeekNumber, int *weekYear) const
483{
484 int y, m, d;
485 q->julianDayToDate(date.toJulianDay(), y, m, d);
486
487 int firstWeekDayOffset = (dayOfWeek(date) - weekStartDay + daysInWeek()) % daysInWeek();
488 int dayInYear = date.toJulianDay() - firstDayOfYear(y).toJulianDay(); // 0 indexed
489 int week = ((dayInYear - firstWeekDayOffset + daysInWeek()) / daysInWeek());
490
491 if (dayOfWeek(firstDayOfYear(y)) != weekStartDay) {
492 week = week + firstWeekNumber;
493 }
494
495 if (week < 1) {
496 y = y - 1;
497 week = regularWeeksInYear(y, weekStartDay, firstWeekNumber);
498 }
499
500 if (weekYear) {
501 *weekYear = y;
502 }
503
504 return week;
505}
506
507// Reimplement if special maths handling required, e.g. Hebrew.
508int KCalendarSystemPrivate::simpleWeekNumber(const QDate &date, int *yearNum) const
509{
510 int y, m, d;
511 q->julianDayToDate(date.toJulianDay(), y, m, d);
512 if (yearNum) {
513 *yearNum = y;
514 }
515 return ((date.toJulianDay() - firstDayOfYear(y).toJulianDay()) / daysInWeek()) + 1;
516}
517
518// Reimplement if special maths handling required, e.g. Hebrew.
519int KCalendarSystemPrivate::weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const
520{
521 switch (weekNumberSystem) {
522 case KLocale::IsoWeekNumber:
523 return isoWeeksInYear(year);
524 case KLocale::FirstFullWeek:
525 return regularWeeksInYear(year, locale()->weekStartDay(), 0);
526 case KLocale::FirstPartialWeek:
527 return regularWeeksInYear(year, locale()->weekStartDay(), 1);
528 case KLocale::SimpleWeek:
529 return simpleWeeksInYear(year);
530 case KLocale::DefaultWeekNumber:
531 default:
532 return weeksInYear(year, locale()->weekNumberSystem());
533 }
534}
535
536// Reimplement if special maths handling required, e.g. Hebrew.
537int KCalendarSystemPrivate::isoWeeksInYear(int year) const
538{
539 QDate lastDayOfThisYear = lastDayOfYear(year);
540
541 int weekYear = year;
542 int lastWeekInThisYear = isoWeekNumber(lastDayOfThisYear, &weekYear);
543
544 // If error, or the last day of the year is in the first week of next year use the week before
545 if (lastWeekInThisYear < 1 || weekYear != year) {
546 lastWeekInThisYear = isoWeekNumber(q->addDays(lastDayOfThisYear, -7), &weekYear);
547 }
548
549 return lastWeekInThisYear;
550}
551
552// Reimplement if special maths handling required, e.g. Hebrew.
553int KCalendarSystemPrivate::regularWeeksInYear(int year, int weekStartDay, int firstWeekNumber) const
554{
555 return regularWeekNumber(lastDayOfYear(year), weekStartDay, firstWeekNumber, 0);
556}
557
558// Reimplement if special maths handling required, e.g. Hebrew.
559int KCalendarSystemPrivate::simpleWeeksInYear(int year) const
560{
561 return simpleWeekNumber(lastDayOfYear(year), 0);
562}
563
564// Reimplement if special maths handling required, e.g. Hebrew.
565// Works for calendars with constant number of months, or where leap month is last month of year
566// Will not work for Hebrew or others where leap month is inserted in middle of year
567void KCalendarSystemPrivate::dateDifference(const QDate &fromDate, const QDate &toDate,
568 int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const
569{
570 // This could be optimised a little but is left in full as it's easier to understand
571 int dy = 0;
572 int dm = 0;
573 int dd = 0;
574 int dir = 1;
575
576 if (toDate < fromDate) {
577 dateDifference(toDate, fromDate, &dy, &dm, &dd, 0);
578 dir = -1;
579 } else if (toDate > fromDate) {
580
581 int fromYear = q->year(fromDate);
582 int toYear = q->year(toDate);
583 int fromMonth = q->month(fromDate);
584 int toMonth = q->month(toDate);
585 int fromDay = q->day(fromDate);
586 int toDay = q->day(toDate);
587
588 int monthsInPrevYear = monthsInYear(addYears(toYear, -1));
589 int daysInPrevMonth = q->daysInMonth(q->addMonths(toDate, -1));
590 int daysInFromMonth = daysInMonth(fromYear, fromMonth);
591 int daysInToMonth = daysInMonth(toYear, toMonth);
592
593 // Calculate years difference
594 if (toYear == fromYear) {
595 dy = 0;
596 } else if (toMonth > fromMonth) {
597 dy = differenceYearNumbers(fromYear, toYear);
598 } else if (toMonth < fromMonth) {
599 dy = differenceYearNumbers(fromYear, toYear) - 1;
600 } else { // toMonth == fromMonth
601 // Allow for last day of month to last day of month and leap days
602 // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years
603 if ((toDay >= fromDay) || (fromDay == daysInFromMonth && toDay == daysInToMonth)) {
604 dy = differenceYearNumbers(fromYear, toYear);
605 } else {
606 dy = differenceYearNumbers(fromYear, toYear) - 1;
607 }
608 }
609
610 // Calculate months and days difference
611 if (toDay >= fromDay) {
612 dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear;
613 dd = toDay - fromDay;
614 } else { // toDay < fromDay
615 // Allow for last day of month to last day of month and leap days
616 // e.g. 2010-03-31 to 2010-04-30 is 1 month
617 // 2000-02-29 to 2001-02-28 is 1 year
618 // 2000-02-29 to 2001-03-01 is 1 year 1 day
619 int prevMonth = q->month(q->addMonths(toDate, -1));
620 if (fromDay == daysInFromMonth && toDay == daysInToMonth) {
621 dm = (monthsInPrevYear + toMonth - fromMonth) % monthsInPrevYear;
622 dd = 0;
623 } else if (prevMonth == fromMonth && daysInPrevMonth < daysInFromMonth) {
624 // Special case where fromDate = leap day and toDate in month following but non-leap year
625 // e.g. 2000-02-29 to 2001-03-01 needs to use 29 to calculate day number not 28
626 dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear;
627 dd = (daysInFromMonth + toDay - fromDay) % daysInFromMonth;
628 } else {
629 dm = (monthsInPrevYear + toMonth - fromMonth - 1) % monthsInPrevYear;
630 dd = (daysInPrevMonth + toDay - fromDay) % daysInPrevMonth;
631 }
632 }
633
634 }
635
636 // Only return values if we have a valid pointer
637 if (yearsDiff) {
638 *yearsDiff = dy;
639 }
640 if (monthsDiff) {
641 *monthsDiff = dm;
642 }
643 if (daysDiff) {
644 *daysDiff = dd;
645 }
646 if (direction) {
647 *direction = dir;
648 }
649}
650
651// Reimplement if special maths handling required, e.g. Hebrew
652// Allows for calendars with leap months at end of year but not during year
653int KCalendarSystemPrivate::yearsDifference(const QDate &fromDate, const QDate &toDate) const
654{
655 // This could be optimised a little but is left in full as it's easier to understand
656 // Alternatively could just call dateDifference(), but this is slightly more efficient
657
658 if (toDate < fromDate) {
659 return 0 - yearsDifference(toDate, fromDate);
660 }
661
662 if (toDate == fromDate) {
663 return 0;
664 }
665
666 int fromYear = q->year(fromDate);
667 int toYear = q->year(toDate);
668
669 if (toYear == fromYear) {
670 return 0;
671 }
672
673 int fromMonth = q->month(fromDate);
674 int toMonth = q->month(toDate);
675
676 if (toMonth > fromMonth) {
677 return differenceYearNumbers(fromYear, toYear);
678 }
679
680 if (toMonth < fromMonth) {
681 return differenceYearNumbers(fromYear, toYear) - 1;
682 }
683
684 // toMonth == fromMonth
685 int fromDay = q->day(fromDate);
686 int toDay = q->day(toDate);
687
688 // Adjust for month numbers in from and to year
689 // Allow for last day of month to last day of month and leap days
690 // e.g. 2000-02-29 to 2001-02-28 is 1 year not 0 years
691 if ((toDay >= fromDay) ||
692 (fromDay == daysInMonth(fromYear, fromMonth) &&
693 toDay == daysInMonth(toYear, toMonth))) {
694 return differenceYearNumbers(fromYear, toYear);
695 } else {
696 return differenceYearNumbers(fromYear, toYear) - 1;
697 }
698
699}
700
701// Reimplement if special maths handling required, e.g. maybe Hebrew?
702// Allows for calendars with leap months
703int KCalendarSystemPrivate::monthsDifference(const QDate &fromDate, const QDate &toDate) const
704{
705 if (toDate < fromDate) {
706 return 0 - monthsDifference(toDate, fromDate);
707 }
708
709 if (toDate == fromDate) {
710 return 0;
711 }
712
713 int fromYear = q->year(fromDate);
714 int toYear = q->year(toDate);
715 int fromMonth = q->month(fromDate);
716 int toMonth = q->month(toDate);
717 int fromDay = q->day(fromDate);
718 int toDay = q->day(toDate);
719
720 int monthsInPreceedingYears;
721
722 // Calculate number of months in full years preceding toYear
723 if (toYear == fromYear) {
724 monthsInPreceedingYears = 0;
725 } else if (hasLeapMonths()) {
726 monthsInPreceedingYears = 0;
727 for (int y = fromYear; y < toYear; y = addYears(y, 1)) {
728 monthsInPreceedingYears = monthsInPreceedingYears + monthsInYear(y);
729 }
730 } else {
731 monthsInPreceedingYears = differenceYearNumbers(fromYear, toYear) * monthsInYear(toYear);
732 }
733
734 // Adjust for months in from and to year
735 // Allow for last day of month to last day of month and leap days
736 // e.g. 2010-03-31 to 2010-04-30 is 1 month not 0 months
737 // also 2000-02-29 to 2001-02-28 is 12 months not 11 months
738 if ((toDay >= fromDay) ||
739 (fromDay == daysInMonth(fromYear, fromMonth) &&
740 toDay == daysInMonth(toYear, toMonth))) {
741 return monthsInPreceedingYears + toMonth - fromMonth;
742 } else {
743 return monthsInPreceedingYears + toMonth - fromMonth - 1;
744 }
745}
746
747// Reimplement if special string to integer handling required, e.g. Hebrew.
748// Peel a number off the front of a string which may have other trailing chars after the number
749// Stop either at either maxLength, eos, or first non-digit char
750int KCalendarSystemPrivate::integerFromString(const QString &string, int maxLength, int &readLength) const
751{
752 int value = -1;
753 int position = 0;
754 readLength = 0;
755 bool ok = false;
756
757 if (maxLength < 0) {
758 maxLength = string.length();
759 }
760
761 while (position < string.length() &&
762 position < maxLength &&
763 string.at(position).isDigit()) {
764 position++;
765 }
766
767 if (position > 0) {
768 value = string.left(position).toInt(&ok);
769 if (ok) {
770 readLength = position;
771 } else {
772 value = -1;
773 }
774 }
775
776 return value;
777}
778
779// Reimplement if special integer to string handling required, e.g. Hebrew.
780// Utility to convert an integer into the correct display string form
781QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar) const
782{
783 return stringFromInteger(number, padWidth, padChar, q->locale()->dateTimeDigitSet());
784}
785
786// Reimplement if special integer to string handling required, e.g. Hebrew.
787// Utility to convert an integer into the correct display string form
788QString KCalendarSystemPrivate::stringFromInteger(int number, int padWidth, QChar padChar, KLocale::DigitSet digitSet) const
789{
790 if (padChar == QLatin1Char('\0') || padWidth == 0) {
791 return q->locale()->convertDigits(QString::number(number), digitSet);
792 } else {
793 return q->locale()->convertDigits(QString::number(number).rightJustified(padWidth, padChar), digitSet);
794 }
795}
796
797// Allows us to set dates outside publically valid range, USE WITH CARE!!!!
798bool KCalendarSystemPrivate::setAnyDate(QDate &date, int year, int month, int day) const
799{
800 int jd;
801 q->dateToJulianDay(year, month, day, jd);
802 date = QDate::fromJulianDay(jd);
803 return true;
804}
805
806// Utility to correctly add years to a year number because some systems such as
807// Julian and Gregorian calendars don't have a year 0
808int KCalendarSystemPrivate::addYears(int originalYear, int addYears) const
809{
810 int newYear = originalYear + addYears;
811
812 if (!hasYearZero()) {
813 if (originalYear > 0 && newYear <= 0) {
814 newYear = newYear - 1;
815 } else if (originalYear < 0 && newYear >= 0) {
816 newYear = newYear + 1;
817 }
818 }
819
820 return newYear;
821}
822
823// Utility to correctly return number of years between two year numbers because some systems such as
824// Julian and Gregorian calendars don't have a year 0
825int KCalendarSystemPrivate::differenceYearNumbers(int fromYear, int toYear) const
826{
827 int dy = toYear - fromYear;
828
829 if (!hasYearZero()) {
830 if (toYear > 0 && fromYear < 0) {
831 dy = dy - 1;
832 } else if (toYear < 0 && fromYear > 0) {
833 dy = dy + 1;
834 }
835 }
836
837 return dy;
838}
839
840QDate KCalendarSystemPrivate::invalidDate() const
841{
842 //Is QDate's way of saying is invalid
843 return QDate();
844}
845
846QString KCalendarSystemPrivate::simpleDateString(const QString &str) const
847{
848 QString newStr;
849 for (int i = 0; i < str.length(); i++) {
850 if (str.at(i).isLetterOrNumber()) {
851 newStr.append(str.at(i));
852 } else {
853 newStr.append(QLatin1Char(' '));
854 }
855 }
856
857 return newStr.simplified();
858}
859
860int KCalendarSystemPrivate::dayOfYear(const QDate &date) const
861{
862 int y, m, d, jdFirstDayOfYear;
863 q->julianDayToDate(date.toJulianDay(), y, m, d);
864 q->dateToJulianDay(y, 1, 1, jdFirstDayOfYear);
865 //Take the jd of the given date, and subtract the jd of the first day of that year
866 return (date.toJulianDay() - jdFirstDayOfYear + 1);
867}
868
869int KCalendarSystemPrivate::dayOfWeek(const QDate &date) const
870{
871 // Makes assumption that Julian Day 0 was day 1 of week
872 // This is true for Julian/Gregorian calendar with jd 0 being Monday
873 // We add 1 for ISO compliant numbering for 7 day week
874 // Assumes we've never skipped weekdays
875 return ((date.toJulianDay() % daysInWeek()) + 1);
876}
877
878QDate KCalendarSystemPrivate::firstDayOfYear(int year) const
879{
880 int jd;
881 q->dateToJulianDay(year, 1, 1, jd);
882 return QDate::fromJulianDay(jd);
883}
884
885QDate KCalendarSystemPrivate::lastDayOfYear(int year) const
886{
887 int jd;
888 q->dateToJulianDay(year, 1, 1, jd);
889 jd = jd + daysInYear(year) - 1;
890 return QDate::fromJulianDay(jd);
891}
892
893QDate KCalendarSystemPrivate::firstDayOfMonth(int year, int month) const
894{
895 int jd;
896 q->dateToJulianDay(year, month, 1, jd);
897 return QDate::fromJulianDay(jd);
898}
899
900QDate KCalendarSystemPrivate::lastDayOfMonth(int year, int month) const
901{
902 int jd;
903 q->dateToJulianDay(year, month, 1, jd);
904 jd = jd + daysInMonth(year, month) - 1;
905 return QDate::fromJulianDay(jd);
906}
907
908const KLocale * KCalendarSystemPrivate::locale() const
909{
910 if (m_locale) {
911 return m_locale;
912 } else {
913 return KGlobal::locale();
914 }
915}
916
917QList<KCalendarEra> *KCalendarSystemPrivate::eraList() const
918{
919 return m_eraList;
920}
921
922KCalendarEra KCalendarSystemPrivate::era(const QDate &eraDate) const
923{
924 for (int i = m_eraList->count() - 1; i >= 0; --i) {
925 if (m_eraList->at(i).isInEra(eraDate)) {
926 return m_eraList->at(i);
927 }
928 }
929 return KCalendarEra();
930}
931
932KCalendarEra KCalendarSystemPrivate::era(const QString &eraName, int yearInEra) const
933{
934 Q_UNUSED(yearInEra)
935
936 for (int i = m_eraList->count() - 1; i >= 0; --i) {
937 KCalendarEra era = m_eraList->at(i);
938 if (era.name(KLocale::LongName).toLower() == eraName.toLower() ||
939 era.name(KLocale::ShortName).toLower() == eraName.toLower()) {
940 return era;
941 }
942 }
943 return KCalendarEra();
944}
945
946void KCalendarSystemPrivate::loadEraList(const KConfigGroup & cg)
947{
948 delete m_eraList;
949 m_eraList = new QList<KCalendarEra>;
950 QString eraKey = QString::fromLatin1("Era1");
951 int i = 1;
952 while (cg.hasKey(eraKey)) {
953 QString eraEntry = cg.readEntry(eraKey, QString());
954 if (!eraEntry.isEmpty()) {
955 // Based on LC_TIME, but different!
956 // Includes long and short names, uses ISO fomat dates
957 // e.g. +:1:0001-01-01:9999-12-31:Anno Domini:AD:%EC %Ey
958 QChar direction = eraEntry.section(QLatin1Char(':'), 0, 0).at(0);
959 QDate startDate, endDate;
960 int startYear;
961 QString buffer = eraEntry.section(QLatin1Char(':'), 2, 2);
962 if (buffer.isEmpty()) {
963 if (direction == QLatin1Char('-')) {
964 startDate = q->latestValidDate();
965 } else {
966 startDate = q->earliestValidDate();
967 }
968 } else {
969 startDate = q->readDate(buffer, KLocale::IsoFormat);
970 }
971 if (q->isValid(startDate)) {
972 startYear = q->year(startDate);
973 } else {
974 startYear = eraEntry.section(QLatin1Char(':'), 1, 1).toInt(); //Use offset
975 }
976
977 buffer = eraEntry.section(QLatin1Char(':'), 3, 3);
978 if (buffer.isEmpty()) {
979 if (direction == QLatin1Char('-')) {
980 endDate = q->earliestValidDate();
981 } else {
982 endDate = q->latestValidDate();
983 }
984 } else {
985 endDate = q->readDate(buffer, KLocale::IsoFormat);
986 }
987 addEra(direction.toLatin1(), eraEntry.section(QLatin1Char(':'), 1, 1).toInt(),
988 startDate, startYear, endDate, eraEntry.section(QLatin1Char(':'), 4, 4),
989 eraEntry.section(QLatin1Char(':'), 5, 5), eraEntry.section(QLatin1Char(':'), 6));
990 }
991 ++i;
992 eraKey = QString::fromLatin1("Era%1").arg(i);
993 }
994
995 if (m_eraList->isEmpty()) {
996 loadDefaultEraList();
997 }
998}
999
1000void KCalendarSystemPrivate::addEra(char direction, int offset,
1001 const QDate &startDate, int startYear, const QDate &endDate,
1002 const QString &name, const QString &shortName,
1003 const QString &format)
1004{
1005 KCalendarEra newEra;
1006
1007 newEra.m_sequence = m_eraList->count() + 1;
1008 if (direction == '-') {
1009 newEra.m_direction = -1;
1010 } else {
1011 newEra.m_direction = 1;
1012 }
1013 newEra.m_offset = offset;
1014 newEra.m_startDate = startDate;
1015 newEra.m_startYear = startYear;
1016 newEra.m_endDate = endDate;
1017 newEra.m_longName = name;
1018 newEra.m_shortName = shortName;
1019 newEra.m_format = format;
1020
1021 m_eraList->append(newEra);
1022}
1023
1024int KCalendarSystemPrivate::shortYearWindowStartYear() const
1025{
1026 return m_shortYearWindowStartYear;
1027}
1028
1029int KCalendarSystemPrivate::applyShortYearWindow(int inputYear) const
1030{
1031 if (inputYear >= 0 && inputYear <= 99) {
1032 int shortStartYear = m_shortYearWindowStartYear % 100;
1033 int yearOffset = m_shortYearWindowStartYear - shortStartYear;
1034 if (inputYear >= shortStartYear) {
1035 return inputYear + yearOffset;
1036 } else {
1037 return inputYear + yearOffset + 100;
1038 }
1039 } else {
1040 return inputYear;
1041 }
1042}
1043
1044void KCalendarSystemPrivate::loadShortYearWindowStartYear(const KConfigGroup & cg)
1045{
1046 // Default to 2000 for backwards compatibility
1047 // as that's the old readDate() default value
1048 int startYear = 2000;
1049 if (cg.exists()) {
1050 startYear = cg.readEntry("ShortYearWindowStartYear", 2000);
1051 }
1052 m_shortYearWindowStartYear = startYear;
1053}
1054
1055KSharedConfig::Ptr KCalendarSystemPrivate::config()
1056{
1057 if (m_config == KSharedConfig::Ptr()) {
1058 return KGlobal::config();
1059 } else {
1060 return m_config;
1061 }
1062}
1063
1064void KCalendarSystemPrivate::loadConfig(const QString & calendarType)
1065{
1066 KConfigGroup localeGroup(config(), QString::fromLatin1("Locale"));
1067 KConfigGroup calendarGroup = localeGroup.group(QString::fromLatin1("KCalendarSystem %1").arg(calendarType));
1068 loadEraList(calendarGroup);
1069 loadShortYearWindowStartYear(calendarGroup);
1070}
1071
1072
1073KCalendarSystem::KCalendarSystem(const KLocale *locale)
1074 : d_ptr(new KCalendarSystemPrivate(this))
1075{
1076 d_ptr->m_config = KSharedConfig::Ptr();
1077 d_ptr->m_locale = locale;
1078}
1079
1080KCalendarSystem::KCalendarSystem(const KSharedConfig::Ptr config, const KLocale *locale)
1081 : d_ptr(new KCalendarSystemPrivate(this))
1082{
1083 d_ptr->m_config = config;
1084 d_ptr->m_locale = locale;
1085}
1086
1087KCalendarSystem::KCalendarSystem(KCalendarSystemPrivate &dd, const KSharedConfig::Ptr config, const KLocale *locale)
1088 : d_ptr(&dd)
1089{
1090 d_ptr->m_config = config;
1091 d_ptr->m_locale = locale;
1092}
1093
1094KCalendarSystem::~KCalendarSystem()
1095{
1096 delete d_ptr;
1097}
1098
1099// NOT VIRTUAL - If override needed use shared-d
1100KLocale::CalendarSystem KCalendarSystem::calendarSystem() const
1101{
1102 Q_D(const KCalendarSystem);
1103
1104 return d->calendarSystem();
1105}
1106
1107// NOT VIRTUAL - If override needed use shared-d
1108QString KCalendarSystem::calendarLabel() const
1109{
1110 return KCalendarSystem::calendarLabel(calendarSystem());
1111}
1112
1113// Dummy version using Gregorian as an example
1114// This method MUST be re-implemented in any new Calendar System
1115QDate KCalendarSystem::epoch() const
1116{
1117 return QDate::fromJulianDay(38);
1118}
1119
1120QDate KCalendarSystem::earliestValidDate() const
1121{
1122 return epoch();
1123}
1124
1125// Dummy version using Gregorian as an example
1126// This method MUST be re-implemented in any new Calendar System
1127QDate KCalendarSystem::latestValidDate() const
1128{
1129 // Default to Gregorian 9999-12-31
1130 return QDate::fromJulianDay(5373484);
1131}
1132
1133bool KCalendarSystem::isValid(int year, int month, int day) const
1134{
1135 Q_D(const KCalendarSystem);
1136
1137 if (year < d->earliestValidYear() || year > d->latestValidYear() ||
1138 (!d->hasYearZero() && year == 0)) {
1139 return false;
1140 }
1141
1142 if (month < 1 || month > d->monthsInYear(year)) {
1143 return false;
1144 }
1145
1146 if (day < 1 || day > d->daysInMonth(year, month)) {
1147 return false;
1148 }
1149
1150 return true;
1151}
1152
1153// NOT VIRTUAL - If override needed use shared-d
1154bool KCalendarSystem::isValid(int year, int dayOfYear) const
1155{
1156 Q_D(const KCalendarSystem);
1157
1158 return (isValid(year, 1, 1) && dayOfYear > 0 && dayOfYear <= d->daysInYear(year));
1159}
1160
1161// NOT VIRTUAL - If override needed use shared-d
1162bool KCalendarSystem::isValid(const QString &eraName, int yearInEra, int month, int day) const
1163{
1164 Q_D(const KCalendarSystem);
1165
1166 KCalendarEra era = d->era(eraName, yearInEra);
1167 return (era.isValid() && isValid(era.year(yearInEra), month, day));
1168}
1169
1170// NOT VIRTUAL - If override needed use shared-d
1171bool KCalendarSystem::isValidIsoWeekDate(int year, int isoWeekNumber, int dayOfIsoWeek) const
1172{
1173 Q_D(const KCalendarSystem);
1174
1175 //Tests Year value in standard YMD isValid()
1176 if (!isValid(year, 1, 1)) {
1177 return false;
1178 }
1179
1180 //Test Week Number falls in valid range for this year
1181 int weeksInThisYear = weeksInYear(year);
1182 if (isoWeekNumber < 1 || isoWeekNumber > weeksInThisYear) {
1183 return false;
1184 }
1185
1186 //Test Day of Week Number falls in valid range
1187 if (dayOfIsoWeek < 1 || dayOfIsoWeek > d->daysInWeek()) {
1188 return false;
1189 }
1190
1191 //If not in earliest or latest years then all OK
1192 //Otherwise need to check don't fall into previous or next year that would be invalid
1193 if (year == d->earliestValidYear() && isoWeekNumber == 1) {
1194 //If firstDayOfYear falls on or before Thursday then firstDayOfYear falls in week 1 this
1195 //year and if wanted dayOfIsoWeek falls before firstDayOfYear then falls in previous year
1196 //and so in invalid year
1197 int dowFirstDay = dayOfWeek(d->firstDayOfYear(year));
1198 if (dowFirstDay <= 4 && dayOfIsoWeek < dowFirstDay) {
1199 return false;
1200 }
1201 } else if (year == d->latestValidYear() && isoWeekNumber == weeksInThisYear) {
1202 //If lastDayOfYear falls on or after Thursday then lastDayOfYear falls in last week this
1203 //year and if wanted dayOfIsoWeek falls after lastDayOfYear then falls in next year
1204 //and so in invalid year
1205 int dowLastDay = dayOfWeek(d->lastDayOfYear(year));
1206 if (dowLastDay >= 4 && dayOfIsoWeek > dowLastDay) {
1207 return false;
1208 }
1209 }
1210
1211 return true;
1212}
1213
1214bool KCalendarSystem::isValid(const QDate &date) const
1215{
1216 if (date.isNull() || date < earliestValidDate() || date > latestValidDate()) {
1217 return false;
1218 }
1219 return true;
1220}
1221
1222bool KCalendarSystem::setDate(QDate &date, int year, int month, int day) const
1223{
1224 Q_D(const KCalendarSystem);
1225
1226 date = d->invalidDate();
1227
1228 if (isValid(year, month, day)) {
1229 int jd;
1230 dateToJulianDay(year, month, day, jd);
1231 QDate calcDate = QDate::fromJulianDay(jd);
1232
1233 if (isValid(calcDate)) {
1234 date = calcDate;
1235 return true;
1236 }
1237 }
1238
1239 return false;
1240}
1241
1242// NOT VIRTUAL - If override needed use shared-d
1243bool KCalendarSystem::setDate(QDate &date, int year, int dayOfYear) const
1244{
1245 Q_D(const KCalendarSystem);
1246
1247 date = d->invalidDate();
1248
1249 if (isValid(year, dayOfYear)) {
1250 int jd;
1251 dateToJulianDay(year, 1, 1, jd);
1252 QDate calcDate = QDate::fromJulianDay(jd + dayOfYear - 1);
1253 if (isValid(calcDate)) {
1254 date = calcDate;
1255 return true;
1256 }
1257 }
1258
1259 return false;
1260}
1261
1262// NOT VIRTUAL - If override needed use shared-d
1263bool KCalendarSystem::setDate(QDate &date, QString eraName, int yearInEra, int month, int day) const
1264{
1265 Q_D(const KCalendarSystem);
1266
1267 KCalendarEra era = d->era(eraName, yearInEra);
1268 return (era.isValid() && setDate(date, era.year(yearInEra), month, day));
1269}
1270
1271// NOT VIRTUAL - If override needed use shared-d
1272bool KCalendarSystem::setDateIsoWeek(QDate &date, int year, int isoWeekNumber, int dayOfIsoWeek) const
1273{
1274 Q_D(const KCalendarSystem);
1275
1276 date = d->invalidDate();
1277
1278 if (isValidIsoWeekDate(year, isoWeekNumber, dayOfIsoWeek)) {
1279
1280 QDate calcDate = d->firstDayOfYear(year);
1281 int dowFirstDayOfYear = dayOfWeek(calcDate);
1282
1283 int daysToAdd = (d->daysInWeek() * (isoWeekNumber - 1)) + dayOfIsoWeek;
1284
1285 if (dowFirstDayOfYear <= 4) {
1286 calcDate = calcDate.addDays(daysToAdd - dowFirstDayOfYear);
1287 } else {
1288 calcDate = calcDate.addDays(daysInWeek(calcDate) + daysToAdd - dowFirstDayOfYear);
1289 }
1290
1291 if (isValid(calcDate)) {
1292 date = calcDate;
1293 return true;
1294 }
1295 }
1296
1297 return false;
1298}
1299
1300// Deprecated
1301bool KCalendarSystem::setYMD(QDate &date, int year, int month, int day) const
1302{
1303 return setDate(date, year, month, day);
1304}
1305
1306// NOT VIRTUAL - If override needed use shared-d
1307void KCalendarSystem::getDate(const QDate date, int *year, int *month, int *day) const
1308{
1309 int y, m, d;
1310
1311 if (isValid(date)) {
1312 julianDayToDate(date.toJulianDay(), y, m, d);
1313 } else {
1314 y = 0; // How do you denote invalid year when we support -ve years?
1315 m = 0;
1316 d = 0;
1317 }
1318
1319 if (year) {
1320 *year = y;
1321 }
1322 if (month) {
1323 *month = m;
1324 }
1325 if (day) {
1326 *day = d;
1327 }
1328
1329}
1330
1331int KCalendarSystem::year(const QDate &date) const
1332{
1333 if (isValid(date)) {
1334 int year, month, day;
1335
1336 julianDayToDate(date.toJulianDay(), year, month, day);
1337
1338 return year;
1339 }
1340
1341 return 0; // How do you denote invalid year when we support -ve years?
1342}
1343
1344int KCalendarSystem::month(const QDate &date) const
1345{
1346 if (isValid(date)) {
1347 int year, month, day;
1348
1349 julianDayToDate(date.toJulianDay(), year, month, day);
1350
1351 return month;
1352 }
1353
1354 return 0;
1355}
1356
1357int KCalendarSystem::day(const QDate &date) const
1358{
1359 if (isValid(date)) {
1360 int year, month, day;
1361
1362 julianDayToDate(date.toJulianDay(), year, month, day);
1363
1364 return day;
1365 }
1366
1367 return 0;
1368}
1369
1370// NOT VIRTUAL - If override needed use shared-d
1371QString KCalendarSystem::eraName(const QDate &date, StringFormat format) const
1372{
1373 Q_D(const KCalendarSystem);
1374
1375 if (isValid(date)) {
1376 if (format == LongFormat) {
1377 return d->era(date).name(KLocale::LongName);
1378 } else {
1379 return d->era(date).name(KLocale::ShortName);
1380 }
1381 }
1382
1383 return QString();
1384}
1385
1386// NOT VIRTUAL - If override needed use shared-d
1387QString KCalendarSystem::eraYear(const QDate &date, StringFormat format) const
1388{
1389 Q_UNUSED(format)
1390 Q_D(const KCalendarSystem);
1391
1392 if (isValid(date)) {
1393 return formatDate(date, d->era(date).format());
1394 }
1395
1396 return QString();
1397}
1398
1399// NOT VIRTUAL - If override needed use shared-d
1400int KCalendarSystem::yearInEra(const QDate &date) const
1401{
1402 Q_D(const KCalendarSystem);
1403
1404 if (isValid(date)) {
1405 return d->era(date).yearInEra(year(date));
1406 }
1407
1408 return -1;
1409}
1410
1411// NOT VIRTUAL - If override needed use shared-d
1412QList<KCalendarEra> *KCalendarSystem::eraList() const
1413{
1414 Q_D(const KCalendarSystem);
1415
1416 return d->eraList();
1417}
1418
1419// NOT VIRTUAL - If override needed use shared-d
1420KCalendarEra KCalendarSystem::era(const QDate &eraDate) const
1421{
1422 Q_D(const KCalendarSystem);
1423
1424 return d->era(eraDate);
1425}
1426
1427// NOT VIRTUAL - If override needed use shared-d
1428KCalendarEra KCalendarSystem::era(const QString &eraName, int yearInEra) const
1429{
1430 Q_D(const KCalendarSystem);
1431
1432 return d->era(eraName, yearInEra);
1433}
1434
1435QDate KCalendarSystem::addYears(const QDate &date, int numYears) const
1436{
1437 Q_D(const KCalendarSystem);
1438
1439 if (isValid(date)) {
1440
1441 int originalYear, originalMonth, originalDay;
1442 julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay);
1443
1444 int newYear = d->addYears(originalYear, numYears);
1445 int newMonth = originalMonth;
1446 int newDay = originalDay;
1447
1448 //Adjust day number if new month has fewer days than old month
1449 int daysInNewMonth = d->daysInMonth(newYear, newMonth);
1450 if (daysInNewMonth < originalDay) {
1451 newDay = daysInNewMonth;
1452 }
1453
1454 QDate newDate;
1455 setDate(newDate, newYear, newMonth, newDay);
1456 return newDate;
1457
1458 }
1459
1460 return d->invalidDate();
1461}
1462
1463QDate KCalendarSystem::addMonths(const QDate &date, int numMonths) const
1464{
1465 Q_D(const KCalendarSystem);
1466
1467 if (isValid(date)) {
1468
1469 int originalYear, originalMonth, originalDay;
1470 julianDayToDate(date.toJulianDay(), originalYear, originalMonth, originalDay);
1471
1472 int monthsInOriginalYear = d->monthsInYear(originalYear);
1473
1474 int newYear = d->addYears(originalYear, (originalMonth + numMonths) / monthsInOriginalYear);
1475 int newMonth = (originalMonth + numMonths) % monthsInOriginalYear;
1476 int newDay = originalDay;
1477
1478 if (newMonth == 0) {
1479 newYear = d->addYears(newYear, - 1);
1480 newMonth = monthsInOriginalYear;
1481 }
1482 if (newMonth < 0) {
1483 newYear = d->addYears(newYear, - 1);
1484 newMonth = newMonth + monthsInOriginalYear;
1485 }
1486
1487 //Adjust day number if new month has fewer days than old month
1488 int daysInNewMonth = d->daysInMonth(newYear, newMonth);
1489 if (daysInNewMonth < originalDay) {
1490 newDay = daysInNewMonth;
1491 }
1492
1493 QDate newDate;
1494 setDate(newDate, newYear, newMonth, newDay);
1495 return newDate;
1496
1497 }
1498
1499 return d->invalidDate();
1500}
1501
1502QDate KCalendarSystem::addDays(const QDate &date, int numDays) const
1503{
1504 Q_D(const KCalendarSystem);
1505
1506 // QDate only holds a uint and has no boundary checking in addDays(), so we need to check
1507 if (isValid(date) && (long) date.toJulianDay() + (long) numDays > 0) {
1508 // QDate adds straight to jd
1509 QDate temp = date.addDays(numDays);
1510 if (isValid(temp)) {
1511 return temp;
1512 }
1513 }
1514
1515 return d->invalidDate();
1516}
1517
1518// NOT VIRTUAL - Uses shared-d instead
1519void KCalendarSystem::dateDifference(const QDate &fromDate, const QDate &toDate,
1520 int *yearsDiff, int *monthsDiff, int *daysDiff, int *direction) const
1521{
1522 Q_D(const KCalendarSystem);
1523
1524 if (isValid(fromDate) && isValid(toDate)) {
1525 d->dateDifference(fromDate, toDate, yearsDiff, monthsDiff, daysDiff, direction);
1526 }
1527}
1528
1529// NOT VIRTUAL - Uses shared-d instead
1530int KCalendarSystem::yearsDifference(const QDate &fromDate, const QDate &toDate) const
1531{
1532 Q_D(const KCalendarSystem);
1533
1534 if (isValid(fromDate) && isValid(toDate)) {
1535 return d->yearsDifference(fromDate, toDate);
1536 }
1537
1538 return 0;
1539}
1540
1541// NOT VIRTUAL - Uses shared-d instead
1542int KCalendarSystem::monthsDifference(const QDate &fromDate, const QDate &toDate) const
1543{
1544 Q_D(const KCalendarSystem);
1545
1546 if (isValid(fromDate) && isValid(toDate)) {
1547 return d->monthsDifference(fromDate, toDate);
1548 }
1549
1550 return 0;
1551}
1552
1553// NOT VIRTUAL - Uses shared-d instead
1554int KCalendarSystem::daysDifference(const QDate &fromDate, const QDate &toDate) const
1555{
1556 if (isValid(fromDate) && isValid(toDate)) {
1557 return toDate.toJulianDay() - fromDate.toJulianDay();
1558 }
1559
1560 return 0;
1561}
1562
1563int KCalendarSystem::monthsInYear(const QDate &date) const
1564{
1565 Q_D(const KCalendarSystem);
1566
1567 if (isValid(date)) {
1568 return d->monthsInYear(year(date));
1569 }
1570
1571 return -1;
1572}
1573
1574// NOT VIRTUAL - Uses shared-d instead
1575int KCalendarSystem::monthsInYear(int year) const
1576{
1577 Q_D(const KCalendarSystem);
1578
1579 if (isValid(year, 1, 1)) {
1580 return d->monthsInYear(year);
1581 }
1582
1583 return -1;
1584}
1585
1586int KCalendarSystem::weeksInYear(const QDate &date) const
1587{
1588 return weeksInYear(date, KLocale::DefaultWeekNumber);
1589}
1590
1591int KCalendarSystem::weeksInYear(int year) const
1592{
1593 return weeksInYear(year, KLocale::DefaultWeekNumber);
1594}
1595
1596// NOT VIRTUAL - Uses shared-d instead
1597int KCalendarSystem::weeksInYear(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem) const
1598{
1599 Q_D(const KCalendarSystem);
1600
1601 if (isValid(date)) {
1602 return d->weeksInYear(year(date), weekNumberSystem);
1603 }
1604
1605 return -1;
1606}
1607
1608// NOT VIRTUAL - Uses shared-d instead
1609int KCalendarSystem::weeksInYear(int year, KLocale::WeekNumberSystem weekNumberSystem) const
1610{
1611 Q_D(const KCalendarSystem);
1612
1613 if (isValid(year, 1, 1)) {
1614 return d->weeksInYear(year, weekNumberSystem);
1615 }
1616
1617 return -1;
1618}
1619
1620int KCalendarSystem::daysInYear(const QDate &date) const
1621{
1622 Q_D(const KCalendarSystem);
1623
1624 if (isValid(date)) {
1625 return d->daysInYear(year(date));
1626 }
1627
1628 return -1;
1629}
1630
1631// NOT VIRTUAL - Uses shared-d instead
1632int KCalendarSystem::daysInYear(int year) const
1633{
1634 Q_D(const KCalendarSystem);
1635
1636 if (isValid(year, 1, 1)) {
1637 return d->daysInYear(year);
1638 }
1639
1640 return -1;
1641}
1642
1643int KCalendarSystem::daysInMonth(const QDate &date) const
1644{
1645 Q_D(const KCalendarSystem);
1646
1647 if (isValid(date)) {
1648 int year, month;
1649 getDate(date, &year, &month, 0);
1650 return d->daysInMonth(year, month);
1651 }
1652
1653 return -1;
1654}
1655
1656// NOT VIRTUAL - Uses shared-d instead
1657int KCalendarSystem::daysInMonth(int year, int month) const
1658{
1659 Q_D(const KCalendarSystem);
1660
1661 if (isValid(year, 1, 1)) {
1662 return d->daysInMonth(year, month);
1663 }
1664
1665 return -1;
1666}
1667
1668int KCalendarSystem::daysInWeek(const QDate &date) const
1669{
1670 Q_UNUSED(date)
1671 Q_D(const KCalendarSystem);
1672 return d->daysInWeek();
1673}
1674
1675int KCalendarSystem::dayOfYear(const QDate &date) const
1676{
1677 Q_D(const KCalendarSystem);
1678
1679 if (isValid(date)) {
1680 return d->dayOfYear(date);
1681 }
1682
1683 return -1;
1684}
1685
1686int KCalendarSystem::dayOfWeek(const QDate &date) const
1687{
1688 Q_D(const KCalendarSystem);
1689
1690 if (isValid(date)) {
1691 return d->dayOfWeek(date);
1692 }
1693
1694 return -1;
1695}
1696
1697int KCalendarSystem::weekNumber(const QDate &date, int *yearNum) const
1698{
1699 return week(date, KLocale::IsoWeekNumber, yearNum);
1700}
1701
1702// NOT VIRTUAL - Uses shared-d instead
1703int KCalendarSystem::week(const QDate &date, int *yearNum) const
1704{
1705 return week(date, KLocale::DefaultWeekNumber, yearNum);
1706}
1707
1708// NOT VIRTUAL - Uses shared-d instead
1709int KCalendarSystem::week(const QDate &date, KLocale::WeekNumberSystem weekNumberSystem, int *yearNum) const
1710{
1711 Q_D(const KCalendarSystem);
1712
1713 if (isValid(date)) {
1714 return d->week(date, weekNumberSystem, yearNum);
1715 }
1716
1717 return -1;
1718}
1719
1720bool KCalendarSystem::isLeapYear(int year) const
1721{
1722 Q_D(const KCalendarSystem);
1723
1724 if (isValid(year, 1, 1)) {
1725 return d->isLeapYear(year);
1726 }
1727
1728 return false;
1729}
1730
1731bool KCalendarSystem::isLeapYear(const QDate &date) const
1732{
1733 Q_D(const KCalendarSystem);
1734
1735 if (isValid(date)) {
1736 return d->isLeapYear(year(date));
1737 }
1738
1739 return false;
1740}
1741
1742// NOT VIRTUAL - If override needed use shared-d
1743QDate KCalendarSystem::firstDayOfYear(int year) const
1744{
1745 Q_D(const KCalendarSystem);
1746
1747 if (isValid(year, 1, 1)) {
1748 return d->firstDayOfYear(year);
1749 }
1750
1751 return QDate();
1752}
1753
1754// NOT VIRTUAL - If override needed use shared-d
1755QDate KCalendarSystem::lastDayOfYear(int year) const
1756{
1757 Q_D(const KCalendarSystem);
1758
1759 if (isValid(year, 1, 1)) {
1760 return d->lastDayOfYear(year);
1761 }
1762
1763 return QDate();
1764}
1765
1766// NOT VIRTUAL - If override needed use shared-d
1767QDate KCalendarSystem::firstDayOfYear(const QDate &date) const
1768{
1769 Q_D(const KCalendarSystem);
1770
1771 if (isValid(date)) {
1772 return d->firstDayOfYear(year(date));
1773 }
1774
1775 return QDate();
1776}
1777
1778// NOT VIRTUAL - If override needed use shared-d
1779QDate KCalendarSystem::lastDayOfYear(const QDate &date) const
1780{
1781 Q_D(const KCalendarSystem);
1782
1783 if (isValid(date)) {
1784 return d->lastDayOfYear(year(date));
1785 }
1786
1787 return QDate();
1788}
1789
1790// NOT VIRTUAL - If override needed use shared-d
1791QDate KCalendarSystem::firstDayOfMonth(int year, int month) const
1792{
1793 Q_D(const KCalendarSystem);
1794
1795 if (isValid(year, month, 1)) {
1796 return d->firstDayOfMonth(year, month);
1797 }
1798
1799 return QDate();
1800}
1801
1802// NOT VIRTUAL - If override needed use shared-d
1803QDate KCalendarSystem::lastDayOfMonth(int year, int month) const
1804{
1805 Q_D(const KCalendarSystem);
1806
1807 if (isValid(year, month, 1)) {
1808 return d->lastDayOfMonth(year, month);
1809 }
1810
1811 return QDate();
1812}
1813
1814// NOT VIRTUAL - If override needed use shared-d
1815QDate KCalendarSystem::firstDayOfMonth(const QDate &date) const
1816{
1817 Q_D(const KCalendarSystem);
1818
1819 if (isValid(date)) {
1820 int year, month;
1821 getDate(date, &year, &month, 0);
1822 return d->firstDayOfMonth(year, month);
1823 }
1824
1825 return QDate();
1826}
1827
1828// NOT VIRTUAL - If override needed use shared-d
1829QDate KCalendarSystem::lastDayOfMonth(const QDate &date) const
1830{
1831 Q_D(const KCalendarSystem);
1832
1833 if (isValid(date)) {
1834 int year, month;
1835 getDate(date, &year, &month, 0);
1836 return d->lastDayOfMonth(year, month);
1837 }
1838
1839 return QDate();
1840}
1841
1842QString KCalendarSystem::monthName(int month, int year, KCalendarSystem::MonthNameFormat format) const
1843{
1844 Q_D(const KCalendarSystem);
1845
1846 if (!isValid(year, month, 1)) {
1847 return QString();
1848 }
1849
1850 if (format == KCalendarSystem::NarrowName) {
1851 return d->monthName(month, year, KLocale::NarrowName, false);
1852 }
1853
1854 if (format == KCalendarSystem::ShortNamePossessive) {
1855 return d->monthName(month, year, KLocale::ShortName, true);
1856 }
1857
1858 if (format == KCalendarSystem::ShortName) {
1859 return d->monthName(month, year, KLocale::ShortName, false);
1860 }
1861
1862 if (format == KCalendarSystem::LongNamePossessive) {
1863 return d->monthName(month, year, KLocale::LongName, true);
1864 }
1865
1866 // KCalendarSystem::LongName or any other
1867 return d->monthName(month, year, KLocale::LongName, false);
1868}
1869
1870QString KCalendarSystem::monthName(const QDate &date, MonthNameFormat format) const
1871{
1872 if (isValid(date)) {
1873 int year, month;
1874 getDate(date, &year, &month, 0);
1875 return monthName(month, year, format);
1876 }
1877
1878 return QString();
1879}
1880
1881QString KCalendarSystem::weekDayName(int weekDay, KCalendarSystem::WeekDayNameFormat format) const
1882{
1883 Q_D(const KCalendarSystem);
1884
1885 if (weekDay < 1 || weekDay > d->daysInWeek()) {
1886 return QString();
1887 }
1888
1889 if (format == KCalendarSystem::NarrowDayName) {
1890 return d->weekDayName(weekDay, KLocale::NarrowName);
1891 }
1892
1893 if (format == KCalendarSystem::ShortDayName) {
1894 return d->weekDayName(weekDay, KLocale::ShortName);
1895 }
1896
1897 return d->weekDayName(weekDay, KLocale::LongName);
1898}
1899
1900QString KCalendarSystem::weekDayName(const QDate &date, WeekDayNameFormat format) const
1901{
1902 if (isValid(date)) {
1903 return weekDayName(dayOfWeek(date), format);
1904 }
1905
1906 return QString();
1907}
1908
1909QString KCalendarSystem::yearString(const QDate &date, StringFormat format) const
1910{
1911 if (format == ShortFormat) {
1912 return formatDate(date, KLocale::Year, KLocale::ShortNumber);
1913 } else {
1914 return formatDate(date, KLocale::Year, KLocale::LongNumber);
1915 }
1916}
1917
1918QString KCalendarSystem::monthString(const QDate &date, StringFormat format) const
1919{
1920 if (format == ShortFormat) {
1921 return formatDate(date, KLocale::Month, KLocale::ShortNumber);
1922 } else {
1923 return formatDate(date, KLocale::Month, KLocale::LongNumber);
1924 }
1925}
1926
1927QString KCalendarSystem::dayString(const QDate &date, StringFormat format) const
1928{
1929 if (format == ShortFormat) {
1930 return formatDate(date, KLocale::Day, KLocale::ShortNumber);
1931 } else {
1932 return formatDate(date, KLocale::Day, KLocale::LongNumber);
1933 }
1934}
1935
1936// NOT VIRTUAL - If override needed use shared-d
1937QString KCalendarSystem::yearInEraString(const QDate &date, StringFormat format) const
1938{
1939 if (format == ShortFormat) {
1940 return formatDate(date, KLocale::YearInEra, KLocale::ShortNumber);
1941 } else {
1942 return formatDate(date, KLocale::YearInEra, KLocale::LongNumber);
1943 }
1944}
1945
1946// NOT VIRTUAL - If override needed use shared-d
1947QString KCalendarSystem::dayOfYearString(const QDate &date, StringFormat format) const
1948{
1949 if (format == ShortFormat) {
1950 return formatDate(date, KLocale::DayOfYear, KLocale::ShortNumber);
1951 } else {
1952 return formatDate(date, KLocale::DayOfYear, KLocale::LongNumber);
1953 }
1954}
1955
1956// NOT VIRTUAL - If override needed use shared-d
1957QString KCalendarSystem::dayOfWeekString(const QDate &date) const
1958{
1959 return formatDate(date, KLocale::DayOfWeek, KLocale::ShortNumber);
1960}
1961
1962// NOT VIRTUAL - If override needed use shared-d
1963QString KCalendarSystem::weekNumberString(const QDate &date, StringFormat format) const
1964{
1965 if (format == ShortFormat) {
1966 return formatDate(date, KLocale::Week, KLocale::ShortNumber);
1967 } else {
1968 return formatDate(date, KLocale::Week, KLocale::LongNumber);
1969 }
1970}
1971
1972// NOT VIRTUAL - If override needed use shared-d
1973QString KCalendarSystem::monthsInYearString(const QDate &date, StringFormat format) const
1974{
1975 if (format == ShortFormat) {
1976 return formatDate(date, KLocale::MonthsInYear, KLocale::ShortNumber);
1977 } else {
1978 return formatDate(date, KLocale::MonthsInYear, KLocale::LongNumber);
1979 }
1980}
1981
1982// NOT VIRTUAL - If override needed use shared-d
1983QString KCalendarSystem::weeksInYearString(const QDate &date, StringFormat format) const
1984{
1985 if (format == ShortFormat) {
1986 return formatDate(date, KLocale::WeeksInYear, KLocale::ShortNumber);
1987 } else {
1988 return formatDate(date, KLocale::WeeksInYear, KLocale::LongNumber);
1989 }
1990}
1991
1992// NOT VIRTUAL - If override needed use shared-d
1993QString KCalendarSystem::daysInYearString(const QDate &date, StringFormat format) const
1994{
1995 if (format == ShortFormat) {
1996 return formatDate(date, KLocale::DaysInYear, KLocale::ShortNumber);
1997 } else {
1998 return formatDate(date, KLocale::DaysInYear, KLocale::LongNumber);
1999 }
2000}
2001
2002// NOT VIRTUAL - If override needed use shared-d
2003QString KCalendarSystem::daysInMonthString(const QDate &date, StringFormat format) const
2004{
2005 if (format == ShortFormat) {
2006 return formatDate(date, KLocale::DaysInMonth, KLocale::ShortNumber);
2007 } else {
2008 return formatDate(date, KLocale::DaysInMonth, KLocale::LongNumber);
2009 }
2010}
2011
2012// NOT VIRTUAL - If override needed use shared-d
2013QString KCalendarSystem::daysInWeekString(const QDate &date) const
2014{
2015 return formatDate(date, KLocale::DaysInWeek, KLocale::ShortNumber);
2016}
2017
2018int KCalendarSystem::yearStringToInteger(const QString &yearString, int &readLength) const
2019{
2020 Q_D(const KCalendarSystem);
2021
2022 QString minus = i18nc("Negative symbol as used for year numbers, e.g. -5 = 5 BC", "-");
2023 if (yearString.startsWith(minus)) {
2024 int value = d->integerFromString(yearString.mid(minus.length()), 4, readLength);
2025 if (readLength > 0 && value >= 0) {
2026 readLength = readLength + minus.length();
2027 return value * -1;
2028 } else {
2029 return value;
2030 }
2031 }
2032
2033 return d->integerFromString(yearString, 4, readLength);
2034}
2035
2036int KCalendarSystem::monthStringToInteger(const QString &monthString, int &readLength) const
2037{
2038 Q_D(const KCalendarSystem);
2039 return d->integerFromString(monthString, 2, readLength);
2040}
2041
2042int KCalendarSystem::dayStringToInteger(const QString &dayString, int &readLength) const
2043{
2044 Q_D(const KCalendarSystem);
2045 return d->integerFromString(dayString, 2, readLength);
2046}
2047
2048QString KCalendarSystem::formatDate(const QDate &fromDate, KLocale::DateFormat toFormat) const
2049{
2050 if (!fromDate.isValid()) {
2051 return QString();
2052 }
2053
2054 if (toFormat == KLocale::FancyShortDate || toFormat == KLocale::FancyLongDate) {
2055 QDate now = KDateTime::currentLocalDate();
2056 int daysToNow = fromDate.daysTo(now);
2057 switch (daysToNow) {
2058 case 0:
2059 return i18n("Today");
2060 case 1:
2061 return i18n("Yesterday");
2062 case 2:
2063 case 3:
2064 case 4:
2065 case 5:
2066 case 6:
2067 return weekDayName(fromDate);
2068 default:
2069 break;
2070 }
2071 }
2072
2073 switch (toFormat) {
2074 case KLocale::LongDate:
2075 case KLocale::FancyLongDate:
2076 return formatDate(fromDate, locale()->dateFormat());
2077 case KLocale::IsoDate:
2078 return formatDate(fromDate, QLatin1String("%Y-%m-%d"));
2079 case KLocale::IsoWeekDate:
2080 return formatDate(fromDate, QLatin1String("%Y-W%V-%u"));
2081 case KLocale::IsoOrdinalDate:
2082 return formatDate(fromDate, QLatin1String("%Y-%j"));
2083 case KLocale::ShortDate:
2084 case KLocale::FancyShortDate:
2085 default:
2086 return formatDate(fromDate, locale()->dateFormatShort());
2087 }
2088
2089}
2090
2091// NOT VIRTUAL - If override needed use shared-d
2092QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat,
2093 KLocale::DateTimeFormatStandard standard) const
2094{
2095 return formatDate(fromDate, toFormat, locale()->dateTimeDigitSet(), standard);
2096}
2097
2098// NOT VIRTUAL - If override needed use shared-d
2099QString KCalendarSystem::formatDate(const QDate &fromDate, const QString &toFormat, KLocale::DigitSet digitSet,
2100 KLocale::DateTimeFormatStandard formatStandard) const
2101{
2102 if (!isValid(fromDate) || toFormat.isEmpty()) {
2103 return QString();
2104 }
2105
2106 KDateTimeFormatter formatter;
2107 return formatter.formatDate(fromDate, toFormat, this, locale(), digitSet, formatStandard);
2108}
2109
2110// NOT VIRTUAL - If override needed use shared-d
2111QString KCalendarSystem::formatDate(const QDate &date, KLocale::DateTimeComponent component,
2112 KLocale::DateTimeComponentFormat format,
2113 KLocale::WeekNumberSystem weekNumberSystem) const
2114{
2115 Q_D(const KCalendarSystem);
2116
2117 switch (component) {
2118 case KLocale::Year:
2119 case KLocale::YearName:
2120 switch (format) {
2121 case KLocale::ShortName:
2122 case KLocale::NarrowName:
2123 case KLocale::ShortNumber:
2124 return formatDate(date, QLatin1String("%y"));
2125 case KLocale::LongNumber:
2126 case KLocale::LongName:
2127 case KLocale::DefaultComponentFormat:
2128 default:
2129 return formatDate(date, QLatin1String("%Y"));
2130 }
2131 case KLocale::Month:
2132 switch (format) {
2133 case KLocale::LongName:
2134 return monthName(date, KCalendarSystem::LongName);
2135 case KLocale::ShortName:
2136 return monthName(date, KCalendarSystem::ShortName);
2137 case KLocale::NarrowName:
2138 return monthName(date, KCalendarSystem::NarrowName);
2139 case KLocale::LongNumber:
2140 return formatDate(date, QLatin1String("%m"));
2141 case KLocale::ShortNumber:
2142 case KLocale::DefaultComponentFormat:
2143 default:
2144 return formatDate(date, QLatin1String("%n"));
2145 }
2146 case KLocale::MonthName:
2147 switch (format) {
2148 case KLocale::NarrowName:
2149 return monthName(date, KCalendarSystem::NarrowName);
2150 case KLocale::ShortName:
2151 case KLocale::ShortNumber:
2152 return monthName(date, KCalendarSystem::ShortName);
2153 case KLocale::LongName:
2154 case KLocale::LongNumber:
2155 case KLocale::DefaultComponentFormat:
2156 default:
2157 return monthName(date, KCalendarSystem::LongName);
2158 }
2159 case KLocale::Day:
2160 case KLocale::DayName:
2161 switch (format) {
2162 case KLocale::LongNumber:
2163 case KLocale::LongName:
2164 return formatDate(date, QLatin1String("%d"));
2165 case KLocale::ShortName:
2166 case KLocale::NarrowName:
2167 case KLocale::ShortNumber:
2168 case KLocale::DefaultComponentFormat:
2169 default:
2170 return formatDate(date, QLatin1String("%e"));
2171 }
2172 case KLocale::JulianDay:
2173 return d->stringFromInteger(date.toJulianDay(), 0);
2174 case KLocale::EraName:
2175 switch (format) {
2176 case KLocale::LongNumber:
2177 case KLocale::LongName:
2178 return eraName(date, KCalendarSystem::LongFormat);
2179 case KLocale::ShortName:
2180 case KLocale::NarrowName:
2181 case KLocale::ShortNumber:
2182 case KLocale::DefaultComponentFormat:
2183 default:
2184 return eraName(date, KCalendarSystem::ShortFormat);
2185 }
2186 case KLocale::EraYear:
2187 switch (format) {
2188 case KLocale::LongNumber:
2189 case KLocale::LongName:
2190 return eraYear(date, KCalendarSystem::LongFormat);
2191 case KLocale::ShortName:
2192 case KLocale::NarrowName:
2193 case KLocale::ShortNumber:
2194 case KLocale::DefaultComponentFormat:
2195 default:
2196 return eraYear(date, KCalendarSystem::ShortFormat);
2197 }
2198 case KLocale::YearInEra:
2199 switch (format) {
2200 case KLocale::LongNumber:
2201 case KLocale::LongName:
2202 return formatDate(date, QLatin1String("%4Ey"));
2203 case KLocale::ShortName:
2204 case KLocale::NarrowName:
2205 case KLocale::ShortNumber:
2206 case KLocale::DefaultComponentFormat:
2207 default:
2208 return formatDate(date, QLatin1String("%Ey"));
2209 }
2210 case KLocale::DayOfYear:
2211 case KLocale::DayOfYearName:
2212 switch (format) {
2213 case KLocale::LongNumber:
2214 case KLocale::LongName:
2215 return formatDate(date, QLatin1String("%j"));
2216 case KLocale::ShortName:
2217 case KLocale::NarrowName:
2218 case KLocale::ShortNumber:
2219 case KLocale::DefaultComponentFormat:
2220 default:
2221 return formatDate(date, QLatin1String("%-j"));
2222 }
2223 case KLocale::DayOfWeek:
2224 switch (format) {
2225 case KLocale::LongName:
2226 return weekDayName(date, KCalendarSystem::LongDayName);
2227 case KLocale::ShortName:
2228 return weekDayName(date, KCalendarSystem::ShortDayName);
2229 case KLocale::NarrowName:
2230 return weekDayName(date, KCalendarSystem::NarrowDayName);
2231 case KLocale::LongNumber:
2232 case KLocale::ShortNumber:
2233 case KLocale::DefaultComponentFormat:
2234 default:
2235 return formatDate(date, QLatin1String("%-u"));
2236 }
2237 case KLocale::DayOfWeekName:
2238 switch (format) {
2239 case KLocale::NarrowName:
2240 return weekDayName(date, KCalendarSystem::NarrowDayName);
2241 case KLocale::ShortName:
2242 case KLocale::ShortNumber:
2243 return weekDayName(date, KCalendarSystem::ShortDayName);
2244 case KLocale::LongName:
2245 case KLocale::LongNumber:
2246 case KLocale::DefaultComponentFormat:
2247 default:
2248 return weekDayName(date, KCalendarSystem::LongDayName);
2249 }
2250 case KLocale::Week:
2251 switch (format) {
2252 case KLocale::LongNumber:
2253 case KLocale::LongName:
2254 return d->stringFromInteger(week(date, weekNumberSystem, 0), 2, QLatin1Char('0'));
2255 case KLocale::ShortName:
2256 case KLocale::NarrowName:
2257 case KLocale::ShortNumber:
2258 case KLocale::DefaultComponentFormat:
2259 default:
2260 return d->stringFromInteger(week(date, weekNumberSystem, 0), 0, QLatin1Char('0'));
2261 }
2262 case KLocale::WeekYear: {
2263 int weekYear;
2264 QDate yearDate;
2265 week(date, weekNumberSystem, &weekYear);
2266 setDate(yearDate, weekYear, 1, 1);
2267 return formatDate(yearDate, KLocale::Year, format);
2268 }
2269 case KLocale::MonthsInYear:
2270 switch (format) {
2271 case KLocale::LongNumber:
2272 case KLocale::LongName:
2273 return d->stringFromInteger(monthsInYear(date), 2, QLatin1Char('0'));
2274 case KLocale::ShortName:
2275 case KLocale::NarrowName:
2276 case KLocale::ShortNumber:
2277 case KLocale::DefaultComponentFormat:
2278 default:
2279 return d->stringFromInteger(monthsInYear(date), 0, QLatin1Char('0'));
2280 }
2281 case KLocale::WeeksInYear:
2282 switch (format) {
2283 case KLocale::LongNumber:
2284 case KLocale::LongName:
2285 return d->stringFromInteger(weeksInYear(date), 2, QLatin1Char('0'));
2286 case KLocale::ShortName:
2287 case KLocale::NarrowName:
2288 case KLocale::ShortNumber:
2289 case KLocale::DefaultComponentFormat:
2290 default:
2291 return d->stringFromInteger(weeksInYear(date), 0, QLatin1Char('0'));
2292 }
2293 case KLocale::DaysInYear:
2294 switch (format) {
2295 case KLocale::LongNumber:
2296 case KLocale::LongName:
2297 return d->stringFromInteger(daysInYear(date), 3, QLatin1Char('0'));
2298 case KLocale::ShortName:
2299 case KLocale::NarrowName:
2300 case KLocale::ShortNumber:
2301 case KLocale::DefaultComponentFormat:
2302 default:
2303 return d->stringFromInteger(daysInYear(date), 0, QLatin1Char('0'));
2304 }
2305 case KLocale::DaysInMonth:
2306 switch (format) {
2307 case KLocale::LongNumber:
2308 case KLocale::LongName:
2309 return d->stringFromInteger(daysInMonth(date), 2, QLatin1Char('0'));
2310 case KLocale::ShortName:
2311 case KLocale::NarrowName:
2312 case KLocale::ShortNumber:
2313 case KLocale::DefaultComponentFormat:
2314 default:
2315 return d->stringFromInteger(daysInMonth(date), 0, QLatin1Char('0'));
2316 }
2317 case KLocale::DaysInWeek:
2318 switch (format) {
2319 case KLocale::LongNumber:
2320 case KLocale::LongName:
2321 case KLocale::ShortName:
2322 case KLocale::NarrowName:
2323 case KLocale::ShortNumber:
2324 case KLocale::DefaultComponentFormat:
2325 default:
2326 return d->stringFromInteger(d->daysInWeek(), 0);
2327 }
2328 default:
2329 return QString();
2330 }
2331}
2332
2333QDate KCalendarSystem::readDate(const QString &str, bool *ok) const
2334{
2335 //Try each standard format in turn, start with the locale ones,
2336 //then the well defined standards
2337 QDate date = readDate(str, KLocale::ShortFormat, ok);
2338 if (!isValid(date)) {
2339 date = readDate(str, KLocale::NormalFormat, ok);
2340 if (!isValid(date)) {
2341 date = readDate(str, KLocale::IsoFormat, ok);
2342 if (!isValid(date)) {
2343 date = readDate(str, KLocale::IsoWeekFormat, ok);
2344 if (!isValid(date)) {
2345 date = readDate(str, KLocale::IsoOrdinalFormat, ok);
2346 }
2347 }
2348 }
2349 }
2350
2351 return date;
2352}
2353
2354QDate KCalendarSystem::readDate(const QString &str, KLocale::ReadDateFlags flags, bool *ok) const
2355{
2356 Q_D(const KCalendarSystem);
2357
2358 if (flags & KLocale::ShortFormat) {
2359 return readDate(str, locale()->dateFormatShort(), ok);
2360 } else if (flags & KLocale::NormalFormat) {
2361 return readDate(str, locale()->dateFormat(), ok);
2362 } else if (flags & KLocale::IsoFormat) {
2363 return readDate(str, QLatin1String("%Y-%m-%d"), ok);
2364 } else if (flags & KLocale::IsoWeekFormat) {
2365 return readDate(str, QLatin1String("%Y-W%V-%u"), ok);
2366 } else if (flags & KLocale::IsoOrdinalFormat) {
2367 return readDate(str, QLatin1String("%Y-%j"), ok);
2368 }
2369 return d->invalidDate();
2370}
2371
2372QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok) const
2373{
2374 return readDate(inputString, formatString, ok, KLocale::KdeFormat);
2375}
2376
2377// NOT VIRTUAL - If override needed use shared-d
2378QDate KCalendarSystem::readDate(const QString &inputString, const QString &formatString, bool *ok,
2379 KLocale::DateTimeFormatStandard formatStandard) const
2380{
2381 KDateTimeParser parser;
2382 QDate resultDate = parser.parseDate(inputString, formatString, this, locale(), locale()->dateTimeDigitSet(), formatStandard);
2383 if (ok) {
2384 *ok = resultDate.isValid();
2385 }
2386 return resultDate;
2387}
2388
2389// NOT VIRTUAL - If override needed use shared-d
2390int KCalendarSystem::shortYearWindowStartYear() const
2391{
2392 Q_D(const KCalendarSystem);
2393
2394 return d->shortYearWindowStartYear();
2395}
2396
2397// NOT VIRTUAL - If override needed use shared-d
2398int KCalendarSystem::applyShortYearWindow(int inputYear) const
2399{
2400 Q_D(const KCalendarSystem);
2401
2402 return d->applyShortYearWindow(inputYear);
2403}
2404
2405int KCalendarSystem::weekStartDay() const
2406{
2407 return locale()->weekStartDay();
2408}
2409
2410// Dummy version using Gregorian as an example
2411// This method MUST be re-implemented in any new Calendar System
2412// The implementation MUST NOT do validity checking on date ranges, all calls to this function MUST
2413// instead be wrapped in validity checks, as sometimes we want this to work outside the public valid
2414// range, i.e. to allow us to internally set dates of 1/1/10000 which are not publically valid but
2415// are required for internal maths
2416bool KCalendarSystem::julianDayToDate(int jd, int &year, int &month, int &day) const
2417{
2418 // Formula from The Calendar FAQ by Claus Tondering
2419 // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000
2420 // NOTE: Coded from scratch from mathematical formulas, not copied from
2421 // the Boost licensed source code
2422
2423 int a = jd + 32044;
2424 int b = ((4 * a) + 3) / 146097;
2425 int c = a - ((146097 * b) / 4);
2426 int d = ((4 * c) + 3) / 1461;
2427 int e = c - ((1461 * d) / 4);
2428 int m = ((5 * e) + 2) / 153;
2429 day = e - (((153 * m) + 2) / 5) + 1;
2430 month = m + 3 - (12 * (m / 10));
2431 year = (100 * b) + d - 4800 + (m / 10);
2432
2433 // If year is -ve then is BC. In Gregorian there is no year 0, but the maths
2434 // is easier if we pretend there is, so internally year of 0 = 1BC = -1 outside
2435 if (year < 1) {
2436 year = year - 1;
2437 }
2438
2439 return true;
2440}
2441
2442// Dummy version using Gregorian as an example
2443// This method MUST be re-implemented in any new Calendar System
2444// The implementation MUST NOT do validity checking on date ranges, all calls to this function MUST
2445// instead be wrapped in validity checks, as sometimes we want this to work outside the public valid
2446// range, i.e. to allow us to internally set dates of 1/1/10000 which are not publically valid but
2447// are required for internal maths
2448bool KCalendarSystem::dateToJulianDay(int year, int month, int day, int &jd) const
2449{
2450 // Formula from The Calendar FAQ by Claus Tondering
2451 // http://www.tondering.dk/claus/cal/node3.html#SECTION003161000000000000000
2452 // NOTE: Coded from scratch from mathematical formulas, not copied from
2453 // the Boost licensed source code
2454
2455 // If year is -ve then is BC. In Gregorian there is no year 0, but the maths
2456 // is easier if we pretend there is, so internally year of -1 = 1BC = 0 internally
2457 int y;
2458 if (year < 1) {
2459 y = year + 1;
2460 } else {
2461 y = year;
2462 }
2463
2464 int a = (14 - month) / 12;
2465 y = y + 4800 - a;
2466 int m = month + (12 * a) - 3;
2467
2468 jd = day
2469 + (((153 * m) + 2) / 5)
2470 + (365 * y)
2471 + (y / 4)
2472 - (y / 100)
2473 + (y / 400)
2474 - 32045;
2475
2476 return true;
2477}
2478
2479const KLocale * KCalendarSystem::locale() const
2480{
2481 Q_D(const KCalendarSystem);
2482
2483 return d->locale();
2484}
2485
2486// Deprecated
2487void KCalendarSystem::setMaxMonthsInYear(int maxMonths)
2488{
2489 Q_UNUSED(maxMonths)
2490}
2491
2492// Deprecated
2493void KCalendarSystem::setMaxDaysInWeek(int maxDays)
2494{
2495 Q_UNUSED(maxDays)
2496}
2497
2498// Deprecated
2499void KCalendarSystem::setHasYear0(bool hasYear0)
2500{
2501 Q_UNUSED(hasYear0)
2502}
2503