Jump to content

KDE Core/QtMerge/QDateTime: Difference between revisions

From KDE Community Wiki
Jlayt (talk | contribs)
Jlayt (talk | contribs)
 
(24 intermediate revisions by the same user not shown)
Line 1: Line 1:
The following are proposed additions to Qt's Date/Time support which KDE would like to see to enable dropping of our own Date/Time support, or would help improve Qt's localization under Win/OSX/CLDR.
The initial proposal for merging KDE features in Qt5 as presented at QtCS is documented on the QtCS wiki at http://developer.qt.nokia.com/groups/qt_contributors_summit/wiki/QDateTime


== Code Quality ==
This page documents specific API proposals.


* important code is inline and no d-> means impossible to change implementation without breaking BC, this should be fixed
== Full CLDR Date Format and Calendar System support ==
* poor overflow checking in places returns incorrect results instead of an invalid date


== Date Range ==
The CLDR Date Format support and Calendar System support are closely connected and need to be designed together, although they will be separately implemented.  The following API design is based on the CLDR standard.


The date is stored as a Julian Day Number in a uint with jd == 0 erroneously considered to be invalid. This restricts dates to a range of 2 January 4713BC to about 11 million AD. Changing the uint into an int32 or a int64 will make this date range more useful scientifically:
Backwards source compatibility is required to be maintained by the QDate class using the QT4_COMPAT directive.


* int32 = 5 x 10^6
The Qt4 API is inconsistent, incomplete, and requires modification to fully support CLDR, so the opportunity should be taken to fully overhaul the API.  Most apps will be unaffected as they should simply be using the default toString()/fromString() methods.
* int64 = 25 x 10^15
* Geological time: Age of Earth = 5 x 10^9
* Astronomical time: Age of Universe = 13.75 x 10^9


In theory every value of JD will be considered valid, although one boundary number may be designated the null value rather than using a bool.
=== Object Model ===


Currently used formulas do not reliably support converting JD's to/from Dates outside of 8000BC to 8000AD, but this can be later extended.
The physical object model is still uncertain. The logical model is as follows:


isValid() will indicate if the current JD lies in a valid date range, i.e. one supported by the conversion formulas of the current Calendar System.
QLocale - The locale class, container for type of calendar system, date/time formats, and date/time name translations, and accessor methods to format/parse date/times in that locale. Existing class to be modified.


isNull() will indicate an uninitialised date or completely invalid date, e.g. where date maths has gone overflowed the JD storage size.
QDate - A container class to hold a Julian Day number.  Shouldn't have any ymd or string methods, but to maintain full backwards compatibility will use QT4_COMPAT for all existing ymd and string methods.


Nothing should stop setting Julian Days outside the isValid() date range as this will still be scientifically useful, you just won't be able to convert them to Date form.
QDateCalculator.  A calculator class for converting a QDate to/from YMD values.  No virtuals to be used.


== Date/Time Format Codes ==
QDateTimeParser - Takes an input string, date/time format, and locale and returns a QDateTime.  Existing private class to be modified.


The Qt to/from string format codes are mostly based on the Unicode CLDR formats but have a number of problems:
QDateTimeFormatter - Takes a QDateTime, date/time format and locale and returns a QString.  New private class based on the QLocale formatter.  The QDateTime formatter is to be deleted.
* Only a small sub-set of CLDR codes are supported
* A few Qt format codes are not in the CLDR standard


These format codes also have equivalents in the standard Posix, Windows and OSX date/time formats which are used in localization, so by not supporting them Qt may not be correctly localizing dates to the users system date/time formats.  Many apps also need more flexibility in formatting dates.
The QDateCalculator will be awkward to use directly so we will provide either a QLocalDate class combining all the above in a single convenience wrapper, or a method on QDate to access the calculator such as QDate::calendar(), or both.


Many of the missing format codes are just string forms of existing Qt api.
=== API Changes ===


Reference:
Deprecate the old Qt and QDate enums:
* http://www.unicode.org/reports/tr35/tr35-15.html#Date_Format_Patterns


Qt currently supports the following format codes:
<syntaxhighlight lang="cpp-qt">
  // Merges both format and field type!
  enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };


d    Day as a number without a leading zero (1 to 31)
   // Used for both month and day names!
dd   Day as a number with a leading zero (01 to 31)
   enum QDate::MonthNameType { DateFormat = 0, StandaloneFormat };
ddd  Weekday abbreviated localized name (e.g. 'Mon' to 'Sun').
dddd Weekday long localized name (e.g. 'Monday' to 'Sunday').
M    Month as a number without a leading zero (1 to 12)
MM   Month as a number with a leading zero (01 to 12)
MMM  Month abbreviated localized name (e.g. 'Jan' to 'Dec').
MMMM Month long localized name (e.g. 'January' to 'December').
yy  Year as two digit number (00 to 99)
yyyy Year as four digit number. (-9999 to 9999)


