Add support for calendars beside Gregorian

Add QCalendarBackend as a base class for calendar implementations and
QCalendar as a facade via which to access it.

QDate's implicit implementation of the Gregorian calendar becomes
QGregorianCalendar and QDate methods now support choice of calendar.

Convert QLocale's CLDR data for month names to a locale-data component
of each supported calendar and relevant QLocale methods now support
choice of calendar. Adapt Python scripts for locale data generation to
extract month name data from CLDR (keeping on version v35.1) into the
new calendar-locale files. The locale data for the Gregorian calendar
is held in a Roman calendar base, for sharing with other calendars.

Add tests for basic uses of the new API.

[ChangeLog][QtCore][QCalendar] Added QCalendar to support diverse
calendars, supported by implementing QCalendarBackend.

[ChangeLog][QtCore][QDate] Allow choice of calendar in various
operations, with Gregorian remaining the default.

Done-with: Lars Knoll <lars.knoll@qt.io>
Done-with: Edward Welbourne <edward.welbourne@qt.io>
Fixes: QTBUG-17110
Fixes: QTBUG-950
Change-Id: I9d6278f394269a183aee8156e990cec4d5198ab8
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Soroush Rabiei 2017-01-14 20:23:31 +03:30 committed by Edward Welbourne
parent 8f083bade0
commit aa8393c94f
28 changed files with 6422 additions and 3174 deletions

View File

