KDE Core/QtMerge/QDateTime: Difference between revisions

From KDE Community Wiki
No edit summary
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 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:
The following API design is based on the CLDR standard,and is not Source Compatible with Qt4.  The Qt4 API is inconsistent 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 will simply be using the default toString()/fromString() methods.


* int32 = 5 x 10^6
* 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.
Replace the old enums:


Currently used formulas do not reliably support converting JD's to/from Dates outside of 8000BC to 8000AD, but this can be later extended.
  enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };


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.
  enum QDate:MonthNameType { DateFormat = 0, StandaloneFormat };


isNull() will indicate an uninitialised date or completely invalid date, e.g. where date maths has gone overflowed the JD storage size.
  enum Qt::DateFormat { TextDate,                     // default Qt
                        ISODate,                      // ISO 8601
                        SystemLocaleDate,            // deprecated
                        LocalDate = SystemLocaleDate, // deprecated
                        LocaleDate,                  // deprecated
                        SystemLocaleShortDate,
                        SystemLocaleLongDate,
                        DefaultLocaleShortDate,
                        DefaultLocaleLongDate };


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.
with new enums:


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


The Qt to/from string format codes are mostly based on the Unicode CLDR formats but have a number of problems:
  // CLDR field width attribute
* Only a small sub-set of CLDR codes are supported
  enum QLocale::FieldFormat { LongName,      // e.g. January
* A few Qt format codes are not in the CLDR standard
                              ShortName,    // e.g. Jan
                              NarrowName,    // e.g. J
                              LongNumber,    // e.g. 01
                              ShortNumber }; // e.g. 1


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.  
  // CLDR context attribute
  enum QLocale::FieldContext { FormatContext,       // Use in a format
                              StandaloneContext }; // Use standalone


Many of the missing format codes are just string forms of existing Qt api.
  // CLDR calendar attribute
  enum QLocale::CalendarSystem { DefaultCalendar = -1,  // i.e. locale default
                                GregorianCalendar = 0,
                                ... };


Reference:
  // CLDR year type attribute
* http://www.unicode.org/reports/tr35/tr35-15.html#Date_Format_Patterns
  // Would prefer in QDateTime namespace, but needed for QLocale::monthName()
  enum QLocale::YearType { StandardYear, LeapYear }


Qt currently supports the following format codes:
  enum QDateTime::DateTimeFormat { IsoFormat,
                                  RfcFormat,
                                  Rfc3339Format,
                                  WeekFormat,
                                  OrdinalFormat };


d    Day as a number without a leading zero (1 to 31)
Replace the old name methods:
dd  Day as a number with a leading zero (01 to 31)
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)
   QString QLocale::monthName(int month, FormatType format = LongFormat) const;
hh   Hour with a leading zero (00 to 23 or 01 to 12 if AM/PM)
   QString QLocale::standaloneMonthName(int month, FormatType format = LongFormat) const;
H    24 Hour without a leading zero (0 to 23)
   QString QLocale::dayName(int weekday, FormatType format = LongFormat) const;
HH   24 Hour with a leading zero (00 to 23)
   QString QLocale::standaloneDayName(int weekday, FormatType format = LongFormat) const;
m    Minute without a leading zero (0 to 59)
mm   Minute with a leading zero (00 to 59)
s    Second without a leading zero (0 to 59)
ss   Second with a leading zero (00 to 59)
z    Milliseconds without leading zeroes (0 to 999)
zzz  Milliseconds with leading zeroes (000 to 999)
AP  AM/PM uppercase
ap  AM/PM lowercase
A    AM/PM uppercase
a    AM/PM lowercase
t    Timezone (for example "CEST")


Note that:
  static QString QDate::shortMonthName(int month, MonthNameType type = QDate::DateFormat);
* ddd and dddd formats are not valid CLDR forms but derived from Windows, they should be EEE and EEEE instead.
  static QString QDate::shortDayName(int weekday, MonthNameType type = QDate::DateFormat);