h    Hour without a leading zero (0 to 23 or 1 to 12 if AM/PM)
  enum Qt::DateFormat { TextDate,                    // default Qt
hh  Hour with a leading zero (00 to 23 or 01 to 12 if AM/PM)
                        ISODate,                      // ISO 8601
H    24 Hour without a leading zero (0 to 23)
                        SystemLocaleDate,            // deprecated
HH  24 Hour with a leading zero (00 to 23)
                        LocalDate = SystemLocaleDate, // deprecated
m    Minute without a leading zero (0 to 59)
                        LocaleDate,                  // deprecated
mm  Minute with a leading zero (00 to 59)
                        SystemLocaleShortDate,
s    Second without a leading zero (0 to 59)
                        SystemLocaleLongDate,
ss  Second with a leading zero (00 to 59)
                        DefaultLocaleShortDate,
z    Milliseconds without leading zeroes (0 to 999)
                        DefaultLocaleLongDate };
zzz  Milliseconds with leading zeroes (000 to 999)
</syntaxhighlight>
AP  AM/PM uppercase
ap  AM/PM lowercase
A    AM/PM uppercase
a    AM/PM lowercase
t    Timezone (for example "CEST")


Note that:
Delete or Deprecate the old QLocale enums:
* ddd and dddd formats are not valid CLDR forms but derived from Windows, they should be EEE and EEEE instead.
* AP and ap are not valid CLDR forms
* h and hh do not exactly match the CLDR definition
* t is not a valid CLDR form


The following CLDR codes should be supported:
<syntaxhighlight lang="cpp-qt">
  // Merges both format type and field type!
  enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };
</syntaxhighlight>


ddddd Day narrow localized name (e.g. 'M' to 'S').
Add new QLocale enums:
MMMMM Month narrow localized name (e.g. 'J' to 'D').
y    Year without a leading zero (1 to 9999)


D (1..3)
<syntaxhighlight lang="cpp-qt">
Day of Year, numeric with or without leading zeros.
  // CLDR format length attribute for date/time/number/currency
Matches existing dayOfYear() api.
  enum QLocale::StringFormat { FullFormat,
                              LongFormat,
                              MediumFormat,
                              ShortFormat };


w (1-2)
  // CLDR field width attribute
Week of Year, numeric with or without leading zero.
  enum QLocale::FieldFormat { LongName,      // e.g. January
Matches existing weekNumber() api.
                              ShortName,    // e.g. Jan
                              NarrowName,    // e.g. J
                              LongNumber,   // e.g. 01
                              ShortNumber }; // e.g. 1


Y (1..n)
  // CLDR context attribute
Week year, e.g. for ISO Week Number year week falls in, forms to match y.
  enum QLocale::FieldContext { FormatContext,       // Use in a format
  Matches existing weekNumber() api.
                              StandaloneContext }; // Use standalone


  L (1..5)
  // CLDR calendar attribute
Stand-alone Month
  enum QLocale::CalendarSystem { DefaultCalendar = 0, // i.e. locale default
                                GregorianCalendar = 1,
                                JulianCalendar = 2,
                                ... };


E (1..5)
  // CLDR year type attribute, in Qt or QDateTime namespace instead?
Weekday, abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M')
  enum QLocale::YearType { StandardYear, LeapYear }


c (1..5)
  // CLDR date time fields, maybe in Qt or QLocale namespace?
Stand-alone Weekday
  enum QDateTime::DateTimeField { Year, Month, Day, Hour, Minute, Second, ... }


G (1..5)
  // Common standard formats, maybe in Qt or QLocale namespace?
Era localized name, abbreviated (e.g. 'AD'), long (e.g. 'Anno Domini') and narrow (e.g. 'A')
  enum QDateTime::DateTimeFormat { IsoFormat,
                                  RfcFormat,
                                  Rfc3339Format,
                                  WeekFormat,
                                  OrdinalFormat };
</syntaxhighlight>


z/Z/v/V
Timezones.  TODO.  Depends on QTime support.


The following CLDR codes may be implemented but are not considered as important:
Add new QLocale calendar sytem methods:


Q (1..4)
<syntaxhighlight lang="cpp-qt">
Quarter in year, '2', '02', 'Q2' or '2nd Quarter'
  CalendarSystem QLocale::calendarSystem(); const            // current calendar, usually locale default
  QList<CalendarSystem> QLocale::calendarSystems() const;    // locale preferred list
  QList<CalendarSystem> QLocale::allCalendarSystems() const; // all calendars list
  QDateCalculator QLocale::calendar();                      // current calendar calculator