@ -28,6 +28,7 @@ QOBJS = \
qmetatype.o qsystemerror.o qvariant.o \ qmetatype.o qsystemerror.o qvariant.o \
quuid.o \ quuid.o \
qarraydata.o qbitarray.o qbytearray.o qbytearraymatcher.o \ qarraydata.o qbitarray.o qbytearray.o qbytearraymatcher.o \
qcalendar.o qgregoriancalendar.o qromancalendar.o \
qcryptographichash.o qdatetime.o qhash.o qlist.o \ qcryptographichash.o qdatetime.o qhash.o qlist.o \
qlocale.o qlocale_tools.o qmap.o qregexp.o qringbuffer.o \ qlocale.o qlocale_tools.o qmap.o qregexp.o qringbuffer.o \
qstringbuilder.o qstring.o qstringlist.o qversionnumber.o \ qstringbuilder.o qstring.o qstringlist.o qversionnumber.o \
@ -114,7 +115,10 @@ DEPEND_SRC = \
$(SOURCE_PATH)/src/corelib/text/qstring.cpp \ $(SOURCE_PATH)/src/corelib/text/qstring.cpp \
$(SOURCE_PATH)/src/corelib/text/qstringlist.cpp \ $(SOURCE_PATH)/src/corelib/text/qstringlist.cpp \
$(SOURCE_PATH)/src/corelib/text/qvsnprintf.cpp \ $(SOURCE_PATH)/src/corelib/text/qvsnprintf.cpp \
$(SOURCE_PATH)/src/corelib/time/qcalendar.cpp \
$(SOURCE_PATH)/src/corelib/time/qdatetime.cpp \ $(SOURCE_PATH)/src/corelib/time/qdatetime.cpp \
$(SOURCE_PATH)/src/corelib/time/qgregoriancalendar.cpp \
$(SOURCE_PATH)/src/corelib/time/qromancalendar.cpp \
$(SOURCE_PATH)/src/corelib/tools/qarraydata.cpp \ $(SOURCE_PATH)/src/corelib/tools/qarraydata.cpp \
$(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp \ $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp \
$(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp \ $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp \
@ -428,6 +432,15 @@ qfileinfo.o: $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
qdatetime.o: $(SOURCE_PATH)/src/corelib/time/qdatetime.cpp qdatetime.o: $(SOURCE_PATH)/src/corelib/time/qdatetime.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $< $(CXX) -c -o $@ $(CXXFLAGS) $<
qcalendar.o: $(SOURCE_PATH)/src/corelib/time/qcalendar.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qgregoriancalendar.o: $(SOURCE_PATH)/src/corelib/time/qgregoriancalendar.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qromancalendar.o: $(SOURCE_PATH)/src/corelib/time/qromancalendar.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qstringlist.o: $(SOURCE_PATH)/src/corelib/text/qstringlist.cpp qstringlist.o: $(SOURCE_PATH)/src/corelib/text/qstringlist.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $< $(CXX) -c -o $@ $(CXXFLAGS) $<

View File

@ -71,6 +71,7 @@ QTOBJS= \
qbytearray.obj \ qbytearray.obj \
qvsnprintf.obj \ qvsnprintf.obj \
qbytearraymatcher.obj \ qbytearraymatcher.obj \
qcalendar.obj \
qdatetime.obj \ qdatetime.obj \
qdir.obj \ qdir.obj \
qdiriterator.obj \ qdiriterator.obj \
@ -83,6 +84,7 @@ QTOBJS= \
qfileinfo.obj \ qfileinfo.obj \
qendian.obj \ qendian.obj \
qglobal.obj \ qglobal.obj \
qgregoriancalendar.obj \
qhash.obj \ qhash.obj \
qiodevice.obj \ qiodevice.obj \
qringbuffer.obj \ qringbuffer.obj \
@ -97,6 +99,7 @@ QTOBJS= \
qoperatingsystemversion.obj \ qoperatingsystemversion.obj \
qoperatingsystemversion_win.obj \ qoperatingsystemversion_win.obj \
qregexp.obj \ qregexp.obj \
qromancalendar.obj \
qutfcodec.obj \ qutfcodec.obj \
qstring.obj \ qstring.obj \
qstringlist.obj \ qstringlist.obj \

View File

@ -115,6 +115,7 @@ SOURCES += \
qbuffer.cpp \ qbuffer.cpp \
qbytearray.cpp \ qbytearray.cpp \
qbytearraymatcher.cpp \ qbytearraymatcher.cpp \
qcalendar.cpp \
qcryptographichash.cpp \ qcryptographichash.cpp \
qdatetime.cpp \ qdatetime.cpp \
qdir.cpp \ qdir.cpp \
@ -127,6 +128,7 @@ SOURCES += \
qfsfileengine.cpp \ qfsfileengine.cpp \
qfsfileengine_iterator.cpp \ qfsfileengine_iterator.cpp \
qglobal.cpp \ qglobal.cpp \
qgregoriancalendar.cpp \
qhash.cpp \ qhash.cpp \
qiodevice.cpp \ qiodevice.cpp \
qjson.cpp \ qjson.cpp \
@ -145,6 +147,7 @@ SOURCES += \
qmetatype.cpp \ qmetatype.cpp \
qnumeric.cpp \ qnumeric.cpp \
qregexp.cpp \ qregexp.cpp \
qromancalendar.cpp \
qsettings.cpp \ qsettings.cpp \
qstring.cpp \ qstring.cpp \
qstringlist.cpp \ qstringlist.cpp \
@ -168,6 +171,9 @@ HEADERS += \
qbuffer.h \ qbuffer.h \
qbytearray.h \ qbytearray.h \
qbytearraymatcher.h \ qbytearraymatcher.h \
qcalendar.h \
qcalendarbackend_p.h \
qcalendarmath_p.h \
qchar.h \ qchar.h \
qcryptographichash.h \ qcryptographichash.h \
qdatetime.h \ qdatetime.h \
@ -178,6 +184,7 @@ HEADERS += \
qfile.h \ qfile.h \
qfileinfo.h \ qfileinfo.h \
qglobal.h \ qglobal.h \
qgregoriancalendar_p.h \
qhash.h \ qhash.h \
qiodevice.h \ qiodevice.h \
qjson_p.h \ qjson_p.h \
@ -194,6 +201,7 @@ HEADERS += \
qmetatype.h \ qmetatype.h \
qnumeric.h \ qnumeric.h \
qregexp.h \ qregexp.h \
qromancalendar_p.h \
qstring.h \ qstring.h \
qstringlist.h \ qstringlist.h \
qstringmatcher.h \ qstringmatcher.h \

View File

@ -72,6 +72,10 @@
# include <time.h> # include <time.h>
#endif #endif
#include "private/qcalendarbackend_p.h"
#include "private/qgregoriancalendar_p.h"
#include "qcalendar.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#ifndef QT_NO_SYSTEMLOCALE #ifndef QT_NO_SYSTEMLOCALE
@ -341,8 +345,10 @@ QByteArray QLocalePrivate::bcp47Name(char separator) const
return localeId.withLikelySubtagsRemoved().name(separator); return localeId.withLikelySubtagsRemoved().name(separator);
} }
static const QLocaleData *findLocaleDataById(const QLocaleId &localeId) static const QLocaleData *findLocaleDataById(const QLocaleId &lid)
{ {
QLocaleId localeId = lid.withLikelySubtagsAdded();
const uint idx = locale_index[localeId.language_id]; const uint idx = locale_index[localeId.language_id];
const QLocaleData *data = locale_data + idx; const QLocaleData *data = locale_data + idx;
@ -443,6 +449,12 @@ const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLoca
return locale_data + idx; return locale_data + idx;
} }
uint QLocaleData::findLocaleOffset(QLocale::Language language, QLocale::Script script,
QLocale::Country country)
{
return findLocaleData(language, script, country) - locale_data;
}
static bool parse_locale_tag(const QString &input, int &i, QString *result, static bool parse_locale_tag(const QString &input, int &i, QString *result,
const QString &separators) const QString &separators)
{ {
@ -550,6 +562,16 @@ static const QLocaleData *findLocaleData(const QString &name)
return QLocaleData::findLocaleData(lang, script, cntry); return QLocaleData::findLocaleData(lang, script, cntry);
} }
static uint findLocaleOffset(const QString &name)
{
QLocale::Language lang;
QLocale::Script script;
QLocale::Country cntry;
QLocalePrivate::getLangAndCountry(name, lang, script, cntry);
return QLocaleData::findLocaleOffset(lang, script, cntry);
}
QString qt_readEscapedFormatString(QStringView format, int *idx) QString qt_readEscapedFormatString(QStringView format, int *idx)
{ {
int &i = *idx; int &i = *idx;
@ -617,8 +639,8 @@ static QLocale::NumberOptions default_number_options = QLocale::DefaultNumberOpt
static const QLocaleData *const c_data = locale_data; static const QLocaleData *const c_data = locale_data;
static QLocalePrivate *c_private() static QLocalePrivate *c_private()
{ {
static QLocalePrivate c_locale = static QLocalePrivate c_locale{
{ c_data, Q_BASIC_ATOMIC_INITIALIZER(1), QLocale::OmitGroupSeparator }; c_data, Q_BASIC_ATOMIC_INITIALIZER(1), 0, QLocale::OmitGroupSeparator };
return &c_locale; return &c_locale;
} }
@ -803,9 +825,11 @@ static QLocalePrivate *localePrivateByName(const QString &name)
{ {
if (name == QLatin1String("C")) if (name == QLatin1String("C"))
return c_private(); return c_private();
// TODO: Remove this version, and use offset everywhere
const QLocaleData *data = findLocaleData(name); const QLocaleData *data = findLocaleData(name);
return QLocalePrivate::create(data, data->m_language_id == QLocale::C ? return QLocalePrivate::create(data, findLocaleOffset(name),
QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions); data->m_language_id == QLocale::C
? QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions);
} }
static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script, static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script,
@ -814,7 +838,9 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc
if (language == QLocale::C) if (language == QLocale::C)
return c_private(); return c_private();
// TODO: Remove pointer, use index instead
const QLocaleData *data = QLocaleData::findLocaleData(language, script, country); const QLocaleData *data = QLocaleData::findLocaleData(language, script, country);
const uint offset = QLocaleData::findLocaleOffset(language, script, country);
QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions; QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions;
@ -823,7 +849,7 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc
numberOptions = default_number_options; numberOptions = default_number_options;
data = defaultData(); data = defaultData();
} }
return QLocalePrivate::create(data, numberOptions); return QLocalePrivate::create(data, offset, numberOptions);
} }
@ -1957,7 +1983,7 @@ QString QLocale::toString(qulonglong i) const
QString QLocale::toString(const QDate &date, const QString &format) const QString QLocale::toString(const QDate &date, const QString &format) const
{ {
return d->dateTimeToString(format, QDateTime(), date, QTime(), this); return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
} }
#endif #endif
@ -1972,7 +1998,7 @@ QString QLocale::toString(const QDate &date, const QString &format) const
*/ */
QString QLocale::toString(const QDate &date, QStringView format) const QString QLocale::toString(const QDate &date, QStringView format) const
{ {
return d->dateTimeToString(format, QDateTime(), date, QTime(), this); return QCalendar().dateTimeToString(format, QDateTime(), date, QTime(), *this);
} }
/*! /*!
@ -2027,7 +2053,7 @@ static bool timeFormatContainsAP(QStringView format)
*/ */
QString QLocale::toString(const QTime &time, const QString &format) const QString QLocale::toString(const QTime &time, const QString &format) const
{ {
return d->dateTimeToString(format, QDateTime(), QDate(), time, this); return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
} }
#endif #endif
@ -2042,7 +2068,7 @@ QString QLocale::toString(const QTime &time, const QString &format) const
*/ */
QString QLocale::toString(const QTime &time, QStringView format) const QString QLocale::toString(const QTime &time, QStringView format) const
{ {
return d->dateTimeToString(format, QDateTime(), QDate(), time, this); return QCalendar().dateTimeToString(format, QDateTime(), QDate(), time, *this);
} }
#if QT_STRINGVIEW_LEVEL < 2 #if QT_STRINGVIEW_LEVEL < 2
@ -2058,7 +2084,7 @@ QString QLocale::toString(const QTime &time, QStringView format) const
QString QLocale::toString(const QDateTime &dateTime, const QString &format) const QString QLocale::toString(const QDateTime &dateTime, const QString &format) const
{ {
return d->dateTimeToString(format, dateTime, QDate(), QTime(), this); return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
} }
#endif #endif
@ -2073,7 +2099,58 @@ QString QLocale::toString(const QDateTime &dateTime, const QString &format) cons
*/ */
QString QLocale::toString(const QDateTime &dateTime, QStringView format) const QString QLocale::toString(const QDateTime &dateTime, QStringView format) const
{ {
return d->dateTimeToString(format, dateTime, QDate(), QTime(), this); return QCalendar().dateTimeToString(format, dateTime, QDate(), QTime(), *this);
}
QString QLocale::toString(const QDate &date, QStringView format, QCalendar cal) const
{
return cal.dateTimeToString(format, QDateTime(), date, QTime(), *this);
}
QString QLocale::toString(const QDate &date, QLocale::FormatType format, QCalendar cal) const
{
if (!date.isValid())
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (cal.isGregorian() && d->m_data == systemData()) {
QVariant res = systemLocale()->query(format == LongFormat
? QSystemLocale::DateToStringLong
: QSystemLocale::DateToStringShort,
date);
if (!res.isNull())
return res.toString();
}
#endif
QString format_str = dateFormat(format);
return toString(date, format_str, cal);
}
QString QLocale::toString(const QDateTime &dateTime, QLocale::FormatType format,
QCalendar cal) const
{
if (!dateTime.isValid())
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (cal.isGregorian() && d->m_data == systemData()) {
QVariant res = systemLocale()->query(format == LongFormat
? QSystemLocale::DateTimeToStringLong
: QSystemLocale::DateTimeToStringShort,
dateTime);
if (!res.isNull())
return res.toString();
}
#endif
const QString format_str = dateTimeFormat(format);
return toString(dateTime, format_str, cal);
}
QString QLocale::toString(const QDateTime &dateTime, QStringView format, QCalendar cal) const
{
return cal.dateTimeToString(format, dateTime, QDate(), QTime(), *this);
} }
/*! /*!
@ -2232,6 +2309,7 @@ QString QLocale::dateTimeFormat(FormatType format) const
return dateFormat(format) + QLatin1Char(' ') + timeFormat(format); return dateFormat(format) + QLatin1Char(' ') + timeFormat(format);
} }
#if QT_CONFIG(datestring)
/*! /*!
\since 4.4 \since 4.4
@ -2243,12 +2321,19 @@ QString QLocale::dateTimeFormat(FormatType format) const
\sa timeFormat(), toDate(), toDateTime(), QTime::fromString() \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
*/ */
#if QT_CONFIG(datestring)
QTime QLocale::toTime(const QString &string, FormatType format) const QTime QLocale::toTime(const QString &string, FormatType format) const
{ {
return toTime(string, timeFormat(format)); return toTime(string, timeFormat(format));
} }
#endif
/*!
\since 5.14
\overload
*/
QTime QLocale::toTime(const QString &string, FormatType format, QCalendar cal) const
{
return toTime(string, timeFormat(format), cal);
}
/*! /*!
\since 4.4 \since 4.4
@ -2261,12 +2346,19 @@ QTime QLocale::toTime(const QString &string, FormatType format) const
\sa dateFormat(), toTime(), toDateTime(), QDate::fromString() \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
*/ */
#if QT_CONFIG(datestring)
QDate QLocale::toDate(const QString &string, FormatType format) const QDate QLocale::toDate(const QString &string, FormatType format) const
{ {
return toDate(string, dateFormat(format)); return toDate(string, dateFormat(format));
} }
#endif
/*!
\since 5.14
\overload
*/
QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) const
{
return toDate(string, dateFormat(format), cal);
}
/*! /*!
\since 4.4 \since 4.4
@ -2279,13 +2371,19 @@ QDate QLocale::toDate(const QString &string, FormatType format) const
\sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString() \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
*/ */
#if QT_CONFIG(datestring)
QDateTime QLocale::toDateTime(const QString &string, FormatType format) const QDateTime QLocale::toDateTime(const QString &string, FormatType format) const
{ {
return toDateTime(string, dateTimeFormat(format)); return toDateTime(string, dateTimeFormat(format));
} }
#endif
/*!
\since 5.14
\overload
*/
QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal) const
{
return toDateTime(string, dateTimeFormat(format), cal);
}
/*! /*!
\since 4.4 \since 4.4
@ -2298,22 +2396,30 @@ QDateTime QLocale::toDateTime(const QString &string, FormatType format) const
\sa timeFormat(), toDate(), toDateTime(), QTime::fromString() \sa timeFormat(), toDate(), toDateTime(), QTime::fromString()
*/ */
#if QT_CONFIG(datestring)
QTime QLocale::toTime(const QString &string, const QString &format) const QTime QLocale::toTime(const QString &string, const QString &format) const
{
return toTime(string, format, QCalendar());
}
/*!
\since 5.14
\overload
*/
QTime QLocale::toTime(const QString &string, const QString &format, QCalendar cal) const
{ {
QTime time; QTime time;
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(*this); dt.setDefaultLocale(*this);
if (dt.parseFormat(format)) if (dt.parseFormat(format))
dt.fromString(string, 0, &time); dt.fromString(string, 0, &time);
#else #else
Q_UNUSED(cal);
Q_UNUSED(string); Q_UNUSED(string);
Q_UNUSED(format); Q_UNUSED(format);
#endif #endif
return time; return time;
} }
#endif
/*! /*!
\since 4.4 \since 4.4
@ -2329,22 +2435,30 @@ QTime QLocale::toTime(const QString &string, const QString &format) const
\sa dateFormat(), toTime(), toDateTime(), QDate::fromString() \sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
*/ */
#if QT_CONFIG(datestring)
QDate QLocale::toDate(const QString &string, const QString &format) const QDate QLocale::toDate(const QString &string, const QString &format) const
{
return toDate(string, format, QCalendar());
}
/*!
\since 5.14
\overload
*/
QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal) const
{ {
QDate date; QDate date;
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(*this); dt.setDefaultLocale(*this);
if (dt.parseFormat(format)) if (dt.parseFormat(format))
dt.fromString(string, &date, 0); dt.fromString(string, &date, 0);
#else #else
Q_UNUSED(string); Q_UNUSED(string);
Q_UNUSED(format); Q_UNUSED(format);
Q_UNUSED(cal);
#endif #endif
return date; return date;
} }
#endif
/*! /*!
\since 4.4 \since 4.4
@ -2360,25 +2474,33 @@ QDate QLocale::toDate(const QString &string, const QString &format) const
\sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString() \sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
*/ */
#if QT_CONFIG(datestring)
QDateTime QLocale::toDateTime(const QString &string, const QString &format) const QDateTime QLocale::toDateTime(const QString &string, const QString &format) const
{
return toDateTime(string, format, QCalendar());
}
/*!
\since 5.14
\overload
*/
QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal) const
{ {
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QTime time; QTime time;
QDate date; QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(*this); dt.setDefaultLocale(*this);
if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time); return QDateTime(date, time);
#else #else
Q_UNUSED(string); Q_UNUSED(string);
Q_UNUSED(format); Q_UNUSED(format);
Q_UNUSED(cal);
#endif #endif
return QDateTime(QDate(), QTime(-1, -1, -1)); return QDateTime(QDate(), QTime(-1, -1, -1));
} }
#endif #endif // datestring
/*! /*!
\since 4.1 \since 4.1
@ -2623,38 +2745,7 @@ QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
*/ */
QString QLocale::monthName(int month, FormatType type) const QString QLocale::monthName(int month, FormatType type) const
{ {
if (month < 1 || month > 12) return QCalendar().monthName(*this, month, QCalendar::Unspecified, type);
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == systemData()) {
QVariant res = systemLocale()->query(type == LongFormat
? QSystemLocale::MonthNameLong
: QSystemLocale::MonthNameShort,
month);
if (!res.isNull())
return res.toString();
}
#endif
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = d->m_data->m_long_month_names_idx;
size = d->m_data->m_long_month_names_size;
break;
case QLocale::ShortFormat:
idx = d->m_data->m_short_month_names_idx;
size = d->m_data->m_short_month_names_size;
break;
case QLocale::NarrowFormat:
idx = d->m_data->m_narrow_month_names_idx;
size = d->m_data->m_narrow_month_names_size;
break;
default:
return QString();
}
return getLocaleListData(months_data + idx, size, month - 1);
} }
/*! /*!
@ -2670,41 +2761,7 @@ QString QLocale::monthName(int month, FormatType type) const
*/ */
QString QLocale::standaloneMonthName(int month, FormatType type) const QString QLocale::standaloneMonthName(int month, FormatType type) const
{ {
if (month < 1 || month > 12) return QCalendar().standaloneMonthName(*this, month, QCalendar::Unspecified, type);
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == systemData()) {
QVariant res = systemLocale()->query(type == LongFormat
? QSystemLocale::StandaloneMonthNameLong
: QSystemLocale::StandaloneMonthNameShort,
month);
if (!res.isNull())
return res.toString();
}
#endif
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = d->m_data->m_standalone_long_month_names_idx;
size = d->m_data->m_standalone_long_month_names_size;
break;
case QLocale::ShortFormat:
idx = d->m_data->m_standalone_short_month_names_idx;
size = d->m_data->m_standalone_short_month_names_size;
break;
case QLocale::NarrowFormat:
idx = d->m_data->m_standalone_narrow_month_names_idx;
size = d->m_data->m_standalone_narrow_month_names_size;
break;
default:
return QString();
}
QString name = getLocaleListData(months_data + idx, size, month - 1);
if (name.isEmpty())
return monthName(month, type);
return name;
} }
/*! /*!
@ -2718,40 +2775,7 @@ QString QLocale::standaloneMonthName(int month, FormatType type) const
*/ */
QString QLocale::dayName(int day, FormatType type) const QString QLocale::dayName(int day, FormatType type) const
{ {
if (day < 1 || day > 7) return QCalendar().weekDayName(*this, day, type);
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == systemData()) {
QVariant res = systemLocale()->query(type == LongFormat
? QSystemLocale::DayNameLong
: QSystemLocale::DayNameShort,
day);
if (!res.isNull())
return res.toString();
}
#endif
if (day == 7)
day = 0;
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = d->m_data->m_long_day_names_idx;
size = d->m_data->m_long_day_names_size;
break;
case QLocale::ShortFormat:
idx = d->m_data->m_short_day_names_idx;
size = d->m_data->m_short_day_names_size;
break;
case QLocale::NarrowFormat:
idx = d->m_data->m_narrow_day_names_idx;
size = d->m_data->m_narrow_day_names_size;
break;
default:
return QString();
}
return getLocaleListData(days_data + idx, size, day);
} }
/*! /*!
@ -2767,13 +2791,191 @@ QString QLocale::dayName(int day, FormatType type) const
\sa dayName(), standaloneMonthName() \sa dayName(), standaloneMonthName()
*/ */
QString QLocale::standaloneDayName(int day, FormatType type) const QString QLocale::standaloneDayName(int day, FormatType type) const
{
return QCalendar().standaloneWeekDayName(*this, day, type);
}
// Calendar look-up of month and day names:
/*!
\internal
*/
static QString rawMonthName(const QCalendarLocale &localeData,
const ushort *monthsData, int month,
QLocale::FormatType type)
{
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = localeData.m_long.index;
size = localeData.m_long.size;
break;
case QLocale::ShortFormat:
idx = localeData.m_short.index;
size = localeData.m_short.size;
break;
case QLocale::NarrowFormat:
idx = localeData.m_narrow.index;
size = localeData.m_narrow.size;
break;
default:
return QString();
}
return getLocaleListData(monthsData + idx, size, month - 1);
}
/*!
\internal
*/
static QString rawStandaloneMonthName(const QCalendarLocale &localeData,
const ushort *monthsData, int month,
QLocale::FormatType type)
{
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = localeData.m_standalone_long.index;
size = localeData.m_standalone_long.size;
break;
case QLocale::ShortFormat:
idx = localeData.m_standalone_short.index;
size = localeData.m_standalone_short.size;
break;
case QLocale::NarrowFormat:
idx = localeData.m_standalone_narrow.index;
size = localeData.m_standalone_narrow.size;
break;
default:
return QString();
}
QString name = getLocaleListData(monthsData + idx, size, month - 1);
return name.isEmpty() ? rawMonthName(localeData, monthsData, month, type) : name;
}
/*!
\internal
*/
static QString rawWeekDayName(const QLocaleData *data, const int day,
QLocale::FormatType type)
{
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = data->m_long_day_names_idx;
size = data->m_long_day_names_size;
break;
case QLocale::ShortFormat:
idx = data->m_short_day_names_idx;
size = data->m_short_day_names_size;
break;
case QLocale::NarrowFormat:
idx = data->m_narrow_day_names_idx;
size = data->m_narrow_day_names_size;
break;
default:
return QString();
}
return getLocaleListData(days_data + idx, size, day == 7 ? 0 : day);
}
/*!
\internal
*/
static QString rawStandaloneWeekDayName(const QLocaleData *data, const int day,
QLocale::FormatType type)
{
quint32 idx, size;
switch (type) {
case QLocale::LongFormat:
idx = data->m_standalone_long_day_names_idx;
size = data->m_standalone_long_day_names_size;
break;
case QLocale::ShortFormat:
idx = data->m_standalone_short_day_names_idx;
size = data->m_standalone_short_day_names_size;
break;
case QLocale::NarrowFormat:
idx = data->m_standalone_narrow_day_names_idx;
size = data->m_standalone_narrow_day_names_size;
break;
default:
return QString();
}
QString name = getLocaleListData(days_data + idx, size, day == 7 ? 0 : day);
if (name.isEmpty())
return rawWeekDayName(data, day, type);
return name;
}
// Refugees from qcalendar.cpp that need functions above:
QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maxMonthsInYear());
return rawMonthName(localeMonthIndexData()[locale.d->m_data_offset],
localeMonthData(), month, format);
}
QString QGregorianCalendar::monthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const
{
#ifndef QT_NO_SYSTEMLOCALE
if (locale.d->m_data == systemData()) {
Q_ASSERT(month >= 1 && month <= 12);
QVariant res = systemLocale()->query(format == QLocale::LongFormat
? QSystemLocale::MonthNameLong
: QSystemLocale::MonthNameShort,
month);
if (!res.isNull())
return res.toString();
}
#endif
return QCalendarBackend::monthName(locale, month, year, format);
}
QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month, int,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maxMonthsInYear());
return rawStandaloneMonthName(localeMonthIndexData()[locale.d->m_data_offset],
localeMonthData(), month, format);
}
QString QGregorianCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const
{
#ifndef QT_NO_SYSTEMLOCALE
if (locale.d->m_data == systemData()) {
Q_ASSERT(month >= 1 && month <= 12);
QVariant res = systemLocale()->query(format == QLocale::LongFormat
? QSystemLocale::StandaloneMonthNameLong
: QSystemLocale::StandaloneMonthNameShort,
month);
if (!res.isNull())
return res.toString();
}
#endif
return QCalendarBackend::standaloneMonthName(locale, month, year, format);
}
// Most calendars share the common week-day naming, modulo locale.
// Calendars that don't must override these methods.
QString QCalendarBackend::weekDayName(const QLocale &locale, int day,
QLocale::FormatType format) const
{ {
if (day < 1 || day > 7) if (day < 1 || day > 7)
return QString(); return QString();
#ifndef QT_NO_SYSTEMLOCALE #ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == systemData()) { if (locale.d->m_data == systemData()) {
QVariant res = systemLocale()->query(type == LongFormat QVariant res = systemLocale()->query(format == QLocale::LongFormat
? QSystemLocale::DayNameLong ? QSystemLocale::DayNameLong
: QSystemLocale::DayNameShort, : QSystemLocale::DayNameShort,
day); day);
@ -2781,32 +2983,32 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
return res.toString(); return res.toString();
} }
#endif #endif
if (day == 7)
day = 0;
quint32 idx, size; return rawWeekDayName(locale.d->m_data, day, format);
switch (type) {
case QLocale::LongFormat:
idx = d->m_data->m_standalone_long_day_names_idx;
size = d->m_data->m_standalone_long_day_names_size;
break;
case QLocale::ShortFormat:
idx = d->m_data->m_standalone_short_day_names_idx;
size = d->m_data->m_standalone_short_day_names_size;
break;
case QLocale::NarrowFormat:
idx = d->m_data->m_standalone_narrow_day_names_idx;
size = d->m_data->m_standalone_narrow_day_names_size;
break;
default:
return QString();
}
QString name = getLocaleListData(days_data + idx, size, day);
if (name.isEmpty())
return dayName(day == 0 ? 7 : day, type);
return name;
} }
QString QCalendarBackend::standaloneWeekDayName(const QLocale &locale, int day,
QLocale::FormatType format) const
{
if (day < 1 || day > 7)
return QString();
#ifndef QT_NO_SYSTEMLOCALE
if (locale.d->m_data == systemData()) {
QVariant res = systemLocale()->query(format == QLocale::LongFormat
? QSystemLocale::DayNameLong
: QSystemLocale::DayNameShort,
day);
if (!res.isNull())
return res.toString();
}
#endif
return rawStandaloneWeekDayName(locale.d->m_data, day, format);
}
// End of this block of qcalendar.cpp refugees. (One more follows.)
/*! /*!
\since 4.8 \since 4.8
@ -3010,10 +3212,11 @@ QString QLocale::pmText() const
return getLocaleData(pm_data + d->m_data->m_pm_idx, d->m_data->m_pm_size); return getLocaleData(pm_data + d->m_data->m_pm_idx, d->m_data->m_pm_size);
} }
// Another intrusion from QCalendar, using some of the tools above:
QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &datetime, QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly, const QDate &dateOnly, const QTime &timeOnly,
const QLocale *q) const const QLocale &locale) const
{ {
QDate date; QDate date;
QTime time; QTime time;
@ -3035,6 +3238,15 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
} }
QString result; QString result;
int year = 0, month = 0, day = 0;
if (formatDate) {
const auto parts = julianDayToDate(date.toJulianDay());
if (!parts.isValid())
return QString();
year = parts.year;
month = parts.month;
day = parts.day;
}
int i = 0; int i = 0;
while (i < format.size()) { while (i < format.size()) {
@ -3057,14 +3269,13 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
switch (repeat) { switch (repeat) {
case 4: { case 4: {
const int yr = date.year(); const int len = (year < 0) ? 5 : 4;
const int len = (yr < 0) ? 5 : 4; result.append(locale.d->m_data->longLongToString(year, -1, 10, len,
result.append(m_data->longLongToString(yr, -1, 10, len,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
} }
case 2: case 2:
result.append(m_data->longLongToString(date.year() % 100, -1, 10, 2, result.append(locale.d->m_data->longLongToString(year % 100, -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
default: default:
@ -3079,17 +3290,17 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
repeat = qMin(repeat, 4); repeat = qMin(repeat, 4);
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(date.month())); result.append(locale.d->m_data->longLongToString(month));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(date.month(), -1, 10, 2, result.append(locale.d->m_data->longLongToString(month, -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
case 3: case 3:
result.append(q->monthName(date.month(), QLocale::ShortFormat)); result.append(monthName(locale, month, year, QLocale::ShortFormat));
break; break;
case 4: case 4:
result.append(q->monthName(date.month(), QLocale::LongFormat)); result.append(monthName(locale, month, year, QLocale::LongFormat));
break; break;
} }
break; break;
@ -3099,17 +3310,19 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
repeat = qMin(repeat, 4); repeat = qMin(repeat, 4);
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(date.day())); result.append(locale.d->m_data->longLongToString(day));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(date.day(), -1, 10, 2, result.append(locale.d->m_data->longLongToString(day, -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
case 3: case 3:
result.append(q->dayName(date.dayOfWeek(), QLocale::ShortFormat)); result.append(locale.dayName(
dayOfWeek(date.toJulianDay()), QLocale::ShortFormat));
break; break;
case 4: case 4:
result.append(q->dayName(date.dayOfWeek(), QLocale::LongFormat)); result.append(locale.dayName(
dayOfWeek(date.toJulianDay()), QLocale::LongFormat));
break; break;
} }
break; break;
@ -3133,10 +3346,10 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(hour)); result.append(locale.d->m_data->longLongToString(hour));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(hour, -1, 10, 2, result.append(locale.d->m_data->longLongToString(hour, -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
} }
@ -3147,10 +3360,10 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
repeat = qMin(repeat, 2); repeat = qMin(repeat, 2);
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(time.hour())); result.append(locale.d->m_data->longLongToString(time.hour()));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(time.hour(), -1, 10, 2, result.append(locale.d->m_data->longLongToString(time.hour(), -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
} }
@ -3161,10 +3374,10 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
repeat = qMin(repeat, 2); repeat = qMin(repeat, 2);
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(time.minute())); result.append(locale.d->m_data->longLongToString(time.minute()));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(time.minute(), -1, 10, 2, result.append(locale.d->m_data->longLongToString(time.minute(), -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
} }
@ -3175,10 +3388,10 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
repeat = qMin(repeat, 2); repeat = qMin(repeat, 2);
switch (repeat) { switch (repeat) {
case 1: case 1:
result.append(m_data->longLongToString(time.second())); result.append(locale.d->m_data->longLongToString(time.second()));
break; break;
case 2: case 2:
result.append(m_data->longLongToString(time.second(), -1, 10, 2, result.append(locale.d->m_data->longLongToString(time.second(), -1, 10, 2,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
break; break;
} }
@ -3187,13 +3400,15 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
case 'a': case 'a':
used = true; used = true;
repeat = format.mid(i + 1).startsWith(QLatin1Char('p')) ? 2 : 1; repeat = format.mid(i + 1).startsWith(QLatin1Char('p')) ? 2 : 1;
result.append(time.hour() < 12 ? q->amText().toLower() : q->pmText().toLower()); result.append(time.hour() < 12 ? locale.amText().toLower()
: locale.pmText().toLower());
break; break;
case 'A': case 'A':
used = true; used = true;
repeat = format.mid(i + 1).startsWith(QLatin1Char('P')) ? 2 : 1; repeat = format.mid(i + 1).startsWith(QLatin1Char('P')) ? 2 : 1;
result.append(time.hour() < 12 ? q->amText().toUpper() : q->pmText().toUpper()); result.append(time.hour() < 12 ? locale.amText().toUpper()
: locale.pmText().toUpper());
break; break;
case 'z': case 'z':
@ -3202,15 +3417,14 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
// note: the millisecond component is treated like the decimal part of the seconds // note: the millisecond component is treated like the decimal part of the seconds
// so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200" // so ms == 2 is always printed as "002", but ms == 200 can be either "2" or "200"
result.append(m_data->longLongToString(time.msec(), -1, 10, 3, result.append(locale.d->m_data->longLongToString(time.msec(), -1, 10, 3,
QLocaleData::ZeroPadded)); QLocaleData::ZeroPadded));
if (repeat == 1) { if (repeat == 1) {
if (result.endsWith(zero())) if (result.endsWith(locale.d->zero()))
result.chop(1); result.chop(1);
if (result.endsWith(zero())) if (result.endsWith(locale.d->zero()))
result.chop(1); result.chop(1);
} }
break; break;
case 't': case 't':
@ -3233,6 +3447,8 @@ QString QLocalePrivate::dateTimeToString(QStringView format, const QDateTime &da
return result; return result;
} }
// End of QCalendar intrustions
QString QLocaleData::doubleToString(double d, int precision, DoubleForm form, QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
int width, unsigned flags) const int width, unsigned flags) const
{ {

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QCalendar;
class QDataStream; class QDataStream;
class QDate; class QDate;
class QDateTime; class QDateTime;
@ -1013,6 +1013,14 @@ public:
QString toString(const QDate &date, FormatType format = LongFormat) const; QString toString(const QDate &date, FormatType format = LongFormat) const;
QString toString(const QTime &time, FormatType format = LongFormat) const; QString toString(const QTime &time, FormatType format = LongFormat) const;
QString toString(const QDateTime &dateTime, FormatType format = LongFormat) const; QString toString(const QDateTime &dateTime, FormatType format = LongFormat) const;
/* Removing default value for `format' is done intentionally,
* after all tests we will remove non-calendar-aware version of these functions,
* and add a default value for both calendar instance, and format
*/
QString toString(const QDate &date, QStringView formatStr, QCalendar cal) const;
QString toString(const QDate &date, FormatType format, QCalendar cal) const;
QString toString(const QDateTime &dateTime, FormatType format, QCalendar cal) const;
QString toString(const QDateTime &dateTime, QStringView formatStr, QCalendar cal) const;
QString dateFormat(FormatType format = LongFormat) const; QString dateFormat(FormatType format = LongFormat) const;
QString timeFormat(FormatType format = LongFormat) const; QString timeFormat(FormatType format = LongFormat) const;
@ -1024,6 +1032,13 @@ public:
QDate toDate(const QString &string, const QString &format) const; QDate toDate(const QString &string, const QString &format) const;
QTime toTime(const QString &string, const QString &format) const; QTime toTime(const QString &string, const QString &format) const;
QDateTime toDateTime(const QString &string, const QString &format) const; QDateTime toDateTime(const QString &string, const QString &format) const;
// Calendar-aware API
QDate toDate(const QString &string, FormatType format, QCalendar cal) const;
QTime toTime(const QString &string, FormatType format, QCalendar cal) const;
QDateTime toDateTime(const QString &string, FormatType format, QCalendar cal) const;
QDate toDate(const QString &string, const QString &format, QCalendar cal) const;
QTime toTime(const QString &string, const QString &format, QCalendar cal) const;
QDateTime toDateTime(const QString &string, const QString &format, QCalendar cal) const;
#endif #endif
// ### Qt 5: We need to return QString from these function since // ### Qt 5: We need to return QString from these function since
@ -1108,6 +1123,8 @@ private:
QLocale(QLocalePrivate &dd); QLocale(QLocalePrivate &dd);
friend class QLocalePrivate; friend class QLocalePrivate;
friend class QSystemLocale; friend class QSystemLocale;
friend class QCalendarBackend;
friend class QGregorianCalendar;
friend Q_CORE_EXPORT uint qHash(const QLocale &key, uint seed) noexcept; friend Q_CORE_EXPORT uint qHash(const QLocale &key, uint seed) noexcept;
QSharedDataPointer<QLocalePrivate> d; QSharedDataPointer<QLocalePrivate> d;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation. ** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
@ -57,6 +57,7 @@
#include "QtCore/qvarlengtharray.h" #include "QtCore/qvarlengtharray.h"
#include "QtCore/qvariant.h" #include "QtCore/qvariant.h"
#include "QtCore/qnumeric.h" #include "QtCore/qnumeric.h"
#include <QtCore/qcalendar.h>
#include "qlocale.h" #include "qlocale.h"
@ -171,9 +172,14 @@ Q_DECLARE_TYPEINFO(QLocaleId, Q_PRIMITIVE_TYPE);
struct QLocaleData struct QLocaleData
{ {
public: public:
// TODO: Remove this?
static const QLocaleData *findLocaleData(QLocale::Language language, static const QLocaleData *findLocaleData(QLocale::Language language,
QLocale::Script script, QLocale::Script script,
QLocale::Country country); QLocale::Country country);
// Having an offset of current locale, enables us to have multiple sources of data, i.e. user-provided calendar locales
static uint findLocaleOffset(QLocale::Language language,
QLocale::Script script,
QLocale::Country country);
static const QLocaleData *c(); static const QLocaleData *c();
// Maximum number of significant digits needed to represent a double. // Maximum number of significant digits needed to represent a double.
@ -297,12 +303,6 @@ public:
quint16 m_long_date_format_idx, m_long_date_format_size; quint16 m_long_date_format_idx, m_long_date_format_size;
quint16 m_short_time_format_idx, m_short_time_format_size; quint16 m_short_time_format_idx, m_short_time_format_size;
quint16 m_long_time_format_idx, m_long_time_format_size; quint16 m_long_time_format_idx, m_long_time_format_size;
quint16 m_standalone_short_month_names_idx, m_standalone_short_month_names_size;
quint16 m_standalone_long_month_names_idx, m_standalone_long_month_names_size;
quint16 m_standalone_narrow_month_names_idx, m_standalone_narrow_month_names_size;
quint16 m_short_month_names_idx, m_short_month_names_size;
quint16 m_long_month_names_idx, m_long_month_names_size;
quint16 m_narrow_month_names_idx, m_narrow_month_names_size;
quint16 m_standalone_short_day_names_idx, m_standalone_short_day_names_size; quint16 m_standalone_short_day_names_idx, m_standalone_short_day_names_size;
quint16 m_standalone_long_day_names_idx, m_standalone_long_day_names_size; quint16 m_standalone_long_day_names_idx, m_standalone_long_day_names_size;
quint16 m_standalone_narrow_day_names_idx, m_standalone_narrow_day_names_size; quint16 m_standalone_narrow_day_names_idx, m_standalone_narrow_day_names_size;
@ -328,16 +328,17 @@ public:
quint16 m_weekend_end : 3; quint16 m_weekend_end : 3;
}; };
class Q_CORE_EXPORT QLocalePrivate class Q_CORE_EXPORT QLocalePrivate // A POD type
{ {
public: public:
static QLocalePrivate *create( static QLocalePrivate *create(
const QLocaleData *data, const QLocaleData *data, const uint data_offset = 0,
QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions) QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions)
{ {
QLocalePrivate *retval = new QLocalePrivate; auto *retval = new QLocalePrivate;
retval->m_data = data; retval->m_data = data;
retval->ref.storeRelaxed(0); retval->ref.storeRelaxed(0);
retval->m_data_offset = data_offset;
retval->m_numberOptions = numberOptions; retval->m_numberOptions = numberOptions;
return retval; return retval;
} }
@ -374,12 +375,9 @@ public:
QLocale::MeasurementSystem measurementSystem() const; QLocale::MeasurementSystem measurementSystem() const;
QString dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly,
const QLocale *q) const;
const QLocaleData *m_data; const QLocaleData *m_data;
QBasicAtomicInt ref; QBasicAtomicInt ref;
uint m_data_offset;
QLocale::NumberOptions m_numberOptions; QLocale::NumberOptions m_numberOptions;
}; };
@ -392,7 +390,7 @@ inline QLocalePrivate *QSharedDataPointer<QLocalePrivate>::clone()
{ {
// cannot use QLocalePrivate's copy constructor // cannot use QLocalePrivate's copy constructor
// since it is deleted in C++11 // since it is deleted in C++11
return QLocalePrivate::create(d->m_data, d->m_numberOptions); return QLocalePrivate::create(d->m_data, d->m_data_offset, d->m_numberOptions);
} }
inline char QLocaleData::digitToCLocale(QChar in) const inline char QLocaleData::digitToCLocale(QChar in) const

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCALENDAR_H
#define QCALENDAR_H
#include <limits>
#include <QtCore/qglobal.h>
#include <QtCore/qlocale.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringview.h>
/* Suggested enum names for other calendars known to CLDR (v33.1)
Not yet implemented - see QCalendar::System - contributions welcome:
* Buddhist -- Thai Buddhist, to be specific
* Chinese
* Coptic
* Dangi -- Korean
* Ethiopic (Amete Mihret - epoch approx. 8 C.E.)
* EthiopicAmeteAlem (Amete Alem - epoch approx. 5493 B.C.E; data from
type="ethiopic-amete-alem", an alias for type="ethioaa")
* Hebrew
* Indian -- National
* Islamic -- Based on astronomical observations, not predictions, so hard to
implement. CLDR's data for type="islamic" apply, unless overridden, to the
other Islamic calendar variants.
* IslamicTabular -- tabular, astronomical epoch, CLDR type="islamic-tbla"
* Saudi -- Saudi Arabia, sighting; CLDR type="islamic-rgsa"
* UmmAlQura -- Umm al-Qura, Saudi Arabia, calculated; CLDR type="islamic-umalqura"
* Iso8601 -- as Gregorian, but treating ISO 8601 weeks as "months"
* Japanese -- Imperial calendar
* Minguo -- Republic of China, Taiwan; CLDR type="roc"
See:
http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml
These can potentially be supported, as features, using CLDR's data; any
others shall need hand-crafted localization data; it would probably be best
to do that by contributing data for them to CLDR.
*/
QT_BEGIN_NAMESPACE
class QCalendarBackend;
class QDate;
class Q_CORE_EXPORT QCalendar
{
Q_GADGET
public:
// (Extra parentheses to suppress bogus reading of min() as a macro.)
enum : int { Unspecified = (std::numeric_limits<int>::min)() };
struct YearMonthDay
{
YearMonthDay() = default;
YearMonthDay(int y, int m = 1, int d = 1) : year(y), month(m), day(d) {}
bool isValid() const
{ return month != Unspecified && day != Unspecified; }
// (The first year supported by QDate has year == Unspecified.)
int year = Unspecified;
int month = Unspecified;
int day = Unspecified;
};
// Feature (\w+)calendar uses CLDR type="\1" data, except as noted in type="..." comments below
enum class System {
Gregorian, // CLDR: type = "gregory", alias = "gregorian"
Last = Gregorian,
User = -1
};
// New entries must be added to the \enum doc in qcalendar.cpp and
// handled in QCalendar::fromEnum()
Q_ENUM(System)
explicit QCalendar(); // Gregorian, optimised
explicit QCalendar(System system);
explicit QCalendar(QLatin1String name);
explicit QCalendar(QStringView name);
// QCalendar is a trivially copyable value type.
bool isValid() { return d != nullptr; }
// Date queries:
int daysInMonth(int month, int year = Unspecified) const;
int daysInYear(int year) const;
int monthsInYear(int year) const;
bool isDateValid(int year, int month, int day) const;
// Leap years:
bool isLeapYear(int year) const;
// Properties of the calendar:
bool isGregorian() const;
bool isLunar() const;
bool isLuniSolar() const;
bool isSolar() const;
bool isProleptic() const;
bool hasYearZero() const;
int maxDaysInMonth() const;
int minDaysInMonth() const;
int maxMonthsInYear() const;
QString name() const;
// QDate conversions:
QDate dateFromParts(int year, int month, int day) const;
QDate dateFromParts(const YearMonthDay &parts) const;
YearMonthDay partsFromDate(QDate date) const;
int dayOfWeek(QDate date) const;
// Month and week-day names (as in QLocale):
QString monthName(const QLocale &locale, int month, int year = Unspecified,
QLocale::FormatType format=QLocale::LongFormat) const;
QString standaloneMonthName(const QLocale &locale, int month, int year = Unspecified,
QLocale::FormatType format = QLocale::LongFormat) const;
QString weekDayName(const QLocale &locale, int day,
QLocale::FormatType format = QLocale::LongFormat) const;
QString standaloneWeekDayName(const QLocale &locale, int day,
QLocale::FormatType format=QLocale::LongFormat) const;
// Formatting of date-times:
QString dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly,
const QLocale &locale) const;
// What's available ?
static QStringList availableCalendars();
private:
// Always supplied by QCalendarBackend and expected to be a singleton
const QCalendarBackend *d;
};
QT_END_NAMESPACE
#endif // QCALENDAR_H