* AP and ap are not valid CLDR forms
  static QString QDate::longMonthName(int month, MonthNameType type = QDate::DateFormat);
* h and hh do not exactly match the CLDR definition
  static QString QDate::longDayName(int weekday, MonthNameType type = QDate::DateFormat);
* t is not a valid CLDR form


The following CLDR codes should be supported:
with new name methods:


ddddd Day narrow localized name (e.g. 'M' to 'S').
  QString QLocale::monthName(int month,
MMMMM Month narrow localized name (e.g. 'J' to 'D').
                            FieldFormat format = LongName,
y    Year without a leading zero (1 to 9999)
                            FieldContext context = FormatContext,
                            YearType yearType = StandardYear,
                            CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::weekdayName(int weekday,
                              FieldFormat format = LongName,
                              FieldContext context = FormatContext,
                              CalendarSystem calendar = DefaultCalendar) const;


D (1..3)
and extend with new feature name methods:
Day of Year, numeric with or without leading zeros.
Matches existing dayOfYear() api.


w (1-2)
  QString QLocale::quarterName(int quarter,
Week of Year, numeric with or without leading zero.
                              FieldFormat format = LongName,
Matches existing weekNumber() api.
                              FieldContext context = FormatContext,
                              CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::eraName(int year,
                          FieldFormat format = LongName,
                          FieldContext context = FormatContext,
                          CalendarSystem calendar = DefaultCalendar) const;
  QString QLocale::calendarName(CalendarSystem calendar = DefaultCalendar,
                                FieldFormat format = LongName,
                                FieldContext context = FormatContext) const;
  QString QLocale::dayPeriodName(QTime time,
                                FieldFormat format = LongName,
                                FieldContext context = FormatContext,
                                CalendarSystem calendar = DefaultCalendar) const;


Y (1..n)
Note the QDate methods are removed as being redundent, see also the QDate::setLocale() method below.
Week year, e.g. for ISO Week Number year week falls in, forms to match y.
Matches existing weekNumber() api.


L (1..5)
Modify the date/time format methods to use the new enums:
Stand-alone Month


E (1..5)
  QString QLocale::dateFormat(StringFormat format = LongFormat);
Weekday, abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M')
  QString QLocale::timeFormat(StringFormat format = LongFormat);
  QString QLocale::dateTimeFormat(StringFormat format = LongFormat);


c (1..5)
Remove all the QLocale toString(), toDate(), toTime(), toDateTime() methods, all formatting/parsing to be done in QDate/QTime/QDateTime
Stand-alone Weekday


G (1..5)
Replace all the QDate toString() and fromString() methods with the following:
Era localized name, abbreviated (e.g. 'AD'), long (e.g. 'Anno Domini') and narrow (e.g. 'A')


z/Z/v/V
  QString QDate::toString(const QString &format) const;
Timezones.  TODO.  Depends on QTime support.
  QString QDate::toString(QLocale::StringFormat format = QLocale::LongFormat) const;
  QString QDate::toString(QDateTime::DateTimeFormat format) const;


The following CLDR codes may be implemented but are not considered as important:
  static QDate QDate::fromString(const QString &string, const QString &format);
  static QDate QDate::fromString(const QString &string, QLocale::StringFormat format = QLocale::LongFormat);
  static QDate QDate::fromString(const QString &string, QDateTime::DateTimeFormat format);


Q (1..4)
Repeat exactly the same for QTime and QDateTime.
Quarter in year, '2', '02', 'Q2' or '2nd Quarter'


q (1..4)
Add the following new methods to support calendar systems:
Stand-alone Quarter in year


W (1)
  CalendarSystem QLocale::calendarSystem()           // locale default calendar
Week of Month, numeric.
  QList<CalendarSystem> QLocale::calendarSystems()    // locale preferred list
  QList<CalendarSystem> QLocale::allCalendarSystems() // all calendars list


F (1)
  void QDate::setCalendarSystem(KLocale::CalendarSystem calendar);
Day of Week In Month, e.g. if today is 2nd Monday in Month = 2
  QLocale::CalendarSystem QDate::calendarSystem();


e (1..5)
  void QDate::setLocale(const QLocale & locale);
Weekday, localized numeric (1 or 01), abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M').
  QLocale QDate::locale();
Would require QLocale support for localized week number, i.e. US week as well as ISO week.


The following new api will be required in QDateTime to support the format codes.
  int QDate::eraYear()
 
   int QDate::monthsInYear()
enum QLocale::NameFormat {LongName, ShortName, NarrowName}  //Replaces QLocale::FormatType
  int QDate::weeksInYear()
enum QLocale::NameContext {SentenceFormat, StandaloneFormat}  //Replaces QDate::MonthNameType
  int QDate::daysInWeek()
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)
QString QDate::eraName(QLocale::NameFormat format)
 
Note the month and day name api are already marked for change in Qt5.
 
An alternative is to merge NameFormat and NameContext, e.g.:
 
enum QLocale::NameFormat {LongName, ShortName, NarrowName, StandaloneLongName, StandaloneShortName, StandaloneNarrowName}
 
Or a further refinement used in KDE:
 
enum QLocale::StringFormat {LongNumber, ShortNumber, LongName, ShortName, NarrowName, StandaloneLongName, StandaloneShortName, StandaloneNarrowName}
 
Dropping the non-CLDR compliant codes should be considered
 
== Date/Time Named Formats ==
 
Goal: To add more date/time named formats
 
Rationale: Convenience for coders
 
Qt currently provides the following named date formats via an enum:
 
    enum DateFormat {
        TextDate,      // default Qt
        ISODate,      // ISO 8601
        SystemLocaleShortDate,
        SystemLocaleLongDate,
        DefaultLocaleShortDate,
        DefaultLocaleLongDate
    };
 
The following named date/time formats would be useful:
 
ISOTime          ISO 8601 format time
                  "hh[:mm[:ss[.sss]]]TZ"
ISODateTime      ISO 8601 format date and time
                  "[±]YYYY-MM-DDThh[:mm[:ss[.sss]]]TZ"
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.
 
Note: KDateTime uses regex's for these in an inefficient way, don't just copy.
 
== Date Eras ==
 
Many locales have an optional Era system for dates, others such as Japan use an era system in its official date formats.
 
== ISO Ordinal Date ==
 
== ISO Week Date ==
 
== Date Maths ==
 
Qt currently only provides standard date math functions for adding years, months or days.  Some more convenience functions could be added.
 
== Date Locale Functions ==
 
Some additional localization options could be added to QLocale to support date formatting:
 
* Week Start Day
* Working Week Start/End Days (or Weekend Start/End)
* Short Year Window
* Digit Sets
* Calendar System
* Week Number System
 
These are also detailed on the QtMerge/QLocale page.
 
== Calendar Systems ==
 
 
 
The following api changes will be required
isNull() - Will now indicate an invalid date in any calendar system, e.g. addition resulting in out-of-bounds
isValid() - Will now indicate if date is valid within current calendar system, but date may still be valid in another calendar system.
 
== Time Zones ==
 
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.
 
TODO: Proposal details.
 
== Durations ==
 
== Widgets ==
 
The various widgets will need modification to match the new features and api.
 
From qt-interest list: QCalendarWidget to use Start of Week from QLocale, but be able to override if needed.
 
== Summary all api proposals ==
 
enum QLocale::NameFormat {LongName, ShortName, NarrowName}  //Replaces QLocale::FormatType
enum QLocale::NameContext {SentanceFormat, StandaloneFormat}  //Replaces QDate::MonthNameType
enum QLocale::CalendarSystem {...}
 
bool QDate::isValidOrdinalDate(int year, int dayOfYear)
bool QDate::setOrdinalDate(int year, int dayOfYear)
 
bool QDate::isValidEraDate(QString eraName, int yearInEra, int month, int day)
bool QDate::setEraDate(QString eraName, int yearInEra, int month, int day)
 
bool QDate::isValidWeekDate(int year, int weekOfYear, int dayOfWeek)
bool QDate::setWeekDate(int year, int weekOfYear, int dayOfWeek)
 
QString QDate::eraName()
int    QDate::yearInEra()
QString QDate::eraName(QLocale::NameFormat format)
 
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()

Revision as of 22:43, 30 July 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,and is not Source Compatible with Qt4. The Qt4 API is inconsistent 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 will simply be using the default toString()/fromString() methods.


Replace the old enums:

 enum QLocale::FormatType { LongFormat, ShortFormat, NarrowFormat };
 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 };