</syntaxhighlight>


q (1..4)
Deprecate the old QDate name methods:
Stand-alone Quarter in year


W (1)
<syntaxhighlight lang="cpp-qt">
Week of Month, numeric.
  static QString QDate::shortMonthName(int month, MonthNameType type = QDate::DateFormat);
  static QString QDate::shortDayName(int weekday, MonthNameType type = QDate::DateFormat);
  static QString QDate::longMonthName(int month, MonthNameType type = QDate::DateFormat);
  static QString QDate::longDayName(int weekday, MonthNameType type = QDate::DateFormat);
</syntaxhighlight>


F (1)
Delete or Deprecate the old QLocale name methods:
Day of Week In Month, e.g. if today is 2nd Monday in Month = 2


e (1..5)
<syntaxhighlight lang="cpp-qt">
Weekday, localized numeric (1 or 01), abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M').
  QString QLocale::monthName(int month, FormatType format = LongFormat) const;
Would require QLocale support for localized week number, i.e. US week as well as ISO week.
  QString QLocale::standaloneMonthName(int month, FormatType format = LongFormat) const;
  QString QLocale::dayName(int weekday, FormatType format = LongFormat) const;
  QString QLocale::standaloneDayName(int weekday, FormatType format = LongFormat) const;
  QString QLocale::amText() const;
  QString QLocale::pmText() const;
</syntaxhighlight>


The following new api will be required in QDateTime to support the format codes.
Add new QLocale name methods:


enum QLocale::NameFormat {LongName, ShortName, NarrowName}  //Replaces QLocale::FormatType
<syntaxhighlight lang="cpp-qt">
enum QLocale::NameContext {SentenceFormat, StandaloneFormat}  //Replaces QDate::MonthNameType
  QString QLocale::monthName(int month,
int QDate::quarter()
                            FieldFormat format = LongName,
int QDate::weekOfMonth()
                            FieldContext context = StandaloneContext,
int QDate::weekdayInMonth()
                            YearType yearType = StandardYear,
QString QDate::monthName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
                            CalendarSystem calendar = DefaultCalendar) const;