View File

@ -0,0 +1,144 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCALENDAR_BACKEND_P_H
#define QCALENDAR_BACKEND_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of calendar implementations. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qobjectdefs.h>
#include <QtCore/qcalendar.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qstring.h>
#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
// Locale-related parts, mostly handled in ../text/qlocale.cpp
struct QLocaleDataEntry {
quint16 index, size;
};
struct QCalendarLocale {
quint16 m_language_id, m_script_id, m_country_id;
// Month name indexes:
QLocaleDataEntry m_standalone_short;
QLocaleDataEntry m_standalone_long;
QLocaleDataEntry m_standalone_narrow;
QLocaleDataEntry m_short;
QLocaleDataEntry m_long;
QLocaleDataEntry m_narrow;
};
// Partial implementation, of methods with common forms, in qcalendar.cpp
class Q_CORE_EXPORT QCalendarBackend
{
friend class QCalendar;
public:
virtual ~QCalendarBackend();
virtual QString name() const = 0;
virtual QCalendar::System calendarSystem() const;
// Date queries:
virtual int daysInMonth(int month, int year = QCalendar::Unspecified) const = 0;
virtual int daysInYear(int year) const;
virtual int monthsInYear(int year) const;
virtual bool isDateValid(int year, int month, int day) const;
// Properties of the calendar:
virtual bool isLeapYear(int year) const = 0;
virtual bool isLunar() const = 0;
virtual bool isLuniSolar() const = 0;
virtual bool isSolar() const = 0;
virtual bool isProleptic() const;
virtual bool hasYearZero() const;
virtual int maxDaysInMonth() const;
virtual int minDaysInMonth() const;
virtual int maxMonthsInYear() const;
// Julian Day conversions:
virtual bool dateToJulianDay(int year, int month, int day, qint64 *jd) const = 0;
virtual QCalendar::YearMonthDay julianDayToDate(qint64 jd) const = 0;
// Day of week and week numbering:
virtual int dayOfWeek(qint64 jd) const;
// Names of months and week-days (implemented in qlocale.cpp):
virtual QString monthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const;
virtual QString standaloneMonthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const;
virtual QString weekDayName(const QLocale &locale, int day,
QLocale::FormatType format) const;
virtual QString standaloneWeekDayName(const QLocale &locale, int day,
QLocale::FormatType format) const;
// Formatting of date-times (implemented in qlocale.cpp):
virtual QString dateTimeToString(QStringView format, const QDateTime &datetime,
const QDate &dateOnly, const QTime &timeOnly,
const QLocale &locale) const;
// Calendar enumeration by name:
static QStringList availableCalendars();
protected:
QCalendarBackend(const QString &name, QCalendar::System id = QCalendar::System::User);
// Locale support:
virtual const QCalendarLocale *localeMonthIndexData() const = 0;
virtual const ushort *localeMonthData() const = 0;
bool registerAlias(const QString &name);
private:
// QCalendar's access to its registry:
static const QCalendarBackend *fromName(QStringView name);
static const QCalendarBackend *fromName(QLatin1String name);
// QCalendar's access to singletons:
static const QCalendarBackend *fromEnum(QCalendar::System system);
};
QT_END_NAMESPACE
#endif // QCALENDAR_BACKEND_P_H

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCALENDARMATH_P_H
#define QCALENDARMATH_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of q*calendar.cpp. This header file may change from version to version
// without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
namespace QRoundingDown {
/*
Division, rounding down (rather than towards zero).
From C++11 onwards, integer division is defined to round towards zero, so we
can rely on that when implementing this. This is only used with denominator b
> 0, so we only have to treat negative numerator, a, specially.
*/
template<typename Int> constexpr Int qDiv(Int a, unsigned b)
{ return (a - (a < 0 ? int(b - 1) : 0)) / int(b); }
template<typename Int> constexpr Int qMod(Int a, unsigned b)
{ return a - qDiv(a, b) * b; }
} // QRoundingDown
QT_END_NAMESPACE
#endif // QCALENDARMATH_P_H

View File