with new 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 = -1,  // i.e. locale default
                                GregorianCalendar = 0,
                                ... };
 // CLDR year type attribute
 // Would prefer in QDateTime namespace, but needed for QLocale::monthName()
 enum QLocale::YearType { StandardYear, LeapYear }
 enum QDateTime::DateTimeFormat { IsoFormat,
                                  RfcFormat,
                                  Rfc3339Format,	
                                  WeekFormat,
                                  OrdinalFormat };

Replace the old 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;
 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);

with new name methods:

 QString QLocale::monthName(int month,
                            FieldFormat format = LongName,
                            FieldContext context = FormatContext,
                            YearType yearType = StandardYear,
                            CalendarSystem calendar = DefaultCalendar) const;
 QString QLocale::weekdayName(int weekday,
                              FieldFormat format = LongName,
                              FieldContext context = FormatContext,
                              CalendarSystem calendar = DefaultCalendar) const;

and extend with new feature name methods:

 QString QLocale::quarterName(int quarter,
                              FieldFormat format = LongName,
                              FieldContext context = FormatContext,
                              CalendarSystem calendar = DefaultCalendar) const;
 QString QLocale::eraName(int year,
                          FieldFormat format = LongName,
                          FieldContext context = FormatContext,
                          CalendarSystem calendar = DefaultCalendar) const;
 QString QLocale::calendarName(CalendarSystem calendar = DefaultCalendar,
                               FieldFormat format = LongName,
                               FieldContext context = FormatContext) const;
 QString QLocale::dayPeriodName(QTime time,
                                FieldFormat format = LongName,
                                FieldContext context = FormatContext,
                                CalendarSystem calendar = DefaultCalendar) const;