QString QDate::weekdayName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
  QString QLocale::weekdayName(int weekday,
QString QDate::quarterName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
                              FieldFormat format = LongName,
QString QDate::eraName(QLocale::NameFormat format)
                              FieldContext context = StandaloneContext,
                              CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::dayPeriodName(QTime time,
                                FieldFormat format = LongName,
                                FieldContext context = StandaloneContext,
                                CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::eraName(int year,
                          FieldFormat format = LongName,
                          FieldContext context = StandaloneContext,
                          CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::quarterName(int quarter,
                              FieldFormat format = LongName,
                              FieldContext context = StandaloneContext,
                              CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::calendarName(CalendarSystem calendar = DefaultCalendar,
                                FieldFormat format = LongName,
                                FieldContext context = Standaloneontext) const;
</syntaxhighlight>


Note the month and day name api are already marked for change in Qt5.
Modify the QLocale date/time format methods:


An alternative is to merge NameFormat and NameContext, e.g.:
<syntaxhighlight lang="cpp-qt">
    QString QLocale::dateFormat(FormatType format = LongFormat) const;
    QString QLocale::timeFormat(FormatType format = LongFormat) const;
    QString QLocale::dateTimeFormat(FormatType format = LongFormat) const;
</syntaxhighlight>


enum QLocale::NameFormat {LongName, ShortName, NarrowName, StandaloneLongName, StandaloneShortName, StandaloneNarrowName}
to replace FormatType with StringType:


Or a further refinement used in KDE:
<syntaxhighlight lang="cpp-qt">
  QString QLocale::dateFormat(StringFormat format = LongFormat) const;
  QString QLocale::timeFormat(StringFormat format = LongFormat) const;
  QString QLocale::dateTimeFormat(StringFormat format = LongFormat) const;
</syntaxhighlight>


enum QLocale::StringFormat {LongNumber, ShortNumber, LongName, ShortName, NarrowName, StandaloneLongName, StandaloneShortName, StandaloneNarrowName}
Deprecate all the QDateTime toString() and fromString() methods:


Dropping the non-CLDR compliant codes should be considered
<syntaxhighlight lang="cpp-qt">
  QString QDate::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QDate::toString(const QString &format) const;


== Date/Time Named Formats ==
  static QDate QDate::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
  static QDate QDate::fromString(const QString &s, const QString &format);


Goal: To add more date/time named formats
  QString QTime::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QTime::toString(const QString &format) const;


Rationale: Convenience for coders
  static QTime QTime::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
  static QTime QTime::fromString(const QString &s, const QString &format);


Qt currently provides the following named date formats via an enum:
  QString QDateTime::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QDateTime::toString(const QString &format) const;


    enum DateFormat {
  static QDateTime QDateTime::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
        TextDate,     // default Qt
  static QDateTime QDateTime::fromString(const QString &s, const QString &format);
        ISODate,      // ISO 8601
</syntaxhighlight>
        SystemLocaleShortDate,
        SystemLocaleLongDate,
        DefaultLocaleShortDate,
        DefaultLocaleLongDate
    };


The following named date/time formats would be useful:
Mondify the QLocale toString() and fromString() methods:


ISOTime          ISO 8601 format time
<syntaxhighlight lang="cpp-qt">
                  "hh[:mm[:ss[.sss]]]TZ"
  QString QLocale::toString(const QDate &date, FormatType format = LongFormat) const;
ISODateTime      ISO 8601 format date and time
  QString QLocale::toString(const QTime &time, FormatType format = LongFormat) const;
                  "[±]YYYY-MM-DDThh[:mm[:ss[.sss]]]TZ"
  QString QLocale::toString(const QDateTime &dateTime, FormatType format = LongFormat) const;
RFCDateTime      RFC 822/850/1036/1123/2822 format
                  "[Wdy,] DD Mon YYYY hh:mm[:ss] ±hhmm"
                  "Wdy Mon DD HH:MM:SS YYYY"
RFCDateTimeDay  RFC format including day of the week
                  "Wdy, DD Mon YYYY hh:mm:ss ±hhmm"
RFC3339DateTime  RFC 3339 format
                  "YYYY-MM-DDThh:mm:ss[.sss](Z|±hh:mm)"
ISOWeekDate,     ISO 8601 Week Date format
                  "YYYY-Www-D", e.g. 2009-W01-1
ISOOrdinalDate  ISO 8601 Ordinal Date format
                  "YYYY-DDD", e.g. 2009-001


Note the ISO dates should accept both basic and expanded formats.
  QDate QLocale::toDate(const QString &string, FormatType = LongFormat) const;
  QTime QLocale::toTime(const QString &string, FormatType = LongFormat) const;
  QDateTime QLocale::toDateTime(const QString &string, FormatType format = LongFormat) const;
</syntaxhighlight>


Note: KDateTime uses regex's for these in an inefficient way, don't just copy.
to replace FormatType with StringType:


== Date Eras ==
<syntaxhighlight lang="cpp-qt">
  QString QLocale::toString(const QDate &date, StringType format = LongFormat) const;
  QString QLocale::toString(const QTime &time, StringType format = LongFormat) const;
  QString QLocale::toString(const QDateTime &dateTime, StringType format = LongFormat) const;


Many locales have an optional Era system for dates, others such as Japan use an era system in its official date formats.
  QDate QLocale::toDate(const QString &string, StringType = LongFormat) const;
  QTime QLocale::toTime(const QString &string, StringType = LongFormat) const;
  QDateTime QLocale::toDateTime(const QString &string, StringType format = LongFormat) const;
</syntaxhighlight>


== ISO Ordinal Date ==
Add the following new toString/fromSting methods to QLocale


== ISO Week Date ==
<syntaxhighlight lang="cpp-qt">
  QString QLocale::toString(const QDate &date, QDateTime::DateTimeFormat format) const;
  QString QLocale::toString(const QTime &time, QDateTime::DateTimeFormat format) const;
  QString QLocale::toString(const QDateTime &dateTime, QDateTime::DateTimeFormat format) const;


== Date Maths ==
  QString QLocale::toString(const QDate &date, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QString QLocale::toString(const QTime &time, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QString QLocale::toString(const QDateTime &dateTime, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;


Qt currently only provides standard date math functions for adding years, months or days.  Some more convenience functions could be added.
  QDate QLocale::toDate(const QString &string, QDateTime::DateTimeFormat format) const;
  QTime QLocale::toTime(const QString &string, QDateTime::DateTimeFormat format) const;
  QDateTime QLocale::toDateTime(const QString &string, QDateTime::DateTimeFormat format) const;


== Date Locale Functions ==
  QDate QLocale::toDate(const QString &string, QDateTime::DateTimeField field,
                        FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QTime QLocale::toTime(const QString &string, QDateTime::DateTimeField field,
                        FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QDateTime QLocale::toDateTime(const QString &string, QDateTime::DateTimeField field,
                                FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
</syntaxhighlight>


Some additional localization options could be added to QLocale to support date formatting:
Modify the existing string date field format codes to be CLDR compliant as follows:


* Week Start Day
<syntaxhighlight lang="cpp-qt">
* Working Week Start/End Days (or Weekend Start/End)
  ddd - Weekday - Change to EEE
* Short Year Window
  dddd - Weekday - Change to EEEE
* Digit Sets
    AP - AM/PM - Remove, already have A
* Calendar System
    ap - am/pm - Remove, already have a
* Week Number System
    h - Hour - Modify behaviour to match CLDR
    hh - Hour - Modify behaviour to match CLDR
    t - Timezone - Change to z
</syntaxhighlight>


These are also detailed on the QtMerge/QLocale page.
Add new CLDR date field format codes for existing or new api:


== Calendar Systems ==
<syntaxhighlight lang="cpp-qt">
  ddddd - Weekday narrow name
  MMMMM - Month narrow name
      y - Year without leading zeros
      d - Day of Year
      w - Week of Year
      Y - Week Year
      L - Stand-alone Month
      e - Weekday
      E - Weekday
      c - Stand-alone Weekday
      G - Era name
      z - Timezone
      Z - Timezone
      v - Timezone
      V - Timezone
      Q - Quarter of Year
      q - Stand-alone Quarter of Year
      W - Week of Month
      F - Day of Week In Month
</syntaxhighlight>


== QDate API changes ==


The following QDate YMD methods will be deprecated using QT4_COMPAT:


The following api changes will be required
<syntaxhighlight lang="cpp-qt">
isNull() - Will now indicate an invalid date in any calendar system, e.g. addition resulting in out-of-bounds
    QDate(int y, int m, int d);
isValid() - Will now indicate if date is valid within current calendar system, but date may still be valid in another calendar system.


== Time Zones ==
    int year() const;
    int month() const;
    int day() const;
    int dayOfWeek() const;
    int dayOfYear() const;
    int daysInMonth() const;
    int daysInYear() const;
    int weekNumber(int *yearNum = 0) const;


Proper timezone support is required to allow apps like calendaring to use QDateTime.  While full support inside QDateTime would be ideal, it should at least be able to act as the data container.
    bool setDate(int year, int month, int day);
    void getDate(int *year, int *month, int *day);


TODO: Proposal details.
    QDate addDays(int days) const;
    QDate addMonths(int months) const;
    QDate addYears(int years) const;
    int daysTo(const QDate &) const;


== Durations ==
    static bool isValid(int y, int m, int d);
    static bool isLeapYear(int year);
</syntaxhighlight>


== Widgets ==
The following new methods or variations will be added:


The various widgets will need modification to match the new features and api.
<syntaxhighlight lang="cpp-qt">
    static QDate gregorianDate(int year, int month, int day);
    static QDate localDate(int year, int month, int day, QLocale::CalendarSystem calSys = QLocale::DefaultCalendar);
</syntaxhighlight>


From qt-interest list: QCalendarWidget to use Start of Week from QLocale, but be able to override if needed.
=== Implementation Plan ===


== Summary all api proposals ==
The following phased implementation is planned:


  enum QLocale::NameFormat {LongName, ShortName, NarrowName} //Replaces QLocale::FormatType
* Clean-up current code where required. All existing tests should still pass.
enum QLocale::NameContext {SentanceFormat, StandaloneFormat} //Replaces QDate::MonthNameType
* Separate private QDateTimeParser into own file. All existing tests should still pass.
  enum QLocale::CalendarSystem {...}
* Create new private QDateTimeFormatter class, move current formatting code from QLocale into QDateTimeFormatter, change QDateTime to make calls to it. Delete QDateTime formatter code. All existing tests should still pass.
* Create new QDateCalculator class implementing most calendars. Write new unit tests.


bool QDate::isValidOrdinalDate(int year, int dayOfYear)
Still fuzzy:
  bool QDate::setOrdinalDate(int year, int dayOfYear)
* Change QDateTimeFormatter and QDateTimeParser to fix the currently supported field codes to be CLDR compliant. Modify existing tests to ensure they still pass.
 
* Implement new formatting api but making calls to existing backend code, for options that don't yet have the backend coded just translate to a sensible replacement, i.e. for FullDate return LongDate. Only supported CalendarSystem is DefaultCalendar. All existing tests should still pass.
bool QDate::isValidEraDate(QString eraName, int yearInEra, int month, int day)
* Add to QDateTimeFormatter and QDateTimeParser the CLDR field codes that are already supported by existing QDate api. Write new tests.
  bool QDate::setEraDate(QString eraName, int yearInEra, int month, int day)
* Convert unit tests from old api to new api. All existing tests should still pass.
 
* Convert widgets and other Qt code to new api. All existing tests should still pass.
  bool QDate::isValidWeekDate(int year, int weekOfYear, int dayOfWeek)
* Remove old api. All existing tests should still pass.
bool QDate::setWeekDate(int year, int weekOfYear, int dayOfWeek)
* Modify QLocale CLDR backend to return full set of values for new api. Write new tests.
 
* Modify QLocale Mac backend to return full set of values for new api. Write new tests.
  QString QDate::eraName()
* Modify QLocale Windows backend to return full set of values for new api. Write new tests.
  int    QDate::yearInEra()
* Add Era support
QString QDate::eraName(QLocale::NameFormat format)
* Add Week Date support
 
  int QDate::monthsInYear()
  int QDate::weeksInYear()
int QDate::quarter()
  int QDate::weekOfMonth()
int QDate::weekdayInMonth()
 
QString QDate::monthName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
  QString QDate::weekdayName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
QString QDate::quarterName(QLocale::NameFormat format, QLocale::NameContext context = QLocale::SentenceFormat)
 
  void QDate::setCalendarSystem(KLocale::CalendarSystem)
KLocale::CalendarSystem QDate::calendarSystem()
 
void QDate::dateDifference(const QDate &toDate, int *years, int *months, int *days, int *dir)
int  QDate::yearsDifference(const QDate &toDate)
int  QDate::monthsDifference(const QDate &toDate)
int  QDate::daysDifference(const QDate &toDate)
 
QDate QDate::firstDayOfYear()
QDate QDate::lastDayOfYear()
QDate QDate::firstDayOfMonth()
QDate QDate::lastDayOfMonth()

Latest revision as of 17:51, 14 September 2011

The initial proposal for merging KDE features in Qt5 as presented at QtCS is documented on the QtCS wiki at http://developer.qt.nokia.com/groups/qt_contributors_summit/wiki/QDateTime

This page documents specific API proposals.

Full CLDR Date Format and Calendar System support

The CLDR Date Format support and Calendar System support are closely connected and need to be designed together, although they will be separately implemented. The following API design is based on the CLDR standard.

Backwards source compatibility is required to be maintained by the QDate class using the QT4_COMPAT directive.

The Qt4 API is inconsistent, incomplete, and requires modification to fully support CLDR, so the opportunity should be taken to fully overhaul the API. Most apps will be unaffected as they should simply be using the default toString()/fromString() methods.

Object Model

The physical object model is still uncertain. The logical model is as follows:

QLocale - The locale class, container for type of calendar system, date/time formats, and date/time name translations, and accessor methods to format/parse date/times in that locale. Existing class to be modified.

QDate - A container class to hold a Julian Day number. Shouldn't have any ymd or string methods, but to maintain full backwards compatibility will use QT4_COMPAT for all existing ymd and string methods.

QDateCalculator. A calculator class for converting a QDate to/from YMD values. No virtuals to be used.

QDateTimeParser - Takes an input string, date/time format, and locale and returns a QDateTime. Existing private class to be modified.

QDateTimeFormatter - Takes a QDateTime, date/time format and locale and returns a QString. New private class based on the QLocale formatter. The QDateTime formatter is to be deleted.

The QDateCalculator will be awkward to use directly so we will provide either a QLocalDate class combining all the above in a single convenience wrapper, or a method on QDate to access the calculator such as QDate::calendar(), or both.

API Changes

Deprecate the old Qt and QDate enums:

  // Merges both format and field type!
  enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };

  // Used for both month and day names!
  enum QDate::MonthNameType { DateFormat = 0, StandaloneFormat };

  enum Qt::DateFormat { TextDate,                     // default Qt
                        ISODate,                      // ISO 8601
                        SystemLocaleDate,             // deprecated
                        LocalDate = SystemLocaleDate, // deprecated
                        LocaleDate,                   // deprecated
                        SystemLocaleShortDate,
                        SystemLocaleLongDate,
                        DefaultLocaleShortDate,
                        DefaultLocaleLongDate };

Delete or Deprecate the old QLocale enums:

  // Merges both format type and field type!
  enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };

Add new QLocale enums:

  // CLDR format length attribute for date/time/number/currency
  enum QLocale::StringFormat { FullFormat,
                               LongFormat,
                               MediumFormat,
                               ShortFormat };

  // CLDR field width attribute
  enum QLocale::FieldFormat { LongName,      // e.g. January
                              ShortName,     // e.g. Jan
                              NarrowName,    // e.g. J
                              LongNumber,    // e.g. 01
                              ShortNumber }; // e.g. 1

  // CLDR context attribute
  enum QLocale::FieldContext { FormatContext,        // Use in a format
                               StandaloneContext };  // Use standalone

  // CLDR calendar attribute
  enum QLocale::CalendarSystem { DefaultCalendar = 0,  // i.e. locale default
                                 GregorianCalendar = 1,
                                 JulianCalendar = 2,
                                 ... };

  // CLDR year type attribute, in Qt or QDateTime namespace instead?
  enum QLocale::YearType { StandardYear, LeapYear }

  // CLDR date time fields, maybe in Qt or QLocale namespace?
  enum QDateTime::DateTimeField { Year, Month, Day, Hour, Minute, Second, ... }

  // Common standard formats, maybe in Qt or QLocale namespace?
  enum QDateTime::DateTimeFormat { IsoFormat,
                                   RfcFormat,
                                   Rfc3339Format,	
                                   WeekFormat,
                                   OrdinalFormat };


Add new QLocale calendar sytem methods:

  CalendarSystem QLocale::calendarSystem(); const            // current calendar, usually locale default
  QList<CalendarSystem> QLocale::calendarSystems() const;    // locale preferred list
  QList<CalendarSystem> QLocale::allCalendarSystems() const; // all calendars list
  QDateCalculator QLocale::calendar();                       // current calendar calculator

Deprecate the old QDate name methods:

  static QString QDate::shortMonthName(int month, MonthNameType type = QDate::DateFormat);
  static QString QDate::shortDayName(int weekday, MonthNameType type = QDate::DateFormat);
  static QString QDate::longMonthName(int month, MonthNameType type = QDate::DateFormat);
  static QString QDate::longDayName(int weekday, MonthNameType type = QDate::DateFormat);

Delete or Deprecate the old QLocale name methods:

  QString QLocale::monthName(int month, FormatType format = LongFormat) const;
  QString QLocale::standaloneMonthName(int month, FormatType format = LongFormat) const;
  QString QLocale::dayName(int weekday, FormatType format = LongFormat) const;
  QString QLocale::standaloneDayName(int weekday, FormatType format = LongFormat) const;
  QString QLocale::amText() const;
  QString QLocale::pmText() const;

Add new QLocale name methods:

  QString QLocale::monthName(int month,
                             FieldFormat format = LongName,
                             FieldContext context = StandaloneContext,
                             YearType yearType = StandardYear,
                             CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::weekdayName(int weekday,
                               FieldFormat format = LongName,
                               FieldContext context = StandaloneContext,
                               CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::dayPeriodName(QTime time,
                                 FieldFormat format = LongName,
                                 FieldContext context = StandaloneContext,
                                 CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::eraName(int year,
                           FieldFormat format = LongName,
                           FieldContext context = StandaloneContext,
                           CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::quarterName(int quarter,
                               FieldFormat format = LongName,
                               FieldContext context = StandaloneContext,
                               CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::calendarName(CalendarSystem calendar = DefaultCalendar,
                                FieldFormat format = LongName,
                                FieldContext context = Standaloneontext) const;

Modify the QLocale date/time format methods:

    QString QLocale::dateFormat(FormatType format = LongFormat) const;
    QString QLocale::timeFormat(FormatType format = LongFormat) const;
    QString QLocale::dateTimeFormat(FormatType format = LongFormat) const;

to replace FormatType with StringType:

  QString QLocale::dateFormat(StringFormat format = LongFormat) const;
  QString QLocale::timeFormat(StringFormat format = LongFormat) const;
  QString QLocale::dateTimeFormat(StringFormat format = LongFormat) const;

Deprecate all the QDateTime toString() and fromString() methods:

  QString QDate::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QDate::toString(const QString &format) const;

  static QDate QDate::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
  static QDate QDate::fromString(const QString &s, const QString &format);

  QString QTime::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QTime::toString(const QString &format) const;

  static QTime QTime::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
  static QTime QTime::fromString(const QString &s, const QString &format);

  QString QDateTime::toString(Qt::DateFormat f = Qt::TextDate) const;
  QString QDateTime::toString(const QString &format) const;

  static QDateTime QDateTime::fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
  static QDateTime QDateTime::fromString(const QString &s, const QString &format);

Mondify the QLocale toString() and fromString() methods:

  QString QLocale::toString(const QDate &date, FormatType format = LongFormat) const;
  QString QLocale::toString(const QTime &time, FormatType format = LongFormat) const;
  QString QLocale::toString(const QDateTime &dateTime, FormatType format = LongFormat) const;

  QDate QLocale::toDate(const QString &string, FormatType = LongFormat) const;
  QTime QLocale::toTime(const QString &string, FormatType = LongFormat) const;
  QDateTime QLocale::toDateTime(const QString &string, FormatType format = LongFormat) const;

to replace FormatType with StringType:

  QString QLocale::toString(const QDate &date, StringType format = LongFormat) const;
  QString QLocale::toString(const QTime &time, StringType format = LongFormat) const;
  QString QLocale::toString(const QDateTime &dateTime, StringType format = LongFormat) const;

  QDate QLocale::toDate(const QString &string, StringType = LongFormat) const;
  QTime QLocale::toTime(const QString &string, StringType = LongFormat) const;
  QDateTime QLocale::toDateTime(const QString &string, StringType format = LongFormat) const;

Add the following new toString/fromSting methods to QLocale

  QString QLocale::toString(const QDate &date, QDateTime::DateTimeFormat format) const;
  QString QLocale::toString(const QTime &time, QDateTime::DateTimeFormat format) const;
  QString QLocale::toString(const QDateTime &dateTime, QDateTime::DateTimeFormat format) const;

  QString QLocale::toString(const QDate &date, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QString QLocale::toString(const QTime &time, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QString QLocale::toString(const QDateTime &dateTime, QDateTime::DateTimeField field,
                            FieldFormat format = LongName, FieldContext context = StandaloneContext) const;

  QDate QLocale::toDate(const QString &string, QDateTime::DateTimeFormat format) const;
  QTime QLocale::toTime(const QString &string, QDateTime::DateTimeFormat format) const;
  QDateTime QLocale::toDateTime(const QString &string, QDateTime::DateTimeFormat format) const;

  QDate QLocale::toDate(const QString &string, QDateTime::DateTimeField field,
                        FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QTime QLocale::toTime(const QString &string, QDateTime::DateTimeField field,
                        FieldFormat format = LongName, FieldContext context = StandaloneContext) const;
  QDateTime QLocale::toDateTime(const QString &string, QDateTime::DateTimeField field,
                                FieldFormat format = LongName, FieldContext context = StandaloneContext) const;

Modify the existing string date field format codes to be CLDR compliant as follows:

   ddd - Weekday - Change to EEE
  dddd - Weekday - Change to EEEE
    AP - AM/PM - Remove, already have A
    ap - am/pm - Remove, already have a
     h - Hour - Modify behaviour to match CLDR
    hh - Hour - Modify behaviour to match CLDR
     t - Timezone - Change to z

Add new CLDR date field format codes for existing or new api:

  ddddd - Weekday narrow name
  MMMMM - Month narrow name
      y - Year without leading zeros
      d - Day of Year
      w - Week of Year
      Y - Week Year
      L - Stand-alone Month
      e - Weekday
      E - Weekday 
      c - Stand-alone Weekday
      G - Era name
      z - Timezone
      Z - Timezone
      v - Timezone
      V - Timezone
      Q - Quarter of Year
      q - Stand-alone Quarter of Year
      W - Week of Month
      F - Day of Week In Month

QDate API changes

The following QDate YMD methods will be deprecated using QT4_COMPAT:

    QDate(int y, int m, int d);

    int year() const;
    int month() const;
    int day() const;
    int dayOfWeek() const;
    int dayOfYear() const;
    int daysInMonth() const;
    int daysInYear() const;
    int weekNumber(int *yearNum = 0) const;

    bool setDate(int year, int month, int day);
    void getDate(int *year, int *month, int *day);

    QDate addDays(int days) const;
    QDate addMonths(int months) const;
    QDate addYears(int years) const;
    int daysTo(const QDate &) const;

    static bool isValid(int y, int m, int d);
    static bool isLeapYear(int year);

The following new methods or variations will be added:

    static QDate gregorianDate(int year, int month, int day);
    static QDate localDate(int year, int month, int day, QLocale::CalendarSystem calSys = QLocale::DefaultCalendar);

Implementation Plan

The following phased implementation is planned:

  • Clean-up current code where required. All existing tests should still pass.
  • Separate private QDateTimeParser into own file. All existing tests should still pass.
  • Create new private QDateTimeFormatter class, move current formatting code from QLocale into QDateTimeFormatter, change QDateTime to make calls to it. Delete QDateTime formatter code. All existing tests should still pass.
  • Create new QDateCalculator class implementing most calendars. Write new unit tests.

Still fuzzy:

  • Change QDateTimeFormatter and QDateTimeParser to fix the currently supported field codes to be CLDR compliant. Modify existing tests to ensure they still pass.
  • Implement new formatting api but making calls to existing backend code, for options that don't yet have the backend coded just translate to a sensible replacement, i.e. for FullDate return LongDate. Only supported CalendarSystem is DefaultCalendar. All existing tests should still pass.
  • Add to QDateTimeFormatter and QDateTimeParser the CLDR field codes that are already supported by existing QDate api. Write new tests.
  • Convert unit tests from old api to new api. All existing tests should still pass.
  • Convert widgets and other Qt code to new api. All existing tests should still pass.
  • Remove old api. All existing tests should still pass.
  • Modify QLocale CLDR backend to return full set of values for new api. Write new tests.
  • Modify QLocale Mac backend to return full set of values for new api. Write new tests.
  • Modify QLocale Windows backend to return full set of values for new api. Write new tests.
  • Add Era support
  • Add Week Date support