@ -73,6 +73,8 @@
#include <private/qcore_mac_p.h> #include <private/qcore_mac_p.h>
#endif #endif
#include "qcalendar.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
/***************************************************************************** /*****************************************************************************
@ -94,78 +96,13 @@ enum {
QDate static helper functions QDate static helper functions
*****************************************************************************/ *****************************************************************************/
static inline QDate fixedDate(int y, int m, int d) static inline QDate fixedDate(QCalendar::YearMonthDay &&parts, QCalendar cal)
{ {
QDate result(y, m, 1); if ((parts.year < 0 && !cal.isProleptic()) || (parts.year == 0 && !cal.hasYearZero()))
result.setDate(y, m, qMin(d, result.daysInMonth())); return QDate();
return result;
}
/* parts.day = qMin(parts.day, cal.daysInMonth(parts.month, parts.year));
Division, rounding down (rather than towards zero). return cal.dateFromParts(parts);
From C++11 onwards, integer division is defined to round towards zero, so we
can rely on that when implementing this. This is only used with denominator b
> 0, so we only have to treat negative numerator, a, specially.
*/
static inline qint64 floordiv(qint64 a, int b)
{
return (a - (a < 0 ? b - 1 : 0)) / b;
}
static inline int floordiv(int a, int b)
{
return (a - (a < 0 ? b - 1 : 0)) / b;
}
static inline qint64 julianDayFromDate(int year, int month, int day)
{
// Adjust for no year 0
if (year < 0)
++year;
/*
* Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
* This formula is correct for all julian days, when using mathematical integer
* division (round to negative infinity), not c++11 integer division (round to zero)
*/
int a = floordiv(14 - month, 12);
qint64 y = (qint64)year + 4800 - a;
int m = month + 12 * a - 3;
return day + floordiv(153 * m + 2, 5) + 365 * y + floordiv(y, 4) - floordiv(y, 100) + floordiv(y, 400) - 32045;
}
struct ParsedDate
{
int year, month, day;
};
// prevent this function from being inlined into all 10 users
Q_NEVER_INLINE
static ParsedDate getDateFromJulianDay(qint64 julianDay)
{
/*
* Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
* This formula is correct for all julian days, when using mathematical integer
* division (round to negative infinity), not c++11 integer division (round to zero)
*/
qint64 a = julianDay + 32044;
qint64 b = floordiv(4 * a + 3, 146097);
int c = a - floordiv(146097 * b, 4);
int d = floordiv(4 * c + 3, 1461);
int e = c - floordiv(1461 * d, 4);
int m = floordiv(5 * e + 2, 153);
int day = e - floordiv(153 * m + 2, 5) + 1;
int month = m + 3 - 12 * floordiv(m, 10);
int year = 100 * b + d - 4800 + floordiv(m, 10);
// Adjust for no year 0
if (year <= 0)
--year ;
return { year, month, day };
} }
/***************************************************************************** /*****************************************************************************
@ -189,7 +126,7 @@ static int qt_monthNumberFromShortName(QStringRef shortName)
static int qt_monthNumberFromShortName(const QString &shortName) static int qt_monthNumberFromShortName(const QString &shortName)
{ return qt_monthNumberFromShortName(QStringRef(&shortName)); } { return qt_monthNumberFromShortName(QStringRef(&shortName)); }
static int fromShortMonthName(const QStringRef &monthName) static int fromShortMonthName(const QStringRef &monthName, int year)
{ {
// Assume that English monthnames are the default // Assume that English monthnames are the default
int month = qt_monthNumberFromShortName(monthName); int month = qt_monthNumberFromShortName(monthName);
@ -197,7 +134,7 @@ static int fromShortMonthName(const QStringRef &monthName)
return month; return month;
// If English names can't be found, search the localized ones // If English names can't be found, search the localized ones
for (int i = 1; i <= 12; ++i) { for (int i = 1; i <= 12; ++i) {
if (monthName == QLocale::system().monthName(i, QLocale::ShortFormat)) if (monthName == QCalendar().monthName(QLocale::system(), i, year, QLocale::ShortFormat))
return i; return i;
} }
return -1; return -1;
@ -303,12 +240,6 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcep
} }
#endif // datestring #endif // datestring
static constexpr int daysInUsualMonth(int month) // (February isn't usual.)
{
// Long if odd up to July = 7, or if even from 8 = August onwards:
return Q_ASSERT(month != 2 && month > 0 && month <= 12), 30 | ((month & 1) ^ (month >> 3));
}
/***************************************************************************** /*****************************************************************************
QDate member functions QDate member functions
*****************************************************************************/ *****************************************************************************/
@ -385,7 +316,7 @@ static constexpr int daysInUsualMonth(int month) // (February isn't usual.)
for technical reasons limited to between -784350574879 and 784354017364, for technical reasons limited to between -784350574879 and 784354017364,
which means from before 2 billion BCE to after 2 billion CE. which means from before 2 billion BCE to after 2 billion CE.
\sa QTime, QDateTime, QDateTime::YearRange, QDateEdit, QDateTimeEdit, QCalendarWidget \sa QTime, QDateTime, QCalendar, QDateTime::YearRange, QDateEdit, QDateTimeEdit, QCalendarWidget
*/ */
/*! /*!
@ -399,19 +330,23 @@ static constexpr int daysInUsualMonth(int month) // (February isn't usual.)
/*! /*!
Constructs a date with year \a y, month \a m and day \a d. Constructs a date with year \a y, month \a m and day \a d.
If the specified date is invalid, the date is not set and The date is understood in terms of the Gregorian calendar. If the specified
isValid() returns \c false. date is invalid, the date is not set and isValid() returns \c false.
\warning Years 1 to 99 are interpreted as is. Year 0 is invalid. \warning Years 1 to 99 are interpreted as is. Year 0 is invalid.
\sa isValid() \sa isValid(), QCalendar::dateFromParts()
*/ */
QDate::QDate(int y, int m, int d) QDate::QDate(int y, int m, int d)
{ {
setDate(y, m, d); *this = QCalendar().dateFromParts(y, m, d);
} }
QDate::QDate(int y, int m, int d, QCalendar cal)
{
*this = cal.dateFromParts(y, m, d);
}
/*! /*!
\fn bool QDate::isNull() const \fn bool QDate::isNull() const
@ -429,29 +364,56 @@ QDate::QDate(int y, int m, int d)
Returns \c true if this date is valid; otherwise returns \c false. Returns \c true if this date is valid; otherwise returns \c false.
\sa isNull() \sa isNull(), QCalendar::isDateValid()
*/ */
/*! /*!
Returns the year of this date. Negative numbers indicate years Returns the year of this date.
before 1 CE, such that year -44 is 44 BCE.
Returns 0 if the date is invalid. Uses \a cal as calendar, if supplied, else the Gregorian calendar.
\sa month(), day() Returns 0 if the date is invalid. For some calendars, dates before their
first year may all be invalid.
If using a calendar which has a year 0, check using isValid() if the return
is 0. Such calendars use negative year numbers in the obvious way, with
year 1 preceded by year 0, in turn preceded by year -1 and so on.
Some calendars, despite having no year 0, have a conventional numbering of
the years before their first year, counting backwards from 1. For example,
in the proleptic Gregorian calendar, successive years before 1 CE (the first
year) are identified as 1 BCE, 2 BCE, 3 BCE and so on. For such calendars,
negative year numbers are used to indicate these years before year 1, with
-1 indicating the year before 1.
\sa month(), day(), QCalendar::hasYearZero(), QCalendar::isProleptic()
*/ */
int QDate::year() const int QDate::year(QCalendar cal) const
{ {
if (isNull()) if (isValid()) {
const auto parts = cal.partsFromDate(*this);
if (parts.isValid())
return parts.year;
}
return 0; return 0;
return getDateFromJulianDay(jd).year;
} }
/*! /*!
Returns the number corresponding to the month of this date, using \overload
the following convention: */
int QDate::year() const
{
return year(QCalendar());
}
/*!
Returns the month-number for the date.
Numbers the months of the year starting with 1 for the first. Uses \a cal
as calendar if supplied, else the Gregorian calendar, for which the month
numbering is as follows:
\list \list
\li 1 = "January" \li 1 = "January"
@ -468,105 +430,166 @@ int QDate::year() const
\li 12 = "December" \li 12 = "December"
\endlist \endlist
Returns 0 if the date is invalid. Returns 0 if the date is invalid. Note that some calendars may have more
than 12 months in some years.
\sa year(), day() \sa year(), day()
*/ */
int QDate::month() const int QDate::month(QCalendar cal) const
{ {
if (isNull()) if (isValid()) {
const auto parts = cal.partsFromDate(*this);
if (parts.isValid())
return parts.month;
}
return 0; return 0;
return getDateFromJulianDay(jd).month;
} }
/*! /*!
Returns the day of the month (1 to 31) of this date. \overload
*/
Returns 0 if the date is invalid. int QDate::month() const
{
return month(QCalendar());
}
/*!
Returns the day of the month for this date.
Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
the return ranges from 1 to 31). Returns 0 if the date is invalid.
\sa year(), month(), dayOfWeek() \sa year(), month(), dayOfWeek()
*/ */
int QDate::day(QCalendar cal) const
{
if (isValid()) {
const auto parts = cal.partsFromDate(*this);
if (parts.isValid())
return parts.day;
}
return 0;
}
/*!
\overload
*/
int QDate::day() const int QDate::day() const
{ {
if (isNull()) return day(QCalendar());
return 0;
return getDateFromJulianDay(jd).day;
} }
/*! /*!
Returns the weekday (1 = Monday to 7 = Sunday) for this date. Returns the weekday (1 = Monday to 7 = Sunday) for this date.
Returns 0 if the date is invalid. Uses \a cal as calendar if supplied, else the Gregorian calendar. Returns 0
if the date is invalid. Some calendars may give special meaning
(e.g. intercallary days) to values greater than 7.
\sa day(), dayOfYear(), Qt::DayOfWeek \sa day(), dayOfYear(), Qt::DayOfWeek
*/ */
int QDate::dayOfWeek() const int QDate::dayOfWeek(QCalendar cal) const
{ {
if (isNull()) if (isNull())
return 0; return 0;
if (jd >= 0) return cal.dayOfWeek(*this);
return (jd % 7) + 1;
else
return ((jd + 1) % 7) + 7;
} }
/*! /*!
Returns the day of the year (1 to 365 or 366 on leap years) for \overload
this date. */
Returns 0 if the date is invalid. int QDate::dayOfWeek() const
{
return dayOfWeek(QCalendar());
}
/*!
Returns the day of the year (1 for the first day) for this date.
Uses \a cal as calendar if supplied, else the Gregorian calendar.
Returns 0 if either the date or the first day of its year is invalid.
\sa day(), dayOfWeek() \sa day(), dayOfWeek()
*/ */
int QDate::dayOfYear() const int QDate::dayOfYear(QCalendar cal) const
{ {
if (isNull()) if (isValid()) {
QDate firstDay = cal.dateFromParts(year(cal), 1, 1);
if (firstDay.isValid())
return firstDay.daysTo(*this) + 1;
}
return 0; return 0;
return jd - julianDayFromDate(year(), 1, 1) + 1;
} }
/*! /*!
Returns the number of days in the month (28 to 31) for this date. \overload
*/
Returns 0 if the date is invalid. int QDate::dayOfYear() const
{
return dayOfYear(QCalendar());
}
/*!
Returns the number of days in the month for this date.
Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
the result ranges from 28 to 31). Returns 0 if the date is invalid.
\sa day(), daysInYear() \sa day(), daysInYear()
*/ */
int QDate::daysInMonth() const int QDate::daysInMonth(QCalendar cal) const
{ {
if (isNull()) if (isValid()) {
const auto parts = cal.partsFromDate(*this);
if (parts.isValid())
return cal.daysInMonth(parts.month, parts.year);
}
return 0; return 0;
const ParsedDate pd = getDateFromJulianDay(jd);
if (pd.month == 2)
return isLeapYear(pd.year) ? 29 : 28;
return daysInUsualMonth(pd.month);
} }
/*! /*!
Returns the number of days in the year (365 or 366) for this date. \overload
*/
Returns 0 if the date is invalid. int QDate::daysInMonth() const
{
return daysInMonth(QCalendar());
}
/*!
Returns the number of days in the year for this date.
Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
the result is 365 or 366). Returns 0 if the date is invalid.
\sa day(), daysInMonth() \sa day(), daysInMonth()
*/ */
int QDate::daysInYear() const int QDate::daysInYear(QCalendar cal) const
{ {
if (isNull()) if (isNull())
return 0; return 0;
return isLeapYear(getDateFromJulianDay(jd).year) ? 366 : 365; return cal.daysInYear(year(cal));
}
/*!
\overload
*/
int QDate::daysInYear() const
{
return daysInYear(QCalendar());
} }
/*! /*!
@ -593,6 +616,7 @@ int QDate::weekNumber(int *yearNumber) const
if (!isValid()) if (!isValid())
return 0; return 0;
// This could be replaced by use of QIso8601Calendar, once we implement it.
// The Thursday of the same week determines our answer: // The Thursday of the same week determines our answer:
QDate thursday(addDays(4 - dayOfWeek())); QDate thursday(addDays(4 - dayOfWeek()));
int year = thursday.year(); int year = thursday.year();
@ -904,9 +928,11 @@ QString QDate::shortMonthName(int month, QDate::MonthNameType type)
{ {
switch (type) { switch (type) {
case QDate::DateFormat: case QDate::DateFormat:
return QLocale::system().monthName(month, QLocale::ShortFormat); return QCalendar().monthName(QLocale::system(), month,
QCalendar::Unspecified, QLocale::ShortFormat);
case QDate::StandaloneFormat: case QDate::StandaloneFormat:
return QLocale::system().standaloneMonthName(month, QLocale::ShortFormat); return QCalendar().standaloneMonthName(QLocale::system(), month,
QCalendar::Unspecified, QLocale::ShortFormat);
} }
return QString(); return QString();
} }
@ -947,9 +973,11 @@ QString QDate::longMonthName(int month, MonthNameType type)
{ {
switch (type) { switch (type) {
case QDate::DateFormat: case QDate::DateFormat:
return QLocale::system().monthName(month, QLocale::LongFormat); return QCalendar().monthName(QLocale::system(), month,
QCalendar::Unspecified, QLocale::LongFormat);
case QDate::StandaloneFormat: case QDate::StandaloneFormat:
return QLocale::system().standaloneMonthName(month, QLocale::LongFormat); return QCalendar().standaloneMonthName(QLocale::system(), month,
QCalendar::Unspecified, QLocale::LongFormat);
} }
return QString(); return QString();
} }
@ -1034,23 +1062,31 @@ QString QDate::longDayName(int weekday, MonthNameType type)
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
#if QT_CONFIG(textdate) #if QT_CONFIG(textdate)
static QString toStringTextDate(QDate date, QCalendar cal)
{
if (date.isValid()) {
const auto parts = cal.partsFromDate(date);
if (parts.isValid()) {
const QLatin1Char sp(' ');
return QLocale::system().dayName(cal.dayOfWeek(date), QLocale::ShortFormat) + sp
+ cal.monthName(QLocale::system(), parts.month, parts.year, QLocale::ShortFormat)
+ sp + QString::number(parts.day) + sp + QString::number(parts.year);
}
}
return QString();
}
static QString toStringTextDate(QDate date) static QString toStringTextDate(QDate date)
{ {
const ParsedDate pd = getDateFromJulianDay(date.toJulianDay()); return toStringTextDate(date, QCalendar());
static const QLatin1Char sp(' ');
return QLocale::system().dayName(date.dayOfWeek(), QLocale::ShortFormat) + sp
+ QLocale::system().monthName(pd.month, QLocale::ShortFormat) + sp
+ QString::number(pd.day) + sp
+ QString::number(pd.year);
} }
#endif // textdate #endif // textdate
static QString toStringIsoDate(qint64 jd) static QString toStringIsoDate(const QDate &date)
{ {
const ParsedDate pd = getDateFromJulianDay(jd); const auto parts = QCalendar().partsFromDate(date);
if (pd.year >= 0 && pd.year <= 9999) if (parts.isValid() && parts.year >= 0 && parts.year <= 9999)
return QString::asprintf("%04d-%02d-%02d", pd.year, pd.month, pd.day); return QString::asprintf("%04d-%02d-%02d", parts.year, parts.month, parts.day);
else
return QString(); return QString();
} }
@ -1124,7 +1160,7 @@ QString QDate::toString(Qt::DateFormat format) const
#endif #endif
case Qt::ISODate: case Qt::ISODate:
case Qt::ISODateWithMs: case Qt::ISODateWithMs:
return toStringIsoDate(jd); return toStringIsoDate(*this);
} }
} }
@ -1198,6 +1234,47 @@ QString QDate::toString(const QString &format) const
} }
#endif #endif
QString QDate::toString(Qt::DateFormat format, QCalendar cal) const
{
if (!isValid())
return QString();
switch (format) {
case Qt::SystemLocaleDate:
case Qt::SystemLocaleShortDate:
return QLocale::system().toString(*this, QLocale::ShortFormat, cal);
case Qt::SystemLocaleLongDate:
return QLocale::system().toString(*this, QLocale::LongFormat, cal);
case Qt::LocaleDate:
case Qt::DefaultLocaleShortDate:
return QLocale().toString(*this, QLocale::ShortFormat, cal);
case Qt::DefaultLocaleLongDate:
return QLocale().toString(*this, QLocale::LongFormat, cal);
case Qt::RFC2822Date:
return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal);
default:
#ifndef QT_NO_TEXTDATE
case Qt::TextDate:
return toStringTextDate(*this, cal);
#endif
case Qt::ISODate:
case Qt::ISODateWithMs:
return toStringIsoDate(*this);
}
}
QString QDate::toString(QStringView format, QCalendar cal) const
{
return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6
}
#if QT_STRINGVIEW_LEVEL < 2
QString QDate::toString(const QString &format, QCalendar cal) const
{
return toString(qToStringViewIgnoringNull(format), cal);
}
#endif
#endif // datestring #endif // datestring
/*! /*!
@ -1217,21 +1294,32 @@ QString QDate::toString(const QString &format) const
/*! /*!
\since 4.2 \since 4.2
Sets the date's \a year, \a month, and \a day. Returns \c true if Sets this to represent the date, in the Gregorian calendar, with the given
the date is valid; otherwise returns \c false. \a year, \a month and \a day numbers. Returns true if the resulting date is
valid, otherwise it sets this to represent an invalid date and returns
false.
If the specified date is invalid, the QDate object is set to be \sa isValid(), QCalendar::dateFromParts()
invalid.
\sa isValid()
*/ */
bool QDate::setDate(int year, int month, int day) bool QDate::setDate(int year, int month, int day)
{ {
if (isValid(year, month, day)) return setDate(year, month, day, QCalendar());
jd = julianDayFromDate(year, month, day); }
else
jd = nullJd();
/*!
\since 5.14
Sets this to represent the date, in the given calendar \a cal, with the
given \a year, \a month and \a day numbers. Returns true if the resulting
date is valid, otherwise it sets this to represent an invalid date and
returns false.
\sa isValid(), QCalendar::dateFromParts()
*/
bool QDate::setDate(int year, int month, int day, QCalendar cal)
{
*this = QDate(year, month, day, cal);
return isValid(); return isValid();
} }
@ -1245,20 +1333,21 @@ bool QDate::setDate(int year, int month, int day)
\note In Qt versions prior to 5.7, this function is marked as non-\c{const}. \note In Qt versions prior to 5.7, this function is marked as non-\c{const}.
\sa year(), month(), day(), isValid() \sa year(), month(), day(), isValid(), QCalendar::partsFromDate()
*/ */
void QDate::getDate(int *year, int *month, int *day) const void QDate::getDate(int *year, int *month, int *day) const
{ {
ParsedDate pd = { 0, 0, 0 }; QCalendar::YearMonthDay parts; // invalid by default
if (isValid()) if (isValid())
pd = getDateFromJulianDay(jd); parts = QCalendar().partsFromDate(*this);
const bool ok = parts.isValid();
if (year) if (year)
*year = pd.year; *year = ok ? parts.year : 0;
if (month) if (month)
*month = pd.month; *month = ok ? parts.month : 0;
if (day) if (day)
*day = pd.day; *day = ok ? parts.day : 0;
} }
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
@ -1296,96 +1385,92 @@ QDate QDate::addDays(qint64 ndays) const
Returns a QDate object containing a date \a nmonths later than the Returns a QDate object containing a date \a nmonths later than the
date of this object (or earlier if \a nmonths is negative). date of this object (or earlier if \a nmonths is negative).
\note If the ending day/month combination does not exist in the Uses \a cal as calendar, if supplied, else the Gregorian calendar.
resulting month/year, this function will return a date that is the
latest valid date. \note If the ending day/month combination does not exist in the resulting
month/year, this function will return a date that is the latest valid date
in the selected month.
\sa addDays(), addYears() \sa addDays(), addYears()
*/ */
QDate QDate::addMonths(int nmonths) const QDate QDate::addMonths(int nmonths, QCalendar cal) const
{ {
if (!isValid()) if (!isValid())
return QDate(); return QDate();
if (!nmonths)
if (nmonths == 0)
return *this; return *this;
int old_y, y, m, d; auto parts = cal.partsFromDate(*this);
{
const ParsedDate pd = getDateFromJulianDay(jd);
y = pd.year;
m = pd.month;
d = pd.day;
}
old_y = y;
bool increasing = nmonths > 0; if (!parts.isValid())
return QDate();
Q_ASSERT(parts.year || cal.hasYearZero());
while (nmonths != 0) { parts.month += nmonths;
if (nmonths < 0 && nmonths + 12 <= 0) { while (parts.month <= 0) {
y--; if (--parts.year || cal.hasYearZero())
nmonths+=12; parts.month += cal.monthsInYear(parts.year);
} else if (nmonths < 0) {
m+= nmonths;
nmonths = 0;
if (m <= 0) {
--y;
m += 12;
}
} else if (nmonths - 12 >= 0) {
y++;
nmonths -= 12;
} else if (m == 12) {
y++;
m = 0;
} else {
m += nmonths;
nmonths = 0;
if (m > 12) {
++y;
m -= 12;
}
} }
int count = cal.monthsInYear(parts.year);
while (parts.month > count) {
parts.month -= count;
count = (++parts.year || cal.hasYearZero()) ? cal.monthsInYear(parts.year) : 0;
} }
// was there a sign change? return fixedDate(std::move(parts), cal);
if ((old_y > 0 && y <= 0) || }
(old_y < 0 && y >= 0))
// yes, adjust the date by +1 or -1 years
y += increasing ? +1 : -1;
return fixedDate(y, m, d); /*!
\override
*/
QDate QDate::addMonths(int nmonths) const
{
return addMonths(nmonths, QCalendar());
} }
/*! /*!
Returns a QDate object containing a date \a nyears later than the Returns a QDate object containing a date \a nyears later than the
date of this object (or earlier if \a nyears is negative). date of this object (or earlier if \a nyears is negative).
\note If the ending day/month combination does not exist in the Uses \a cal as calendar, if supplied, else the Gregorian calendar.
resulting year (i.e., if the date was Feb 29 and the final year is
not a leap year), this function will return a date that is the \note If the ending day/month combination does not exist in the resulting
latest valid date (that is, Feb 28). year (e.g., for the Gregorian calendar, if the date was Feb 29 and the final
year is not a leap year), this function will return a date that is the
latest valid date in the given month (in the example, Feb 28).
\sa addDays(), addMonths() \sa addDays(), addMonths()
*/ */
QDate QDate::addYears(int nyears) const QDate QDate::addYears(int nyears, QCalendar cal) const
{ {
if (!isValid()) if (!isValid())
return QDate(); return QDate();
ParsedDate pd = getDateFromJulianDay(jd); auto parts = cal.partsFromDate(*this);
if (!parts.isValid())
return QDate();
int old_y = pd.year; int old_y = parts.year;
pd.year += nyears; parts.year += nyears;
// was there a sign change? // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
if ((old_y > 0 && pd.year <= 0) || if (!cal.hasYearZero() && ((old_y > 0) != (parts.year > 0) || !parts.year))
(old_y < 0 && pd.year >= 0)) parts.year += nyears > 0 ? +1 : -1;
// yes, adjust the date by +1 or -1 years
pd.year += nyears > 0 ? +1 : -1;
return fixedDate(pd.year, pd.month, pd.day); return fixedDate(std::move(parts), cal);
}
/*!
\override
*/
QDate QDate::addYears(int nyears) const
{
return addYears(nyears, QCalendar());
} }
/*! /*!
@ -1505,7 +1590,7 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format)
if (!ok || !day) if (!ok || !day)
return QDate(); return QDate();
const int month = fromShortMonthName(parts.at(1)); const int month = fromShortMonthName(parts.at(1), year);
if (month == -1) // Month name matches no English or localised name. if (month == -1) // Month name matches no English or localised name.
return QDate(); return QDate();
@ -1531,6 +1616,10 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format)
Returns the QDate represented by the \a string, using the \a Returns the QDate represented by the \a string, using the \a
format given, or an invalid date if the string cannot be parsed. format given, or an invalid date if the string cannot be parsed.
Uses \a cal as calendar if supplied, else the Gregorian calendar. Ranges of
values in the format descriptions below are for the latter; they may be
different for other calendars.
These expressions may be used for the format: These expressions may be used for the format:
\table \table
@ -1590,55 +1679,61 @@ QDate QDate::fromString(const QString &string, Qt::DateFormat format)
QLocale::toDate() QLocale::toDate()
*/ */
QDate QDate::fromString(const QString &string, const QString &format) QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
{ {
QDate date; QDate date;
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal);
// dt.setDefaultLocale(QLocale::c()); ### Qt 6 // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format)) if (dt.parseFormat(format))
dt.fromString(string, &date, 0); dt.fromString(string, &date, 0);
#else #else
Q_UNUSED(string); Q_UNUSED(string);
Q_UNUSED(format); Q_UNUSED(format);
Q_UNUSED(cal);
#endif #endif
return date; return date;
} }
/*!
\overload
*/
QDate QDate::fromString(const QString &string, const QString &format)
{
return fromString(string, format, QCalendar());
}
#endif // datestring #endif // datestring
/*! /*!
\overload \overload
Returns \c true if the specified date (\a year, \a month, and \a Returns \c true if the specified date (\a year, \a month, and \a day) is
day) is valid; otherwise returns \c false. valid in the Gregorian calendar; otherwise returns \c false.
Example: Example:
\snippet code/src_corelib_tools_qdatetime.cpp 4 \snippet code/src_corelib_tools_qdatetime.cpp 4
\sa isNull(), setDate() \sa isNull(), setDate(), QCalendar::isDateValid()
*/ */
bool QDate::isValid(int year, int month, int day) bool QDate::isValid(int year, int month, int day)
{ {
// There is no year 0 in the Gregorian calendar. return QCalendar().isDateValid(year, month, day);
return year && day > 0 && month > 0 && month <= 12 &&
day <= (month == 2 ? isLeapYear(year) ? 29 : 28 : daysInUsualMonth(month));
} }
/*! /*!
\fn bool QDate::isLeapYear(int year) \fn bool QDate::isLeapYear(int year)
Returns \c true if the specified \a year is a leap year; otherwise Returns \c true if the specified \a year is a leap year in the Gregorian
returns \c false. calendar; otherwise returns \c false.
\sa QCalendar::isLeapYear()
*/ */
bool QDate::isLeapYear(int y) bool QDate::isLeapYear(int y)
{ {
// No year 0 in Gregorian calendar, so -1, -5, -9 etc are leap years return QCalendar().isLeapYear(y);
if ( y < 1)
++y;
return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
} }
/*! \fn static QDate QDate::fromJulianDay(qint64 jd) /*! \fn static QDate QDate::fromJulianDay(qint64 jd)
@ -2311,7 +2406,7 @@ QTime QTime::fromString(const QString &string, const QString &format)
{ {
QTime time; QTime time;
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, QCalendar());
// dt.setDefaultLocale(QLocale::c()); ### Qt 6 // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format)) if (dt.parseFormat(format))
dt.fromString(string, 0, &time); dt.fromString(string, 0, &time);
@ -4686,12 +4781,10 @@ static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec =
QDate QDate::currentDate() QDate QDate::currentDate()
{ {
QDate d;
SYSTEMTIME st; SYSTEMTIME st;
memset(&st, 0, sizeof(SYSTEMTIME)); memset(&st, 0, sizeof(SYSTEMTIME));
GetLocalTime(&st); GetLocalTime(&st);
d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); return QDate(st.wYear, st.wMonth, st.wDay);
return d;
} }
QTime QTime::currentTime() QTime QTime::currentTime()
@ -4706,24 +4799,22 @@ QTime QTime::currentTime()
QDateTime QDateTime::currentDateTime() QDateTime QDateTime::currentDateTime()
{ {
QDate d;
QTime t; QTime t;
SYSTEMTIME st; SYSTEMTIME st;
memset(&st, 0, sizeof(SYSTEMTIME)); memset(&st, 0, sizeof(SYSTEMTIME));
GetLocalTime(&st); GetLocalTime(&st);
d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); QDate d(st.wYear, st.wMonth, st.wDay);
t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
return QDateTime(d, t); return QDateTime(d, t);
} }
QDateTime QDateTime::currentDateTimeUtc() QDateTime QDateTime::currentDateTimeUtc()
{ {
QDate d;
QTime t; QTime t;
SYSTEMTIME st; SYSTEMTIME st;
memset(&st, 0, sizeof(SYSTEMTIME)); memset(&st, 0, sizeof(SYSTEMTIME));
GetSystemTime(&st); GetSystemTime(&st);
d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); QDate d(st.wYear, st.wMonth, st.wDay);
t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
return QDateTime(d, t, Qt::UTC); return QDateTime(d, t, Qt::UTC);
} }
@ -4733,10 +4824,10 @@ qint64 QDateTime::currentMSecsSinceEpoch() noexcept
SYSTEMTIME st; SYSTEMTIME st;
memset(&st, 0, sizeof(SYSTEMTIME)); memset(&st, 0, sizeof(SYSTEMTIME));
GetSystemTime(&st); GetSystemTime(&st);
const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) + return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +
qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay) daysAfterEpoch * Q_INT64_C(86400000);
- julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400000);
} }
qint64 QDateTime::currentSecsSinceEpoch() noexcept qint64 QDateTime::currentSecsSinceEpoch() noexcept
@ -4744,10 +4835,10 @@ qint64 QDateTime::currentSecsSinceEpoch() noexcept
SYSTEMTIME st; SYSTEMTIME st;
memset(&st, 0, sizeof(SYSTEMTIME)); memset(&st, 0, sizeof(SYSTEMTIME));
GetSystemTime(&st); GetSystemTime(&st);
const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond + return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond +
qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay) daysAfterEpoch * Q_INT64_C(86400);
- julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400);
} }
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
@ -5126,13 +5217,13 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
return QDateTime(); return QDateTime();
// Next try month then day // Next try month then day
month = fromShortMonthName(parts.at(1)); month = fromShortMonthName(parts.at(1), year);
if (month) if (month)
day = parts.at(2).toInt(&ok); day = parts.at(2).toInt(&ok);
// If failed, try day then month // If failed, try day then month
if (!ok || !month || !day) { if (!ok || !month || !day) {
month = fromShortMonthName(parts.at(2)); month = fromShortMonthName(parts.at(2), year);
if (month) { if (month) {
QStringRef dayStr = parts.at(1); QStringRef dayStr = parts.at(1);
if (dayStr.endsWith(QLatin1Char('.'))) { if (dayStr.endsWith(QLatin1Char('.'))) {
@ -5213,6 +5304,10 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
Returns the QDateTime represented by the \a string, using the \a Returns the QDateTime represented by the \a string, using the \a
format given, or an invalid datetime if the string cannot be parsed. format given, or an invalid datetime if the string cannot be parsed.
Uses the calendar \a cal if supplied, else Gregorian. The illustrative
values and ranges below are given for the latter; other calendars may have
different ranges or values.
These expressions may be used for the date part of the format string: These expressions may be used for the date part of the format string:
\table \table
@ -5315,23 +5410,33 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
QLocale::toDateTime() QLocale::toDateTime()
*/ */
QDateTime QDateTime::fromString(const QString &string, const QString &format) QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
{ {
#if QT_CONFIG(datetimeparser) #if QT_CONFIG(datetimeparser)
QTime time; QTime time;
QDate date; QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString); QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString, cal);
// dt.setDefaultLocale(QLocale::c()); ### Qt 6 // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time); return QDateTime(date, time);
#else #else
Q_UNUSED(string); Q_UNUSED(string);
Q_UNUSED(format); Q_UNUSED(format);
Q_UNUSED(cal);
#endif #endif
return QDateTime(); return QDateTime();
} }
/*
\overload
*/
QDateTime QDateTime::fromString(const QString &string, const QString &format)
{
return fromString(string, format, QCalendar());
}
#endif // datestring #endif // datestring
/*! /*!
\fn QDateTime QDateTime::toLocalTime() const \fn QDateTime QDateTime::toLocalTime() const

View File

@ -54,6 +54,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSDate);
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QCalendar;
class QTimeZone; class QTimeZone;
class QDateTime; class QDateTime;
@ -69,6 +70,7 @@ private:
public: public:
Q_DECL_CONSTEXPR QDate() : jd(nullJd()) {} Q_DECL_CONSTEXPR QDate() : jd(nullJd()) {}
QDate(int y, int m, int d); QDate(int y, int m, int d);
QDate(int y, int m, int d, QCalendar cal);
Q_DECL_CONSTEXPR bool isNull() const { return !isValid(); } Q_DECL_CONSTEXPR bool isNull() const { return !isValid(); }
Q_DECL_CONSTEXPR bool isValid() const { return jd >= minJd() && jd <= maxJd(); } Q_DECL_CONSTEXPR bool isValid() const { return jd >= minJd() && jd <= maxJd(); }
@ -82,6 +84,14 @@ public:
int daysInYear() const; int daysInYear() const;
int weekNumber(int *yearNum = nullptr) const; int weekNumber(int *yearNum = nullptr) const;
int year(QCalendar cal) const;
int month(QCalendar cal) const;
int day(QCalendar cal) const;
int dayOfWeek(QCalendar cal) const;
int dayOfYear(QCalendar cal) const;
int daysInMonth(QCalendar cal) const;
int daysInYear(QCalendar cal) const;
QDateTime startOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const; QDateTime startOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
QDateTime endOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const; QDateTime endOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
@ -103,8 +113,12 @@ public:
QString toString(Qt::DateFormat f = Qt::TextDate) const; QString toString(Qt::DateFormat f = Qt::TextDate) const;
#if QT_STRINGVIEW_LEVEL < 2 #if QT_STRINGVIEW_LEVEL < 2
QString toString(const QString &format) const; QString toString(const QString &format) const;
QString toString(const QString &format, QCalendar cal) const;
#endif #endif
QString toString(QStringView format) const; QString toString(QStringView format) const;
QString toString(Qt::DateFormat f, QCalendar cal) const;
QString toString(QStringView format, QCalendar cal) const;
#endif #endif
#if QT_DEPRECATED_SINCE(5,0) #if QT_DEPRECATED_SINCE(5,0)
QT_DEPRECATED_X("Use setDate() instead") inline bool setYMD(int y, int m, int d) QT_DEPRECATED_X("Use setDate() instead") inline bool setYMD(int y, int m, int d)
@ -112,6 +126,7 @@ public:
#endif #endif
bool setDate(int year, int month, int day); bool setDate(int year, int month, int day);
bool setDate(int year, int month, int day, QCalendar cal);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void getDate(int *year, int *month, int *day); // ### Qt 6: remove void getDate(int *year, int *month, int *day); // ### Qt 6: remove
@ -121,6 +136,8 @@ public:
Q_REQUIRED_RESULT QDate addDays(qint64 days) const; Q_REQUIRED_RESULT QDate addDays(qint64 days) const;
Q_REQUIRED_RESULT QDate addMonths(int months) const; Q_REQUIRED_RESULT QDate addMonths(int months) const;
Q_REQUIRED_RESULT QDate addYears(int years) const; Q_REQUIRED_RESULT QDate addYears(int years) const;
Q_REQUIRED_RESULT QDate addMonths(int months, QCalendar cal) const;
Q_REQUIRED_RESULT QDate addYears(int years, QCalendar cal) const;
qint64 daysTo(const QDate &) const; qint64 daysTo(const QDate &) const;
Q_DECL_CONSTEXPR bool operator==(const QDate &other) const { return jd == other.jd; } Q_DECL_CONSTEXPR bool operator==(const QDate &other) const { return jd == other.jd; }
@ -134,6 +151,7 @@ public:
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
static QDate fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); static QDate fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
static QDate fromString(const QString &s, const QString &format); static QDate fromString(const QString &s, const QString &format);
static QDate fromString(const QString &s, const QString &format, QCalendar cal);
#endif #endif
static bool isValid(int y, int m, int d); static bool isValid(int y, int m, int d);
static bool isLeapYear(int year); static bool isLeapYear(int year);
@ -353,6 +371,7 @@ public:
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
static QDateTime fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); static QDateTime fromString(const QString &s, Qt::DateFormat f = Qt::TextDate);
static QDateTime fromString(const QString &s, const QString &format); static QDateTime fromString(const QString &s, const QString &format);
static QDateTime fromString(const QString &s, const QString &format, QCalendar cal);
#endif #endif
#if QT_DEPRECATED_SINCE(5, 8) #if QT_DEPRECATED_SINCE(5, 8)

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -92,11 +92,11 @@ int QDateTimeParser::getDigit(const QDateTime &t, int index) const
case SecondSection: return t.time().second(); case SecondSection: return t.time().second();
case MSecSection: return t.time().msec(); case MSecSection: return t.time().msec();
case YearSection2Digits: case YearSection2Digits:
case YearSection: return t.date().year(); case YearSection: return t.date().year(calendar);
case MonthSection: return t.date().month(); case MonthSection: return t.date().month(calendar);
case DaySection: return t.date().day(); case DaySection: return t.date().day(calendar);
case DayOfWeekSectionShort: case DayOfWeekSectionShort:
case DayOfWeekSectionLong: return t.date().day(); case DayOfWeekSectionLong: return t.date().day(calendar);
case AmPmSection: return t.time().hour() > 11 ? 1 : 0; case AmPmSection: return t.time().hour() > 11 ? 1 : 0;
default: break; default: break;
@ -138,9 +138,9 @@ bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const
const QDate date = v.date(); const QDate date = v.date();
const QTime time = v.time(); const QTime time = v.time();
int year = date.year(); int year = date.year(calendar);
int month = date.month(); int month = date.month(calendar);
int day = date.day(); int day = date.day(calendar);
int hour = time.hour(); int hour = time.hour();
int minute = time.minute(); int minute = time.minute();
int second = time.second(); int second = time.second();
@ -184,13 +184,13 @@ bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const
if (!(node.type & DaySectionMask)) { if (!(node.type & DaySectionMask)) {
if (day < cachedDay) if (day < cachedDay)
day = cachedDay; day = cachedDay;
const int max = QDate(year, month, 1).daysInMonth(); const int max = calendar.daysInMonth(month, year);
if (day > max) { if (day > max) {
day = max; day = max;
} }
} }
const QDate newDate(year, month, day); const QDate newDate(year, month, day, calendar);
const QTime newTime(hour, minute, second, msec); const QTime newTime(hour, minute, second, msec);
if (!newDate.isValid() || !newTime.isValid()) if (!newDate.isValid() || !newTime.isValid())
return false; return false;
@ -231,10 +231,10 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const
// people from typing in a larger // people from typing in a larger
// number in count == 2 sections. // number in count == 2 sections.
// stepBy() will work on real years anyway // stepBy() will work on real years anyway
case MonthSection: return 12; case MonthSection: return calendar.maxMonthsInYear();
case DaySection: case DaySection:
case DayOfWeekSectionShort: case DayOfWeekSectionShort:
case DayOfWeekSectionLong: return cur.isValid() ? cur.date().daysInMonth() : 31; case DayOfWeekSectionLong: return cur.isValid() ? cur.date().daysInMonth(calendar) : calendar.maxDaysInMonth() ;
case AmPmSection: return 1; case AmPmSection: return 1;
default: break; default: break;
} }
@ -612,7 +612,7 @@ int QDateTimeParser::sectionSize(int sectionIndex) const
int QDateTimeParser::sectionMaxSize(Section s, int count) const int QDateTimeParser::sectionMaxSize(Section s, int count) const
{ {
#if QT_CONFIG(textdate) #if QT_CONFIG(textdate)
int mcount = 12; int mcount = calendar.maxMonthsInYear();
#endif #endif
switch (s) { switch (s) {
@ -654,7 +654,7 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const
const QLocale::FormatType format = count == 4 ? QLocale::LongFormat : QLocale::ShortFormat; const QLocale::FormatType format = count == 4 ? QLocale::LongFormat : QLocale::ShortFormat;
for (int i=1; i<=mcount; ++i) { for (int i=1; i<=mcount; ++i) {
const QString str = (s == MonthSection const QString str = (s == MonthSection
? l.monthName(i, format) ? calendar.monthName(l, i, QCalendar::Unspecified, format)
: l.dayName(i, format)); : l.dayName(i, format));
ret = qMax(str.size(), ret); ret = qMax(str.size(), ret);
} }
@ -787,9 +787,9 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
int num = 0, used = 0; int num = 0, used = 0;
if (sn.type == MonthSection) { if (sn.type == MonthSection) {
const QDate minDate = getMinimum().date(); const QDate minDate = getMinimum().date();
const int min = (currentValue.date().year() == minDate.year()) const int year = currentValue.date().year(calendar);
? minDate.month() : 1; const int min = (year == minDate.year(calendar)) ? minDate.month(calendar) : 1;
num = findMonth(sectiontext.toLower(), min, sectionIndex, &sectiontext, &used); num = findMonth(sectiontext.toLower(), min, sectionIndex, year, &sectiontext, &used);
} else { } else {
num = findDay(sectiontext.toLower(), 1, sectionIndex, &sectiontext, &used); num = findDay(sectiontext.toLower(), 1, sectionIndex, &sectiontext, &used);
} }
@ -893,6 +893,26 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
return result; return result;
} }
/*!
\internal
Returns a day-number, in the same month as \a rough and as close to \a rough's
day number as is valid, that \a calendar puts on the day of the week indicated
by \a weekDay.
*/
static int weekDayWithinMonth(const QCalendar &calendar, const QDate &rough, int weekDay)
{
// TODO: can we adapt this to cope gracefully with intercallary days (day of
// week > 7) without making it slower for more widely-used calendars ?
int day = rough.day(calendar) + weekDay - calendar.dayOfWeek(rough);
if (day <= 0)
return day + 7;
if (day > rough.daysInMonth(calendar))
return day - 7;
return day;
}
/*! /*!
\internal \internal
@ -901,11 +921,11 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex,
when on valid date is consistent with the data. when on valid date is consistent with the data.
*/ */
static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digits, static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calendar,
int month, int day, int dayofweek) int year, int year2digits, int month, int day, int dayofweek)
{ {
QDate actual(year, month, day); QDate actual(year, month, day, calendar);
if (actual.isValid() && year % 100 == year2digits && actual.dayOfWeek() == dayofweek) if (actual.isValid() && year % 100 == year2digits && calendar.dayOfWeek(actual) == dayofweek)
return actual; // The obvious candidate is fine :-) return actual; // The obvious candidate is fine :-)
if (dayofweek < 1 || dayofweek > 7) // Invalid: ignore if (dayofweek < 1 || dayofweek > 7) // Invalid: ignore
@ -931,18 +951,18 @@ static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digi
known &= ~QDateTimeParser::MonthSection; known &= ~QDateTimeParser::MonthSection;
} }
QDate first(year, month, 1); QDate first(year, month, 1, calendar);
int last = known & QDateTimeParser::YearSection && known & QDateTimeParser::MonthSection int last = known & QDateTimeParser::YearSection && known & QDateTimeParser::MonthSection
? first.daysInMonth() : 0; ? first.daysInMonth(calendar) : 0;
// If we also know day-of-week, tweak last to the last in the month that matches it: // If we also know day-of-week, tweak last to the last in the month that matches it:
if (last && known & QDateTimeParser::DayOfWeekSectionMask) { if (last && known & QDateTimeParser::DayOfWeekSectionMask) {
int diff = (dayofweek - first.dayOfWeek() - last) % 7; int diff = (dayofweek - calendar.dayOfWeek(first) - last) % 7;
Q_ASSERT(diff <= 0); // C++11 specifies (-ve) % (+ve) to be <= 0. Q_ASSERT(diff <= 0); // C++11 specifies (-ve) % (+ve) to be <= 0.
last += diff; last += diff;
} }
if (day < 1) { if (day < 1) {
if (known & QDateTimeParser::DayOfWeekSectionMask && last) { if (known & QDateTimeParser::DayOfWeekSectionMask && last) {
day = 1 + dayofweek - first.dayOfWeek(); day = 1 + dayofweek - calendar.dayOfWeek(first);
if (day < 1) if (day < 1)
day += 7; day += 7;
} else { } else {
@ -956,12 +976,12 @@ static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digi
day = last; day = last;
} }
actual = QDate(year, month, day); actual = QDate(year, month, day, calendar);
if (!actual.isValid() // We can't do better than we have, in this case if (!actual.isValid() // We can't do better than we have, in this case
|| (known & QDateTimeParser::DaySection || (known & QDateTimeParser::DaySection
&& known & QDateTimeParser::MonthSection && known & QDateTimeParser::MonthSection
&& known & QDateTimeParser::YearSection) // ditto && known & QDateTimeParser::YearSection) // ditto
|| actual.dayOfWeek() == dayofweek // Good enough, use it. || calendar.dayOfWeek(actual) == dayofweek // Good enough, use it.
|| (known & QDateTimeParser::DayOfWeekSectionMask) == 0) { // No contradiction, use it. || (known & QDateTimeParser::DayOfWeekSectionMask) == 0) { // No contradiction, use it.
return actual; return actual;
} }
@ -976,12 +996,8 @@ static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digi
if ((known & QDateTimeParser::DaySection) == 0) { if ((known & QDateTimeParser::DaySection) == 0) {
// Relatively easy to fix. // Relatively easy to fix.
day += dayofweek - actual.dayOfWeek(); day = weekDayWithinMonth(calendar, actual, dayofweek);
if (day < 1) actual = QDate(year, month, day, calendar);
day += 7;
else if (day > actual.daysInMonth())
day -= 7;
actual = QDate(year, month, day);
return actual; return actual;
} }
@ -993,18 +1009,18 @@ static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digi
*/ */
for (int m = 1; m < 12; m++) { for (int m = 1; m < 12; m++) {
if (m < month) { if (m < month) {
actual = QDate(year, month - m, day); actual = QDate(year, month - m, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
} }
if (m + month <= 12) { if (m + month <= 12) {
actual = QDate(year, month + m, day); actual = QDate(year, month + m, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
} }
} }
// Should only get here in corner cases; e.g. day == 31 // Should only get here in corner cases; e.g. day == 31
actual = QDate(year, month, day); // Restore from trial values. actual = QDate(year, month, day, calendar); // Restore from trial values.
} }
if ((known & QDateTimeParser::YearSection) == 0) { if ((known & QDateTimeParser::YearSection) == 0) {
@ -1017,24 +1033,24 @@ static QDate actualDate(QDateTimeParser::Sections known, int year, int year2digi
is '97, it makes sense to consider 1997. If either adjacent is '97, it makes sense to consider 1997. If either adjacent
century does work, the other won't. century does work, the other won't.
*/ */
actual = QDate(year + 100, month, day); actual = QDate(year + 100, month, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
actual = QDate(year - 100, month, day); actual = QDate(year - 100, month, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
} else { } else {
// Offset by 7 is usually enough, but rare cases may need more: // Offset by 7 is usually enough, but rare cases may need more:
for (int y = 1; y < 12; y++) { for (int y = 1; y < 12; y++) {
actual = QDate(year - y, month, day); actual = QDate(year - y, month, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
actual = QDate(year + y, month, day); actual = QDate(year + y, month, day, calendar);
if (actual.dayOfWeek() == dayofweek) if (calendar.dayOfWeek(actual) == dayofweek)
return actual; return actual;
} }
} }
actual = QDate(year, month, day); // Restore from trial values. actual = QDate(year, month, day, calendar); // Restore from trial values.
} }
return actual; // It'll just have to do :-( return actual; // It'll just have to do :-(
@ -1097,7 +1113,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
int minute = defaultTime.minute(); int minute = defaultTime.minute();
int second = defaultTime.second(); int second = defaultTime.second();
int msec = defaultTime.msec(); int msec = defaultTime.msec();
int dayofweek = defaultDate.dayOfWeek(); int dayofweek = calendar.dayOfWeek(defaultDate);
Qt::TimeSpec tspec = defaultValue.timeSpec(); Qt::TimeSpec tspec = defaultValue.timeSpec();
int zoneOffset = 0; // In seconds; local - UTC int zoneOffset = 0; // In seconds; local - UTC
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
@ -1138,7 +1154,8 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
ParsedSection sect; ParsedSection sect;
{ {
const QDate date = actualDate(isSet, year, year2digits, month, day, dayofweek); const QDate date = actualDate(isSet, calendar, year, year2digits,
month, day, dayofweek);
const QTime time = actualTime(isSet, hour, hour12, ampm, minute, second, msec); const QTime time = actualTime(isSet, hour, hour12, ampm, minute, second, msec);
sect = parseSection( sect = parseSection(
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
@ -1248,22 +1265,17 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
} }
} }
const QDate date(year, month, day); const QDate date(year, month, day, calendar);
const int diff = dayofweek - date.dayOfWeek(); if (dayofweek != calendar.dayOfWeek(date)
if (diff != 0 && state == Acceptable && isSet & DayOfWeekSectionMask) { && state == Acceptable && isSet & DayOfWeekSectionMask) {
if (isSet & DaySection) if (isSet & DaySection)
conflicts = true; conflicts = true;
const SectionNode &sn = sectionNode(currentSectionIndex); const SectionNode &sn = sectionNode(currentSectionIndex);
if (sn.type & DayOfWeekSectionMask || currentSectionIndex == -1) { if (sn.type & DayOfWeekSectionMask || currentSectionIndex == -1) {
// dayofweek should be preferred // dayofweek should be preferred
day += diff; day = weekDayWithinMonth(calendar, date, dayofweek);
if (day <= 0) {
day += 7;
} else if (day > date.daysInMonth()) {
day -= 7;
}
QDTPDEBUG << year << month << day << dayofweek QDTPDEBUG << year << month << day << dayofweek
<< diff << QDate(year, month, day).dayOfWeek(); << calendar.dayOfWeek(QDate(year, month, day, calendar));
} }
} }
@ -1275,20 +1287,18 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
needfixday = true; needfixday = true;
} }
if (!QDate::isValid(year, month, day)) { if (!calendar.isDateValid(year, month, day)) {
if (day < 32) { if (day <= calendar.maxDaysInMonth())
cachedDay = day; cachedDay = day;
} if (day > calendar.minDaysInMonth() && calendar.isDateValid(year, month, 1))
if (day > 28 && QDate::isValid(year, month, 1)) {
needfixday = true; needfixday = true;
} }
}
if (needfixday) { if (needfixday) {
if (context == FromString) { if (context == FromString) {
return StateNode(); return StateNode();
} }
if (state == Acceptable && fixday) { if (state == Acceptable && fixday) {
day = qMin<int>(day, QDate(year, month, 1).daysInMonth()); day = qMin<int>(day, calendar.daysInMonth(month, year));
const QLocale loc = locale(); const QLocale loc = locale();
for (int i=0; i<sectionNodesCount; ++i) { for (int i=0; i<sectionNodesCount; ++i) {
@ -1296,7 +1306,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
if (sn.type & DaySection) { if (sn.type & DaySection) {
input->replace(sectionPos(sn), sectionSize(i), loc.toString(day)); input->replace(sectionPos(sn), sectionSize(i), loc.toString(day));
} else if (sn.type & DayOfWeekSectionMask) { } else if (sn.type & DayOfWeekSectionMask) {
const int dayOfWeek = QDate(year, month, day).dayOfWeek(); const int dayOfWeek = calendar.dayOfWeek(QDate(year, month, day, calendar));
const QLocale::FormatType dayFormat = const QLocale::FormatType dayFormat =
(sn.type == DayOfWeekSectionShort (sn.type == DayOfWeekSectionShort
? QLocale::ShortFormat : QLocale::LongFormat); ? QLocale::ShortFormat : QLocale::LongFormat);
@ -1333,13 +1343,12 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
conflicts = true; conflicts = true;
} }
} }
} }
QDTPDEBUG << year << month << day << hour << minute << second << msec; QDTPDEBUG << year << month << day << hour << minute << second << msec;
Q_ASSERT(state != Invalid); Q_ASSERT(state != Invalid);
const QDate date(year, month, day); const QDate date(year, month, day, calendar);
const QTime time(hour, minute, second, msec); const QTime time(hour, minute, second, msec);
const QDateTime when = const QDateTime when =
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
@ -1427,10 +1436,11 @@ QDateTimeParser::parse(QString input, int position, const QDateTime &defaultValu
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case MonthSection: case MonthSection:
if (sn.count >= 3) { if (sn.count >= 3) {
const int finalMonth = scan.value.date().month(); const QDate when = scan.value.date();
const int finalMonth = when.month(calendar);
int tmp = finalMonth; int tmp = finalMonth;
// I know the first possible month makes the date too early // I know the first possible month makes the date too early
while ((tmp = findMonth(t, tmp + 1, i)) != -1) { while ((tmp = findMonth(t, tmp + 1, i, when.year(calendar))) != -1) {
const QDateTime copy(scan.value.addMonths(tmp - finalMonth)); const QDateTime copy(scan.value.addMonths(tmp - finalMonth));
if (copy >= minimum && copy <= maximum) if (copy >= minimum && copy <= maximum)
break; // break out of while break; // break out of while
@ -1566,7 +1576,7 @@ static int findTextEntry(const QString &text, const QVector<QString> &entries, Q
*/ */
int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex, int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex,
QString *usedMonth, int *used) const int year, QString *usedMonth, int *used) const
{ {
const SectionNode &sn = sectionNode(sectionIndex); const SectionNode &sn = sectionNode(sectionIndex);
if (sn.type != MonthSection) { if (sn.type != MonthSection) {
@ -1579,7 +1589,7 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI
QVector<QString> monthNames; QVector<QString> monthNames;
monthNames.reserve(13 - startMonth); monthNames.reserve(13 - startMonth);
for (int month = startMonth; month <= 12; ++month) for (int month = startMonth; month <= 12; ++month)
monthNames.append(l.monthName(month, type)); monthNames.append(calendar.monthName(l, month, year, type));
const int index = findTextEntry(str1, monthNames, usedMonth, used); const int index = findTextEntry(str1, monthNames, usedMonth, used);
return index < 0 ? index : index + startMonth; return index < 0 ? index : index + startMonth;
@ -1877,7 +1887,7 @@ bool QDateTimeParser::potentialValue(const QStringRef &str, int min, int max, in
int val = (int)locale().toUInt(str); int val = (int)locale().toUInt(str);
const SectionNode &sn = sectionNode(index); const SectionNode &sn = sectionNode(index);
if (sn.type == YearSection2Digits) { if (sn.type == YearSection2Digits) {
const int year = currentValue.date().year(); const int year = currentValue.date().year(calendar);
val += year - (year % 100); val += year - (year % 100);
} }
if (val >= min && val <= max && str.size() == size) { if (val >= min && val <= max && str.size() == size) {
@ -2047,4 +2057,13 @@ bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::S
return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count); return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count);
} }
/*!
Sets \a cal as the calendar to use. The default is Gregorian.
*/
void QDateTimeParser::setCalendar(const QCalendar &cal)
{
calendar = cal;
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -57,6 +57,7 @@
#include "QtCore/qdatetime.h" #include "QtCore/qdatetime.h"
#include "QtCore/qstringlist.h" #include "QtCore/qstringlist.h"
#include "QtCore/qlocale.h" #include "QtCore/qlocale.h"
#include "QtCore/qcalendar.h"
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
# include "QtCore/qvariant.h" # include "QtCore/qvariant.h"
#endif #endif
@ -82,9 +83,9 @@ public:
FromString, FromString,
DateTimeEdit DateTimeEdit
}; };
QDateTimeParser(QVariant::Type t, Context ctx) QDateTimeParser(QVariant::Type t, Context ctx, const QCalendar &cal = QCalendar())
: currentSectionIndex(-1), display(nullptr), cachedDay(-1), parserType(t), : currentSectionIndex(-1), display(nullptr), cachedDay(-1), parserType(t),
fixday(false), spec(Qt::LocalTime), context(ctx) fixday(false), spec(Qt::LocalTime), context(ctx), calendar(cal)
{ {
defaultLocale = QLocale::system(); defaultLocale = QLocale::system();
first.type = FirstSection; first.type = FirstSection;
@ -195,6 +196,7 @@ public:
void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; } void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; }
virtual QString displayText() const { return text; } virtual QString displayText() const { return text; }
void setCalendar(const QCalendar &calendar);
private: private:
int sectionMaxSize(Section s, int count) const; int sectionMaxSize(Section s, int count) const;
@ -215,7 +217,7 @@ private:
ParsedSection parseSection(const QDateTime &currentValue, int sectionIndex, ParsedSection parseSection(const QDateTime &currentValue, int sectionIndex,
int offset, QString *text) const; int offset, QString *text) const;
int findMonth(const QString &str1, int monthstart, int sectionIndex, int findMonth(const QString &str1, int monthstart, int sectionIndex,
QString *monthName = nullptr, int *used = nullptr) const; int year, QString *monthName = nullptr, int *used = nullptr) const;
int findDay(const QString &str1, int intDaystart, int sectionIndex, int findDay(const QString &str1, int intDaystart, int sectionIndex,
QString *dayName = nullptr, int *used = nullptr) const; QString *dayName = nullptr, int *used = nullptr) const;
ParsedSection findTimeZone(QStringRef str, const QDateTime &when, ParsedSection findTimeZone(QStringRef str, const QDateTime &when,
@ -297,6 +299,7 @@ protected: // for the benefit of QDateTimeEditPrivate
bool fixday; bool fixday;
Qt::TimeSpec spec; // spec if used by QDateTimeEdit Qt::TimeSpec spec; // spec if used by QDateTimeEdit
Context context; Context context;
QCalendar calendar;
}; };
Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QDateTimeParser::SectionNode, Q_PRIMITIVE_TYPE);

View File

@ -0,0 +1,138 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgregoriancalendar_p.h"
#include "qcalendarmath_p.h"
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
using namespace QRoundingDown;
/*!
\since 5.14
\class QGregorianCalendar
\inmodule QtCore
\brief The QGregorianCalendar class implements the Gregorian calendar.
\section1 The Gregorian Calendar
The Gregorian calendar is a refinement of the earlier Julian calendar,
itself a late form of the Roman calendar. It is widely used.
\sa QRomanCalendar, QCalendarBackend, QCalendar
*/
QGregorianCalendar::QGregorianCalendar()
: QRomanCalendar(QStringLiteral("Gregorian"), QCalendar::System::Gregorian)
{
registerAlias(QStringLiteral("gregory"));
}
QString QGregorianCalendar::name() const
{
return QStringLiteral("Gregorian");
}
QCalendar::System QGregorianCalendar::calendarSystem() const
{
return QCalendar::System::Gregorian;
}
bool QGregorianCalendar::isLeapYear(int year) const
{
if (year == QCalendar::Unspecified)
return false;
// No year 0 in Gregorian calendar, so -1, -5, -9 etc are leap years
if (year < 1)
++year;
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
bool QGregorianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
{
Q_ASSERT(jd);
if (!isDateValid(year, month, day))
return false;
if (year < 0)
++year;
/*
* Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
* This formula is correct for all julian days, when using mathematical integer
* division (round to negative infinity), not c++11 integer division (round to zero)
*/
int a = month < 3 ? 1 : 0;
qint64 y = qint64(year) + 4800 - a;
int m = month + 12 * a - 3;
*jd = day + qDiv(153 * m + 2, 5) - 32045
+ 365 * y + qDiv(y, 4) - qDiv(y, 100) + qDiv(y, 400);
return true;
}
QCalendar::YearMonthDay QGregorianCalendar::julianDayToDate(qint64 jd) const
{
/*
* Math from The Calendar FAQ at http://www.tondering.dk/claus/cal/julperiod.php
* This formula is correct for all julian days, when using mathematical integer
* division (round to negative infinity), not c++11 integer division (round to zero)
*/
qint64 a = jd + 32044;
qint64 b = qDiv(4 * a + 3, 146097);
int c = a - qDiv(146097 * b, 4);
int d = qDiv(4 * c + 3, 1461);
int e = c - qDiv(1461 * d, 4);
int m = qDiv(5 * e + 2, 153);
int y = 100 * b + d - 4800 + qDiv(m, 10);
// Adjust for no year 0
int year = y > 0 ? y : y - 1;
int month = m + 3 - 12 * qDiv(m, 10);
int day = e - qDiv(153 * m + 2, 5) + 1;
return QCalendar::YearMonthDay(year, month, day);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,82 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGREGORIAN_CALENDAR_P_H
#define QGREGORIAN_CALENDAR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of calendar implementations. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qromancalendar_p.h"
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QGregorianCalendar : public QRomanCalendar
{
// TODO: provide static methods, called by the overrides, that can be called
// directly by QDate to optimize various parts.
public:
QGregorianCalendar();
// CAlendar properties:
QString name() const override;
QCalendar::System calendarSystem() const override;
// Date queries:
bool isLeapYear(int year) const override;
// Julian Day conversions:
bool dateToJulianDay(int year, int month, int day, qint64 *jd) const override;
QCalendar::YearMonthDay julianDayToDate(qint64 jd) const override;
// Names of months (implemented in qlocale.cpp):
QString monthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const override;
QString standaloneMonthName(const QLocale &locale, int month, int year,
QLocale::FormatType format) const override;
};
QT_END_NAMESPACE
#endif // QGREGORIAN_CALENDAR_P_H

View File

@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qglobal.h"
#include "qromancalendar_p.h"
#include "qromancalendar_data_p.h"
QT_BEGIN_NAMESPACE
/*!
\since 5.14
\class QRomanCalendar
\inmodule QtCore
\brief The QRomanCalendar class is a shared base for calendars based on the
ancient Roman calendar.
\section1
Calendars based on the ancient Roman calendar share the names of months, whose
lengths depend in a common way on whether the year is a leap year. They differ
in how they determine which years are leap years.
\sa QGregorianCalendar
*/
int QRomanCalendar::daysInMonth(int month, int year) const
{
if (!year || month < 1 || month > 12)
return 0;
if (month == 2)
return isLeapYear(year) ? 29 : 28;
// Long if odd up to July = 7, or if even from 8 = August onwards:
return 30 | ((month & 1) ^ (month >> 3));
}
int QRomanCalendar::minDaysInMonth() const
{
return 28;
}
bool QRomanCalendar::isLunar() const
{
return false;
}
bool QRomanCalendar::isLuniSolar() const
{
return false;
}
bool QRomanCalendar::isSolar() const
{
return true;
}
const QCalendarLocale *QRomanCalendar::localeMonthIndexData() const
{
return locale_data;
}
const ushort *QRomanCalendar::localeMonthData() const
{
return months_data;
}
QT_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QROMAN_CALENDAR_P_H
#define QROMAN_CALENDAR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of calendar implementations. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qcalendarbackend_p.h"
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QRomanCalendar : public QCalendarBackend
{
public:
// date queries:
int daysInMonth(int month, int year = QCalendar::Unspecified) const override;
int minDaysInMonth() const override;
// properties of the calendar
bool isLunar() const override;
bool isLuniSolar() const override;
bool isSolar() const override;
protected:
// locale support:
const QCalendarLocale *localeMonthIndexData() const override;
const ushort *localeMonthData() const override;
// (The INTEGRITY compiler got upset at: using QCalendarBackend:QCalendarBackend;)
QRomanCalendar(const QString &name, QCalendar::System id = QCalendar::System::User)
: QCalendarBackend(name, id) {}
};
QT_END_NAMESPACE
#endif // QROMAN_CALENDAR_P_H

View File

@ -1,10 +1,20 @@
# Qt time / date / zone / calendar module # Qt time / date / zone / calendar module
HEADERS += \ HEADERS += \
time/qcalendar.h \
time/qcalendarbackend_p.h \
time/qcalendarmath_p.h \
time/qdatetime.h \ time/qdatetime.h \
time/qdatetime_p.h time/qdatetime_p.h \
time/qgregoriancalendar_p.h \
time/qromancalendar_p.h \
time/qromancalendar_data_p.h
SOURCES += time/qdatetime.cpp SOURCES += \
time/qdatetime.cpp \
time/qcalendar.cpp \
time/qgregoriancalendar.cpp \
time/qromancalendar.cpp
qtConfig(timezone) { qtConfig(timezone) {
HEADERS += \ HEADERS += \

View File

@ -85,7 +85,10 @@ SOURCES += \
../../corelib/text/qstringlist.cpp \ ../../corelib/text/qstringlist.cpp \
../../corelib/text/qstringview.cpp \ ../../corelib/text/qstringview.cpp \
../../corelib/text/qvsnprintf.cpp \ ../../corelib/text/qvsnprintf.cpp \
../../corelib/time/qcalendar.cpp \
../../corelib/time/qdatetime.cpp \ ../../corelib/time/qdatetime.cpp \
../../corelib/time/qgregoriancalendar.cpp \
../../corelib/time/qromancalendar.cpp \
../../corelib/tools/qarraydata.cpp \ ../../corelib/tools/qarraydata.cpp \
../../corelib/tools/qbitarray.cpp \ ../../corelib/tools/qbitarray.cpp \
../../corelib/tools/qcommandlineparser.cpp \ ../../corelib/tools/qcommandlineparser.cpp \

View File

@ -0,0 +1,5 @@
CONFIG += testcase
TARGET = tst_qcalendar
QT = core testlib
SOURCES = \
tst_qcalendar.cpp

View File

@ -0,0 +1,219 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QCalendar>
Q_DECLARE_METATYPE(QCalendar::System)
class tst_QCalendar : public QObject
{
Q_OBJECT
private:
void checkYear(const QCalendar &cal, int year, bool normal=false);
private slots:
void basic_data();
void basic();
void nameCase();
void specific_data();
void specific();
void daily_data() { basic_data(); }
void daily();
};
// Support for basic():
void tst_QCalendar::checkYear(const QCalendar &cal, int year, bool normal)
{
const int moons = cal.monthsInYear(year);
// Months are numbered from 1 to moons:
QVERIFY(moons > 0);
QVERIFY(!cal.isDateValid(year, moons + 1, 1));
QVERIFY(!cal.isDateValid(year, 0, 1));
QVERIFY(moons <= cal.maxMonthsInYear());
const int days = cal.daysInYear(year);
QVERIFY(days > 0);
int sum = 0;
const int longest = cal.maxDaysInMonth();
for (int i = moons; i > 0; i--) {
const int last = cal.daysInMonth(i, year);
sum += last;
// Valid month has some days and no more than max:
QVERIFY(last > 0);
QVERIFY(last <= longest);
// Days are numbered from 1 to last:
QVERIFY(cal.isDateValid(year, i, 1));
QVERIFY(cal.isDateValid(year, i, last));
QVERIFY(!cal.isDateValid(year, i, 0));
QVERIFY(!cal.isDateValid(year, i, last + 1));
if (normal) // Unspecified year gets same daysInMonth():
QCOMPARE(cal.daysInMonth(i), last);
}
// Months add up to the whole year:
QCOMPARE(sum, days);
}
#define CHECKYEAR(cal, year) checkYear(cal, year); \
if (QTest::currentTestFailed()) \
return
#define NORMALYEAR(cal, year) checkYear(cal, year, true); \
if (QTest::currentTestFailed()) \
return
void tst_QCalendar::basic_data()
{
QTest::addColumn<QCalendar::System>("system");
QMetaEnum e = QCalendar::staticMetaObject.enumerator(0);
Q_ASSERT(qstrcmp(e.name(), "System") == 0);
for (int i = 0; i <= int(QCalendar::System::Last); ++i) {
// There may be gaps in the enum's numbering; and Last is a duplicate:
if (e.value(i) != -1 && qstrcmp(e.key(i), "Last"))
QTest::newRow(e.key(i)) << QCalendar::System(e.value(i));
}
}
void tst_QCalendar::basic()
{
QFETCH(QCalendar::System, system);
QCalendar cal(system);
QVERIFY(cal.isValid());
QCOMPARE(QCalendar(cal.name()).isGregorian(), cal.isGregorian());
QCOMPARE(QCalendar(cal.name()).name(), cal.name());
if (cal.hasYearZero()) {
CHECKYEAR(cal, 0);
} else {
QCOMPARE(cal.monthsInYear(0), 0);
QCOMPARE(cal.daysInYear(0), 0);
QVERIFY(!cal.isDateValid(0, 1, 1));
}
if (cal.isProleptic()) {
CHECKYEAR(cal, -1);
} else {
QCOMPARE(cal.monthsInYear(-1), 0);
QCOMPARE(cal.daysInYear(-1), 0);
QVERIFY(!cal.isDateValid(-1, 1, 1));
}
// Look for a leap year in the last decade.
int year = QDate::currentDate().year(cal);
for (int i = 10; i > 0 && !cal.isLeapYear(year); --i)
--year;
if (cal.isLeapYear(year)) {
// ... and a non-leap year within a decade before it.
int leap = year--;
for (int i = 10; i > 0 && cal.isLeapYear(year); --i)
year--;
if (!cal.isLeapYear(year))
QVERIFY(cal.daysInYear(year) < cal.daysInYear(leap));
CHECKYEAR(cal, leap);
}
// Either year is non-leap or we have a decade of leap years together;
// expect daysInMonth() to treat year the same as unspecified.
NORMALYEAR(cal, year);
}
void tst_QCalendar::nameCase()
{
QVERIFY(QCalendar::availableCalendars().contains(QStringLiteral("Gregorian")));
}
void tst_QCalendar::specific_data()
{
QTest::addColumn<QCalendar::System>("system");
// Date in that system:
QTest::addColumn<int>("sysyear");
QTest::addColumn<int>("sysmonth");
QTest::addColumn<int>("sysday");
// Gregorian equivalent:
QTest::addColumn<int>("gregyear");
QTest::addColumn<int>("gregmonth");
QTest::addColumn<int>("gregday");
#define ADDROW(cal, year, month, day, gy, gm, gd) \
QTest::newRow(#cal) << QCalendar::System::cal << year << month << day << gy << gm << gd
ADDROW(Gregorian, 1970, 1, 1, 1970, 1, 1);
#undef ADDROW
}
void tst_QCalendar::specific()
{
QFETCH(QCalendar::System, system);
QFETCH(int, sysyear);
QFETCH(int, sysmonth);
QFETCH(int, sysday);
QFETCH(int, gregyear);
QFETCH(int, gregmonth);
QFETCH(int, gregday);
const QCalendar cal(system);
const QDate date(sysyear, sysmonth, sysday, cal), gregory(gregyear, gregmonth, gregday);
QCOMPARE(date, gregory);
QCOMPARE(gregory.year(cal), sysyear);
QCOMPARE(gregory.month(cal), sysmonth);
QCOMPARE(gregory.day(cal), sysday);
QCOMPARE(date.year(), gregyear);
QCOMPARE(date.month(), gregmonth);
QCOMPARE(date.day(), gregday);
}
void tst_QCalendar::daily()
{
QFETCH(QCalendar::System, system);
QCalendar calendar(system);
const quint64 startJDN = 0, endJDN = 2488070;
// Iterate from -4713-01-01 (Julian calendar) to 2100-01-01
for (quint64 expect = startJDN; expect <= endJDN; ++expect)
{
QDate date = QDate::fromJulianDay(expect);
auto parts = calendar.partsFromDate(date);
if (!parts.isValid())
continue;
const int year = date.year(calendar);
QCOMPARE(year, parts.year);
const int month = date.month(calendar);
QCOMPARE(month, parts.month);
const int day = date.day(calendar);
QCOMPARE(day, parts.day);
const quint64 actual = QDate(year, month, day, calendar).toJulianDay();
QCOMPARE(actual, expect);
}
}
QTEST_APPLESS_MAIN(tst_QCalendar)
#include "tst_qcalendar.moc"

View File

@ -1,5 +1,6 @@
TEMPLATE = subdirs TEMPLATE = subdirs
SUBDIRS = \ SUBDIRS = \
qcalendar \
qdate \ qdate \
qdatetime \ qdatetime \
qtime \ qtime \

View File

@ -1,7 +1,8 @@
#!/usr/bin/env python2 #!/usr/bin/env python2
# coding=utf8
############################################################################# #############################################################################
## ##
## Copyright (C) 2017 The Qt Company Ltd. ## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/ ## Contact: https://www.qt.io/licensing/
## ##
## This file is part of the test suite of the Qt Toolkit. ## This file is part of the test suite of the Qt Toolkit.
@ -62,6 +63,8 @@ from xpathlite import DraftResolution, findAlias, findEntry, findTagsInFile
from dateconverter import convert_date from dateconverter import convert_date
from localexml import Locale from localexml import Locale
# TODO: make calendars a command-line option
calendars = ['gregorian'] # 'persian', 'islamic', 'hebrew'
findEntryInFile = xpathlite._findEntryInFile findEntryInFile = xpathlite._findEntryInFile
def wrappedwarn(prefix, tokens): def wrappedwarn(prefix, tokens):
return sys.stderr.write( return sys.stderr.write(
@ -395,12 +398,12 @@ def _generateLocaleInfo(path, language_code, script_code, country_code, variant_
('narrow', 'format', 'narrow'), ('narrow', 'format', 'narrow'),
) )
# Month data: # Month names for 12-month calendars:
for cal in ('gregorian',): # We shall want to add to this for cal in calendars:
stem = 'dates/calendars/calendar[' + cal + ']/months/' stem = 'dates/calendars/calendar[' + cal + ']/months/'
for (key, mode, size) in namings: for (key, mode, size) in namings:
prop = 'monthContext[' + mode + ']/monthWidth[' + size + ']/' prop = 'monthContext[' + mode + ']/monthWidth[' + size + ']/'
result[key + 'Months'] = ';'.join( result[key + 'Months_' + cal] = ';'.join(
findEntry(path, stem + prop + "month[%d]" % i) findEntry(path, stem + prop + "month[%d]" % i)
for i in range(1, 13)) + ';' for i in range(1, 13)) + ';'
@ -686,9 +689,9 @@ if skips:
wrappedwarn('skipping likelySubtags (for unknown language codes): ', skips) wrappedwarn('skipping likelySubtags (for unknown language codes): ', skips)
print " <localeList>" print " <localeList>"
Locale.C().toXml() Locale.C(calendars).toXml(calendars)
for key in locale_keys: for key in locale_keys:
locale_database[key].toXml() locale_database[key].toXml(calendars)
print " </localeList>" print " </localeList>"
print "</localeDatabase>" print "</localeDatabase>"

View File

@ -1,6 +1,7 @@
# coding=utf8
############################################################################# #############################################################################
## ##
## Copyright (C) 2017 The Qt Company Ltd. ## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/ ## Contact: https://www.qt.io/licensing/
## ##
## This file is part of the test suite of the Qt Toolkit. ## This file is part of the test suite of the Qt Toolkit.
@ -113,12 +114,11 @@ def convertFormat(format):
return result return result
class Locale: class Locale:
# Tool used during class body (see del below), not method: @staticmethod
def propsMonthDay(lengths=('long', 'short', 'narrow'), scale=('months', 'days')): def propsMonthDay(scale, lengths=('long', 'short', 'narrow')):
for L in lengths: for L in lengths:
for S in scale: yield camelCase((L, scale))
yield camelCase((L, S)) yield camelCase(('standalone', L, scale))
yield camelCase(('standalone', L, S))
# Expected to be numbers, read with int(): # Expected to be numbers, read with int():
__asint = ("decimal", "group", "zero", __asint = ("decimal", "group", "zero",
@ -137,15 +137,13 @@ class Locale:
"listPatternPartEnd", "listPatternPartTwo", "am", "pm", "listPatternPartEnd", "listPatternPartTwo", "am", "pm",
'byte_unit', 'byte_si_quantified', 'byte_iec_quantified', 'byte_unit', 'byte_si_quantified', 'byte_iec_quantified',
"currencyIsoCode", "currencySymbol", "currencyDisplayName", "currencyIsoCode", "currencySymbol", "currencyDisplayName",
"currencyFormat", "currencyNegativeFormat" "currencyFormat", "currencyNegativeFormat")
) + tuple(propsMonthDay())
del propsMonthDay
# Day-of-Week numbering used by Qt: # Day-of-Week numbering used by Qt:
__qDoW = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7} __qDoW = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7}
@classmethod @classmethod
def fromXmlData(cls, lookup): def fromXmlData(cls, lookup, calendars=('gregorian',)):
"""Constructor from the contents of XML elements. """Constructor from the contents of XML elements.
Single parameter, lookup, is called with the names of XML Single parameter, lookup, is called with the names of XML
@ -170,12 +168,15 @@ class Locale:
for k in cls.__asfmt: for k in cls.__asfmt:
data[k] = convertFormat(lookup(k)) data[k] = convertFormat(lookup(k))
for k in cls.__astxt: for k in cls.__astxt + tuple(cls.propsMonthDay('days')):
data[k] = lookup(k) data[k] = lookup(k)
for k in cls.propsMonthDay('months'):
data[k] = dict((cal, lookup('_'.join((k, cal)))) for cal in calendars)
return cls(data) return cls(data)
def toXml(self, indent=' ', tab=' '): def toXml(self, calendars=('gregorian',), indent=' ', tab=' '):
print indent + '<locale>' print indent + '<locale>'
inner = indent + tab inner = indent + tab
get = lambda k: getattr(self, k) get = lambda k: getattr(self, k)
@ -199,13 +200,14 @@ class Locale:
'weekendStart', 'weekendEnd', 'weekendStart', 'weekendEnd',
'longDateFormat', 'shortDateFormat', 'longDateFormat', 'shortDateFormat',
'longTimeFormat', 'shortTimeFormat', 'longTimeFormat', 'shortTimeFormat',
'standaloneLongMonths', 'standaloneShortMonths',
'standaloneNarrowMonths',
'longMonths', 'shortMonths', 'narrowMonths',
'longDays', 'shortDays', 'narrowDays', 'longDays', 'shortDays', 'narrowDays',
'standaloneLongDays', 'standaloneShortDays', 'standaloneNarrowDays', 'standaloneLongDays', 'standaloneShortDays', 'standaloneNarrowDays',
'currencyIsoCode', 'currencySymbol', 'currencyDisplayName', 'currencyIsoCode', 'currencySymbol', 'currencyDisplayName',
'currencyFormat', 'currencyNegativeFormat'): 'currencyFormat', 'currencyNegativeFormat'
) + tuple(self.propsMonthDay('days')) + tuple(
'_'.join((k, cal))
for k in self.propsMonthDay('months')
for cal in calendars):
ent = camelCase(key.split('_')) if key.endswith('_endonym') else key ent = camelCase(key.split('_')) if key.endswith('_endonym') else key
print inner + "<%s>%s</%s>" % (ent, escape(get(key)).encode('utf-8'), ent) print inner + "<%s>%s</%s>" % (ent, escape(get(key)).encode('utf-8'), ent)
@ -218,16 +220,50 @@ class Locale:
if data: self.__dict__.update(data) if data: self.__dict__.update(data)
if kw: self.__dict__.update(kw) if kw: self.__dict__.update(kw)
# Tools used by __monthNames:
def fullName(i, name): return name
def firstThree(i, name): return name[:3]
def initial(i, name): return name[:1]
def number(i, name): return str(i + 1)
@staticmethod
def __monthNames(calendars,
known={ # Map calendar to (names, extractors...):
'gregorian': (('January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December'),
# Extractor pairs, (plain, standalone)
(fullName, fullName), # long
(firstThree, firstThree), # short
(number, initial)), # narrow
'hebrew': (('Tishri', 'Heshvan', 'Kislev', 'Tevet', 'Shevat', 'Adar I',
'Adar', 'Nisan', 'Iyar', 'Sivan', 'Tamuz', 'Av'),
(fullName, fullName),
(fullName, fullName),
(number, number)),
},
sizes=('long', 'short', 'narrow')):
for cal in calendars:
try:
data = known[cal]
except KeyError: # Need to add an entry to known, above.
print 'Unsupported calendar:', cal
raise
names, get = data[0] + ('',), data[1:]
for n, size in enumerate(sizes):
yield ('_'.join((camelCase((size, 'months')), cal)),
';'.join(get[n][0](i, x) for i, x in enumerate(names)))
yield ('_'.join((camelCase(('standalone', size, 'months')), cal)),
';'.join(get[n][1](i, x) for i, x in enumerate(names)))
del fullName, firstThree, initial, number
@classmethod @classmethod
def C(cls, def C(cls, calendars=('gregorian',),
# Empty entries at end to ensure final separator when join()ed: # Empty entry at end to ensure final separator when join()ed:
months = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December', ''),
days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday', ''), 'Thursday', 'Friday', 'Saturday', ''),
quantifiers=('k', 'M', 'G', 'T', 'P', 'E')): quantifiers=('k', 'M', 'G', 'T', 'P', 'E')):
"""Returns an object representing the C locale.""" """Returns an object representing the C locale."""
return cls(language='C', language_code='0', language_endonym='', return cls(dict(cls.__monthNames(calendars)),
language='C', language_code='0', language_endonym='',
script='AnyScript', script_code='0', script='AnyScript', script_code='0',
country='AnyCountry', country_code='0', country_endonym='', country='AnyCountry', country_code='0', country_endonym='',
decimal='.', group=',', list=';', percent='%', decimal='.', group=',', list=';', percent='%',
@ -245,12 +281,6 @@ class Locale:
weekendStart='sat', weekendEnd='sun', weekendStart='sat', weekendEnd='sun',
longDateFormat='EEEE, d MMMM yyyy', shortDateFormat='d MMM yyyy', longDateFormat='EEEE, d MMMM yyyy', shortDateFormat='d MMM yyyy',
longTimeFormat='HH:mm:ss z', shortTimeFormat='HH:mm:ss', longTimeFormat='HH:mm:ss z', shortTimeFormat='HH:mm:ss',
longMonths=';'.join(months),
shortMonths=';'.join(m[:3] for m in months),
narrowMonths='1;2;3;4;5;6;7;8;9;10;11;12;',
standaloneLongMonths=';'.join(months),
standaloneShortMonths=';'.join(m[:3] for m in months),
standaloneNarrowMonths=';'.join(m[:1] for m in months),
longDays=';'.join(days), longDays=';'.join(days),
shortDays=';'.join(d[:3] for d in days), shortDays=';'.join(d[:3] for d in days),
narrowDays='7;1;2;3;4;5;6;', narrowDays='7;1;2;3;4;5;6;',

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2 #!/usr/bin/env python2
############################################################################# #############################################################################
## ##
## Copyright (C) 2017 The Qt Company Ltd. ## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/ ## Contact: https://www.qt.io/licensing/
## ##
## This file is part of the test suite of the Qt Toolkit. ## This file is part of the test suite of the Qt Toolkit.
@ -42,6 +42,10 @@ from enumdata import language_aliases, country_aliases, script_aliases
from localexml import Locale from localexml import Locale
# TODO: Make calendars a command-line parameter
# map { CLDR name: Qt file name }
calendars = {'gregorian': 'roman',} # 'persian': 'jalali', 'islamic': 'hijri', 'hebrew': 'hebrew',
generated_template = """ generated_template = """
/* /*
This part of the file was generated on %s from the This part of the file was generated on %s from the
@ -165,7 +169,7 @@ def loadLocaleMap(doc, language_map, script_map, country_map, likely_subtags_map
result = {} result = {}
for locale_elt in eachEltInGroup(doc.documentElement, "localeList", "locale"): for locale_elt in eachEltInGroup(doc.documentElement, "localeList", "locale"):
locale = Locale.fromXmlData(lambda k: firstChildText(locale_elt, k)) locale = Locale.fromXmlData(lambda k: firstChildText(locale_elt, k), calendars.keys())
language_id = languageNameToId(locale.language, language_map) language_id = languageNameToId(locale.language, language_map)
if language_id == -1: if language_id == -1:
sys.stderr.write("Cannot find a language id for '%s'\n" % locale.language) sys.stderr.write("Cannot find a language id for '%s'\n" % locale.language)
@ -268,6 +272,7 @@ class StringData:
self.data = [] self.data = []
self.hash = {} self.hash = {}
self.name = name self.name = name
def append(self, s): def append(self, s):
if s in self.hash: if s in self.hash:
return self.hash[s] return self.hash[s]
@ -293,6 +298,11 @@ class StringData:
self.data += lst self.data += lst
return token return token
def write(self, fd):
fd.write("\nstatic const ushort %s[] = {\n" % self.name)
fd.write(wrap_list(self.data))
fd.write("\n};\n")
def escapedString(s): def escapedString(s):
result = "" result = ""
i = 0 i = 0
@ -443,7 +453,6 @@ def main():
list_pattern_part_data = StringData('list_pattern_part_data') list_pattern_part_data = StringData('list_pattern_part_data')
date_format_data = StringData('date_format_data') date_format_data = StringData('date_format_data')
time_format_data = StringData('time_format_data') time_format_data = StringData('time_format_data')
months_data = StringData('months_data')
days_data = StringData('days_data') days_data = StringData('days_data')
am_data = StringData('am_data') am_data = StringData('am_data')
pm_data = StringData('pm_data') pm_data = StringData('pm_data')
@ -483,12 +492,6 @@ def main():
+ ' lDtFmt ' + ' lDtFmt '
+ ' sTmFmt ' # Time format + ' sTmFmt ' # Time format
+ ' lTmFmt ' + ' lTmFmt '
+ ' ssMonth ' # Months
+ ' slMonth '
+ ' snMonth '
+ ' sMonth '
+ ' lMonth '
+ ' nMonth '
+ ' ssDays ' # Days + ' ssDays ' # Days
+ ' slDays ' + ' slDays '
+ ' snDays ' + ' snDays '
@ -533,7 +536,7 @@ def main():
# Quotation marks: # Quotation marks:
+ '%8d,' * 4 + '%8d,' * 4
# List patterns, date/time formats, month/day names, am/pm: # List patterns, date/time formats, month/day names, am/pm:
+ '%11s,' * 22 + '%11s,' * 16
# SI/IEC byte-unit abbreviations: # SI/IEC byte-unit abbreviations:
+ '%8s,' * 3 + '%8s,' * 3
# Currency ISO code: # Currency ISO code:
@ -569,12 +572,6 @@ def main():
date_format_data.append(l.longDateFormat), date_format_data.append(l.longDateFormat),
time_format_data.append(l.shortTimeFormat), time_format_data.append(l.shortTimeFormat),
time_format_data.append(l.longTimeFormat), time_format_data.append(l.longTimeFormat),
months_data.append(l.standaloneShortMonths),
months_data.append(l.standaloneLongMonths),
months_data.append(l.standaloneNarrowMonths),
months_data.append(l.shortMonths),
months_data.append(l.longMonths),
months_data.append(l.narrowMonths),
days_data.append(l.standaloneShortDays), days_data.append(l.standaloneShortDays),
days_data.append(l.standaloneLongDays), days_data.append(l.standaloneLongDays),
days_data.append(l.standaloneNarrowDays), days_data.append(l.standaloneNarrowDays),
@ -600,7 +597,7 @@ def main():
l.weekendEnd) l.weekendEnd)
+ ", // %s/%s/%s\n" % (l.language, l.script, l.country)) + ", // %s/%s/%s\n" % (l.language, l.script, l.country))
data_temp_file.write(line_format # All zeros, matching the format: data_temp_file.write(line_format # All zeros, matching the format:
% ( (0,) * (3 + 8 + 4) + ("0,0",) * (22 + 3) % ( (0,) * (3 + 8 + 4) + ("0,0",) * (16 + 3)
+ (currencyIsoCodeData(0),) + (currencyIsoCodeData(0),)
+ ("0,0",) * 6 + (0,) * (2 + 3)) + ("0,0",) * 6 + (0,) * (2 + 3))
+ " // trailing 0s\n") + " // trailing 0s\n")
@ -608,13 +605,11 @@ def main():
# StringData tables: # StringData tables:
for data in (list_pattern_part_data, date_format_data, for data in (list_pattern_part_data, date_format_data,
time_format_data, months_data, days_data, time_format_data, days_data,
byte_unit_data, am_data, pm_data, currency_symbol_data, byte_unit_data, am_data, pm_data, currency_symbol_data,
currency_display_name_data, currency_format_data, currency_display_name_data, currency_format_data,
endonyms_data): endonyms_data):
data_temp_file.write("\nstatic const ushort %s[] = {\n" % data.name) data.write(data_temp_file)
data_temp_file.write(wrap_list(data.data))
data_temp_file.write("\n};\n")
data_temp_file.write("\n") data_temp_file.write("\n")
@ -739,6 +734,62 @@ def main():
os.remove(qtsrcdir + "/src/corelib/text/qlocale_data_p.h") os.remove(qtsrcdir + "/src/corelib/text/qlocale_data_p.h")
os.rename(data_temp_file_path, qtsrcdir + "/src/corelib/text/qlocale_data_p.h") os.rename(data_temp_file_path, qtsrcdir + "/src/corelib/text/qlocale_data_p.h")
# Generate calendar data
calendar_format = ' {%6d,%6d,%6d,{%5s},{%5s},{%5s},{%5s},{%5s},{%5s}}, '
for calendar, stem in calendars.items():
months_data = StringData('months_data')
calendar_data_file = "q%scalendar_data_p.h" % stem
calendar_template_file = open(os.path.join(qtsrcdir, 'src', 'corelib', 'time',
calendar_data_file), "r")
(calendar_temp_file, calendar_temp_file_path) = tempfile.mkstemp(calendar_data_file, dir=qtsrcdir)
calendar_temp_file = os.fdopen(calendar_temp_file, "w")
s = calendar_template_file.readline()
while s and s != GENERATED_BLOCK_START:
calendar_temp_file.write(s)
s = calendar_template_file.readline()
calendar_temp_file.write(GENERATED_BLOCK_START)
calendar_temp_file.write(generated_template % (datetime.date.today(), cldr_version))
calendar_temp_file.write("static const QCalendarLocale locale_data[] = {\n")
calendar_temp_file.write(' // '
# IDs, width 7 (6 + comma)
+ ' lang '
+ ' script'
+ ' terr '
# Month-name start-end pairs, width 8 (5 plus '{},'):
+ ' sShort '
+ ' sLong '
+ ' sNarrow'
+ ' short '
+ ' long '
+ ' narrow'
# No trailing space on last; be sure
# to pad before adding later entries.
+ '\n')
for key in locale_keys:
l = locale_map[key]
calendar_temp_file.write(
calendar_format
% (key[0], key[1], key[2],
months_data.append(l.standaloneShortMonths[calendar]),
months_data.append(l.standaloneLongMonths[calendar]),
months_data.append(l.standaloneNarrowMonths[calendar]),
months_data.append(l.shortMonths[calendar]),
months_data.append(l.longMonths[calendar]),
months_data.append(l.narrowMonths[calendar]))
+ "// %s/%s/%s\n " % (l.language, l.script, l.country))
calendar_temp_file.write(calendar_format % ( (0,) * 3 + ('0,0',) * 6 )
+ '// trailing zeros\n')
calendar_temp_file.write("};\n")
months_data.write(calendar_temp_file)
s = calendar_template_file.readline()
while s and s != GENERATED_BLOCK_END:
s = calendar_template_file.readline()
while s:
calendar_temp_file.write(s)
s = calendar_template_file.readline()
os.rename(calendar_temp_file_path,
os.path.join(qtsrcdir, 'src', 'corelib', 'time', calendar_data_file))
# qlocale.h # qlocale.h
(qlocaleh_temp_file, qlocaleh_temp_file_path) = tempfile.mkstemp("qlocale.h", dir=qtsrcdir) (qlocaleh_temp_file, qlocaleh_temp_file_path) = tempfile.mkstemp("qlocale.h", dir=qtsrcdir)