Note the QDate methods are removed as being redundent, see also the QDate::setLocale() method below.

Modify the date/time format methods to use the new enums:

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

Remove all the QLocale toString(), toDate(), toTime(), toDateTime() methods, all formatting/parsing to be done in QDate/QTime/QDateTime

Replace all the QDate toString() and fromString() methods with the following:

 QString QDate::toString(const QString &format) const;
 QString QDate::toString(QLocale::StringFormat format = QLocale::LongFormat) const;
 QString QDate::toString(QDateTime::DateTimeFormat format) const;
 static QDate QDate::fromString(const QString &string, const QString &format);
 static QDate QDate::fromString(const QString &string, QLocale::StringFormat format = QLocale::LongFormat);
 static QDate QDate::fromString(const QString &string, QDateTime::DateTimeFormat format);

Repeat exactly the same for QTime and QDateTime.

Add the following new methods to support calendar systems:

 CalendarSystem QLocale::calendarSystem()            // locale default calendar
 QList<CalendarSystem> QLocale::calendarSystems()    // locale preferred list
 QList<CalendarSystem> QLocale::allCalendarSystems() // all calendars list
 void QDate::setCalendarSystem(KLocale::CalendarSystem calendar);
 QLocale::CalendarSystem QDate::calendarSystem();
 void QDate::setLocale(const QLocale & locale);
 QLocale QDate::locale();
 int QDate::eraYear()
 int QDate::monthsInYear()
 int QDate::weeksInYear()
 int QDate::daysInWeek()