Jump to content

KDE Core/QtMerge/QDateTime

From KDE Community Wiki

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.

Code Quality

  • important code is inline and no d-> means impossible to change implementation without breaking BC, this should be fixed
  • poor overflow checking in places returns incorrect results instead of an invalid date

Date Range

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 2January 4713BC to about 11 million AD. Changing the uint into an int32 or a int64 will make this date range more useful scientifically:

  • 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

Currently used formulas do not reliably support a date range outside of 8000BC to 8000AD so these should be the limits for now, but can be later extended.

Invalidity (e.g. when adding and you go out-of-bounds) will probably need a bool, or just a very large number considered out-of-range.

Date/Time Format Codes

The Qt to/from string format codes are mostly based on the Unicode CLDR formats but have a number of problems:

  • 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.

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

Reference:

Qt currently supports the following format codes:

d    Day as a number without a leading zero (1 to 31)
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)
hh   Hour with a leading zero (00 to 23 or 01 to 12 if AM/PM)
H    24 Hour without a leading zero (0 to 23)
HH   24 Hour with a leading zero (00 to 23)
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:

  • 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:

ddddd Day narrow localized name (e.g. 'M' to 'S').
MMMMM Month narrow localized name (e.g. 'J' to 'D').
y     Year without a leading zero (1 to 9999)
D (1..3)
Day of Year, numeric with or without leading zeros.
Matches existing dayOfYear() api.
w (1-2)
Week of Year, numeric with or without leading zero.
Matches existing weekNumber() api.
Y (1..n)
Week year, e.g. for ISO Week Number year week falls in, forms to match y.
Matches existing weekNumber() api.
L (1..5)
Stand-alone Month
E (1..5)
Weekday, abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M')
c (1..5)
Stand-alone Weekday
G (1..5)
Era localized name, abbreviated (e.g. 'AD'), long (e.g. 'Anno Domini') and narrow (e.g. 'A')
z/Z/v/V
Timezones.  TODO.  Depends on QTime support.

The following CLDR codes may be implemented but are not considered as important:

Q (1..4)
Quarter in year, '2', '02', 'Q2' or '2nd Quarter'
q (1..4)
Stand-alone Quarter in year
W (1)
Week of Month, numeric.
F (1)
Day of Week In Month, e.g. if today is 2nd Monday in Month = 2
e (1..5)
Weekday, localized numeric (1 or 01), abbreviated (e.g. 'Mon'), long (e.g. 'Monday') and narrow (e.g. 'M').
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.

enum QLocale::NameType {LongName, ShortName, NarrowName}  //Replaces QLocale::FormatType
enum QLocale::NameFormat {SentanceFormat, StandaloneFormat}  //Replaces QDate::MonthNameType
int QDate::quarter()
int QDate::weekOfMonth()
int QDate::weekdayInMonth()
QString QDate::monthName(QLocale::NameType format, QLocale::NameFormat format = QLocale::SentanceFormat)
QString QDate::weekdayName(QLocale::NameType format, QLocale::NameFormat format = QLocale::SentanceFormat)
QString QDate::eraName(QLocale::NameType format, QLocale::NameFormat format = QLocale::SentanceFormat)
QString QDate::quarterName(QLocale::NameType format, QLocale::NameFormat format = QLocale::SentanceFormat)

Note the month and day name api are already marked for change in Qt5.

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

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

void QDate::setCalendarSystem(CalendarSystem)
CalendarSystem QDate::calendarSystem()
void QDate::setLocale(QString)???
QString QDate::locale()???
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()???
int QDate::monthsInYear()
int QDate::weeksInYear()
enum    QDate::NameFormat(NarrowName, ShortName, LongName)
QString QDate::monthName(NameFormat format)
QString QDate::weekdayName(NameFormat format)
int QDate::quarter()
int QDate::weekOfMonth()
int QDate::weekdayInMonth()
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()