On Monday 02 January 2017 09:21:25 Lars Knoll wrote: >>> I wonder whether we can't keep handling of different calendars >>> completely outside of QDate. Something similar to what we've done >>> with QString/QLocale. So QDate would continue unchanged and only >>> support the standard Gregorian calendar. In addition, we have a >>> QCalendar class, that can be constructed with a different calendar >>> system, and can then return 'localized' date strings, days, months >>> and years for this calendar system. >>> >>> Something like: >>> >>> QDate date; >>> QCalendar c(QCalendar::Hebrew); >>> QString hebrewDateString = c.toString(date); >>> int hebrewYear = c.year(date); >>> >>> Maybe one could even integrate this into QLocale, that already provides >>> support for localized month and day names?
The current work actually moves QLocale's calendar-related data *out* to the calendar system classes - a step towards the dismembering of QLocle that was contemplated some years ago, but on which no progress appears to have been made. This separation is one of the particularly satisfying results of Soroush's work. Choice of calendar system is (kinda) orthogonal to choice of locale, anyway, so the calendar data doesn't belong in the QLocale (which only knows about language, script and country, although we *could* teach QLocale(const QString &) to parse more complications out of a string - I doubt that'd be a win). Note, by the way, that the locale data is the *only* data in most calendar system classes, handled as globals (as in QLocale) of the class's compilation unit. Calendar objects themselves are usually entirely algorithmic - they have no data members, just a vtable - although one can conceive of eccentric ones (that we aren't about to implement, but client code might) that could conceivably have member data (e.g. a historian might use a hybrid Julian/Gregorian calendar with one datum, the Julian day number at which to make the transition between the two; the class for that could be instantiated with different transition dates for the various jurisdictions that switched at different dates). On 02/01/17 12:01, "Frédéric Marchal" <frederic.marc...@wowtechnology.com> wrote: >> There is more to it than converting a date to a string: >> >> * Add N days to a date. >> * Find the number of days in a month. >> * Compare two dates. >> * Count the number of days between two dates. >> >> For instance a program wishing a happy new year to its users should >> do it with as little modifications as possible. >> >> Using a plain QDate would have been the easiest way to reach more >> users because it doesn't require to replace lots of QDate with a new, >> very similar, class. As it is not possible to change QDate for now, >> Soroush is looking for a temporary solution that would bridge the gap >> until Qt6 is out. Lars Knoll (2 January 2017 12:39) followed up with: > Sure, that there’s more to do than just the examples I listed. Still, > design wise it might be a good idea to have this functionality in a > class separate from QDate. We’ve done the same design decision for > QString (having no locale specific functionality in QString), and this > worked out rather nicely. So I would encourage you to have a look > whether and how a similar design could be done for calendar system > support. Actually, I do indeed want to move calendaring information - notably that of the Gregorian calendar - out of QDate; even though QDate must surely use Gregorian by default, moving the Gregorian logic (already largely separated into static functions) out makes the QDate class more straightforward. That actually leaves little in QDate itself; and what it does leave can readily be made calendar-system agnostic, although it manipulates a calendar-system object to do the work. So making Gregorian the default in APIs that take a calendar system is in fact a simplification of QDate, where I suppose locale-support complicated QString and its removal simplified. One big reason for wanting to integrate calendar into QDate is that, without it, the overhead of supporting alternate calendars in any app involves re-writing the app, reducing all use of QDate to a mere carrier for its ->toJulianDay(). With QDate taking a calendar object (that defaults Gregorian), it's fairly easy and painless to integrate calendar support into an app. This is rather well illustrated by Soroush's most recent patch-set (11), which extends QCalendarWidget to have QAbstractCalendar member (that, of course, shall default Gregorian), which it duly passes to each QDate method: https://codereview.qt-project.org#/c/182341/11/src/widgets/widgets/qcalendarwidget.cpp,unified This is easy, straightforward and natural; one can readily see that it's correct. (The one wrinkle, QCalendarModel::referenceDate(), being due to the existing comment looking suspiciously bogus, see my comments in Gerrit; search for "Oct 1582" on PS 11.) Now contrast this with what happens if we keep calendar systems out of QDate. There's a basic level of conversion that would go just as straightforwardly - transforming date->method(args) into cal->method(date, args) in most cases - but then there are places where the code needs to add days or jump to the start of the week, month or year, e.g. QCalendarView::moveCursor(). The calendar API can surely have the methods to do that - but, if it does so, the calendar systems would all be doing the same thing as QDate, so we'd end up with concrete methods of QAbstractCalendar (to avoid duplicating *between* systems), each of which duplicates code in a matching QDate method. We could eliminate this duplication by rewriting each QDate method as ret QDate::method(args) { return QGregorianCalendar().method(this, args); } or, indeed, for get-ish things ret QDate::method(args) { return QGregorianCalendar().method(this->toJulianDay(), args); } and, for set-ish things, void QDate::setThing(args) { this->fromJulianDay(QGregorianCalendar()->julianDayFromThing(args)); } possibly with a this->toJulianDay() added to the args, as needed. What bothers me about this is that, at this point, I see no value left in QDate. It would just be a cumbersome way to package a Julian day number - as the last two illustrate - that code using calendar systems other than Gregorian would be obliged to go via in order to interact with the rest of Qt. That's actually worse than no value: it's an obstacle to adding support for other calendars in apps using Qt. QDate is the natural place for the algorithms that would, in this scenario, be carried by QAbstractCalendar's non-abstract methods - they are *date* manipulations, though they need to consult a calendar to work out what to do, not *calendar* manipulations or conversions. Now, as it happens, QDate's relevant methods at present mostly call out to local static functions that would inevitably become methods of QGregorianCalendar (and the exceptions inline relevant code in a QDate method, duplicating what would be in QGregorianCalendar), making it natural to implement them by having a local instance of that calendar class in each method, so as to call its methods. Once we do that, though, the stop to having that instance come in as a parameter (that defaults to a QGregorianCalendar instance) is very low indeed. As a result, integrating calendar support into QDate would actually be more natural than separating it - it would intrude scarcely at all into the implementations (once re-written to use a QGregorianCalendar, to save duplication) while being the natural way to share date-manipulation code that would otherwise have to live in QAbstractCalendar, either as a duplicate of QDate's code or as what QDate code ends up calling to do a job that more naturally belongs to QDate, Eddy. _______________________________________________ Development mailing list Development@qt-project.org http://lists.qt-project.org/mailman/listinfo/development