QDateTime - Add api for Time Zone Abbreviation

Add a new method to return the time zone abbreviation for the current
time spec.  For LocalTime this is the abbreviation returned by mktime.

This new method will later be used in changes to the date formatter
and QTimeZone.

Note this change does not implement WinCE support.

[ChangeLog][QtCore][QDateTime] Add method timeZoneAbbreviation() to
return effective time zone abbreviation.

Change-Id: I265a5e96c72eb7236974f80f053f1fb341e3c816
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
This commit is contained in:
John Layt 2013-07-17 11:38:00 +02:00 committed by The Qt Project
parent 89ee4a50b0
commit 5ec1c7727b
3 changed files with 139 additions and 1 deletions

View File

@ -174,6 +174,7 @@ static void rfcDateImpl(const QString &s, QDate *dd = 0, QTime *dt = 0, int *utf
#endif
static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time);
static void utcToOffset(QDate *date, QTime *time, qint32 offset);
static QDate adjustDate(QDate date);
// Return offset in [+-]HH:MM format
// Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not
@ -225,6 +226,68 @@ static int fromOffsetString(const QString &offsetString, bool *valid)
return ((hour * 60) + minute) * 60;
}
#if !defined(Q_OS_WINCE)
// Calls the platform variant of mktime for the given date and time,
// and updates the date, time, spec and abbreviation with the returned values
// If the date falls outside the 1970 to 2037 range supported by mktime / time_t
// then null date/time will be returned, you should call adjustDate() first if
// you need a guaranteed result.
static time_t qt_mktime(QDate *date, QTime *time, QDateTimePrivate::Spec *spec,
QString *abbreviation, bool *ok)
{
if (ok)
*ok = false;
int yy, mm, dd;
date->getDate(&yy, &mm, &dd);
tm local;
local.tm_sec = time->second();
local.tm_min = time->minute();
local.tm_hour = time->hour();
local.tm_mday = dd;
local.tm_mon = mm - 1;
local.tm_year = yy - 1900;
local.tm_wday = 0;
local.tm_yday = 0;
local.tm_isdst = -1;
#if defined(Q_OS_WIN)
_tzset();
#else
tzset();
#endif // Q_OS_WIN
const time_t secsSinceEpoch = mktime(&local);
if (secsSinceEpoch != (uint)-1) {
*date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
*time = QTime(local.tm_hour, local.tm_min, local.tm_sec, time->msec());
if (local.tm_isdst == 1) {
if (spec)
*spec = QDateTimePrivate::LocalDST;
if (abbreviation)
*abbreviation = QString::fromLocal8Bit(tzname[1]);
} else if (local.tm_isdst == 0) {
if (spec)
*spec = QDateTimePrivate::LocalStandard;
if (abbreviation)
*abbreviation = QString::fromLocal8Bit(tzname[0]);
} else {
if (spec)
*spec = QDateTimePrivate::LocalUnknown;
if (abbreviation)
*abbreviation = QString::fromLocal8Bit(tzname[0]);
}
if (ok)
*ok = true;
} else {
*date = QDate();
*time = QTime();
if (spec)
*spec = QDateTimePrivate::LocalUnknown;
if (abbreviation)
*abbreviation = QString();
}
return secsSinceEpoch;
}
#endif // !Q_OS_WINCE
/*****************************************************************************
QDate member functions
*****************************************************************************/
@ -2456,6 +2519,49 @@ int QDateTime::offsetFromUtc() const
}
}
/*!
\since 5.2
Returns the Time Zone Abbreviation for the datetime.
If the timeSpec() is Qt::UTC this will be "UTC".
If the timeSpec() is Qt::OffsetFromUTC this will be in the format
"UTC[+-]00:00".
If the timeSpec() is Qt::LocalTime then the host system is queried for the
correct abbreviation.
Note that abbreviations may or may not be localized.
Note too that the abbreviation is not guaranteed to be a unique value,
i.e. different time zones may have the same abbreviation.
\sa timeSpec()
*/
QString QDateTime::timeZoneAbbreviation() const
{
switch (d->spec) {
case QDateTimePrivate::UTC:
return QStringLiteral("UTC");
case QDateTimePrivate::OffsetFromUTC:
return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
default: { // Any Qt::LocalTime
#if defined(Q_OS_WINCE)
// TODO Stub to enable compilation on WinCE
return QString();
#else
QDate dt = adjustDate(d->date);
QTime tm = d->time;
QString abbrev;
qt_mktime(&dt, &tm, 0, &abbrev, 0);
return abbrev;
#endif // !Q_OS_WINCE
}
}
}
/*!
Sets the date part of this datetime to \a date.
If no time is set, it is set to midnight.

View File

@ -219,6 +219,7 @@ public:
QTime time() const;
Qt::TimeSpec timeSpec() const;
int offsetFromUtc() const;
QString timeZoneAbbreviation() const;
qint64 toMSecsSinceEpoch() const;
// ### Qt 6: use quint64 instead of uint

View File

@ -133,6 +133,8 @@ private slots:
void setOffsetFromUtc();
void toOffsetFromUtc();
void timeZoneAbbreviation();
void getDate();
void fewDigitsInYear() const;
@ -592,7 +594,7 @@ void tst_QDateTime::fromMSecsSinceEpoch()
QCOMPARE(dtUtc.time(), utc.time());
QCOMPARE(dtOffset, utc);
QCOMPARE(dtOffset.utcOffset(), 60*60);
QCOMPARE(dtOffset.offsetFromUtc(), 60*60);
QCOMPARE(dtOffset.time(), utc.time().addMSecs(60*60*1000));
if (europeanTimeZone) {
@ -2221,6 +2223,35 @@ void tst_QDateTime::toOffsetFromUtc()
QCOMPARE(dt2.time(), QTime(0, 0, 0));
}
void tst_QDateTime::timeZoneAbbreviation()
{
QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60);
QCOMPARE(dt1.timeZoneAbbreviation(), QString("UTC+01:00"));
QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60);
QCOMPARE(dt2.timeZoneAbbreviation(), QString("UTC-01:00"));
QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
QCOMPARE(dt3.timeZoneAbbreviation(), QString("UTC"));
// LocalTime should vary
if (europeanTimeZone) {
// Time definitely in Standard Time
QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
#endif // Q_OS_WIN
QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET"));
// Time definitely in Daylight Time
QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime);
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
#endif // Q_OS_WIN
QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST"));
} else {
QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
}
}
void tst_QDateTime::getDate()
{
{