[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    KDateTime: revised version
From:       David Jarvie <lists () astrojar ! org ! uk>
Date:       2005-11-21 2:14:13
Message-ID: 200511210214.17505.lists () astrojar ! org ! uk
[Download RAW message or body]

Attached is revised code for a new KDateTime class. There are various minor 
changes in response to comments.

It includes toString() and fromString() methods, as requested in previous 
comments. Note that because a UTC offset specified in a time string doesn't 
uniquely define a time zone (different time zones can have the same UTC 
offset at various times of the year, or simultaneously), fromString() can't 
necessarily do the reverse of toString(). The only way to unambiguously read 
a time with time zone is to have the time zone name included in the string, 
and for a KTimezones collection to be supplied in which to look up that time 
zone name. (Of course, a time zone can also be defined by a very long string 
giving details of all its time changes, etc., but that isn't a user readable 
thing which toString() would want to output.) This isn't ideal, but is AFAICS 
an inevitable restriction on what fromString() can do.

Serialisation functions (operator>>(QTextStream&...) etc.) are not included 
because of the problems serialising KTimezone subclasses (see 
http://lists.kde.org/?l=kde-core-devel&m=113210232605956&w=2).

The code doesn't quite compile yet, because it would require a new method in 
KTimezone ( utcOffsets() ) which I'll implement when necessary.

Once it's been tested (via a qttestlib test program) and 
KTimezone::utcOffsets() has been added, is it now OK to commit?

-- 
David Jarvie.
KAlarm author and maintainer.
http://www.astrojar.org.uk/linux/kalarm.html

["kdatetime.cpp" (text/x-c++src)]

/*
    This file is part of the KDE libraries
    Copyright (c) 2005 David Jarvie <software@astrojar.org.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <stdlib.h>
#include <QDateTime>
#include <QRegExp>
#include <QStringList>
#include <kdebug.h>
#include <kdatetime.h>


/****************************************************************************
 **
 ** DateTimeParser and FormatSection classes are based on QDateTime internals:
 **
 ** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 **
 ** This file is part of the QtCore module of the Qt Toolkit.
 **
 ** This file may be used under the terms of the GNU General Public
 ** License version 2.0 as published by the Free Software Foundation
 ** and appearing in the file LICENSE.GPL included in the packaging of
 ** this file.  Please review the following information to ensure GNU
 ** General Public Licensing requirements will be met:
 ** http://www.trolltech.com/products/qt/opensource.html
 **
 ** If you are unsure which license is appropriate for your use, please
 ** review the following information:
 ** http://www.trolltech.com/products/qt/licensing.html or contact the
 ** sales department at sales@trolltech.com.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ****************************************************************************/

#ifndef QT_NO_TEXTDATE
static const char * const qt_shortMonthNames[] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const char * const qt_longMonthNames[] = {
    "January", "February", "Mars", "April", "May", "June",
    "July", "August", "September", "October", "November", "December" };
static const char * const qt_shortDayNames[] = {
    "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
static const char * const qt_longDayNames[] = {
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
#endif

class FormatSection;
class DateTimeParser
{
public:
    enum Section {
        NoSection = 0x0000000,

        Day1 = 0x0000001,
        Day2 = 0x0000002,
        Day3 = 0x0000004,
        Day4 = 0x0000008,
        DayMask = (Day1|Day2|Day3|Day4),

        Month1 = 0x0000010,
        Month2 = 0x0000020,
        Month3 = 0x0000040,
        Month4 = 0x0000080,
        MonthMask = (Month1|Month2|Month3|Month4),

        Year2 = 0x0000100,
        Year4 = 0x0000200,
        YearMask = (Year2|Year4),
        DateMask = (DayMask|MonthMask|YearMask),

        Hour1 = 0x0000400,
        Hour2 = 0x0000800,
        HourMask = (Hour1|Hour2),

        Minute1 = 0x0001000,
        Minute2 = 0x0002000,
        MinuteMask = (Minute1|Minute2),

        Second1 = 0x0004000,
        Second2 = 0x0008000,
        SecondMask = (Second1|Second2),

        MSecond1 = 0x0010000,
        MSecond3 = 0x0020000,
        MSecondMask = (MSecond1|MSecond3),

        APLower = 0x0040000,
        APUpper = 0x0080000,
        APMask = (APLower|APUpper),

        TimeMask = (HourMask|MinuteMask|SecondMask|MSecondMask),

        UTC2 = 0x0100000,
        UTC3 = 0x0200000,
        UTC4  = 0x0400000,
        UTCMask = (UTC2|UTC3|UTC4),

        Zone3 = 0x0800000,
        Zone4  = 0x1000000,
        ZoneMask  = (Zone3|Zone4),

        TimeZoneMask = (UTCMask|ZoneMask),

        Quote = 0x10000000,
        Separator = 0x20000000,
        FirstSection = 0x40000000,
        LastSection = 0x80000000
    };

    DateTimeParser(const QString &f = QString());
    bool isSpecial(const QChar &c) const;
    FormatSection findNextFormat(const QString &str, const int start);
    void parseFormat(const QString &format);
    QDateTime fromString(const QString &string);

    static bool withinBounds(DateTimeParser::Section t, int num);
    static int getNumber(int index, const QString &str, int mindigits, int maxdigits, \
bool *ok, int *digits);

    static FormatSection firstSection;
    static FormatSection lastSection;

    QList<FormatSection> sect;
    QString format;
    uint display;
    QString zoneName;
    QString zoneAbbrev;
    int utcOffset;
};



/*----------------------------------------------------------------------------*/

class KDateTimePrivate
{
  public:
    KDateTimePrivate()  : tz(0), utc(false) {}
    KDateTimePrivate(const QDateTime &d, const KTimezone *z = 0, Qt::TimeSpec spec = \
Qt::LocalTime)  : dt(d), tz(z), utc(!z && spec == Qt::UTC)
    {
        dt.setTimeSpec(utc ? Qt::UTC : Qt::LocalTime);
    }

    KDateTimePrivate(const KDateTimePrivate &dtp)
      : dt(dtp.dt), tz(dtp.tz), utc(dtp.utc) {}

    ~KDateTimePrivate()  {}

    QDateTime  dt;
    const KTimezone *tz;     // this is not owned by KDateTime or KDateTimePrivate
    bool       utc;
};


/*----------------------------------------------------------------------------*/

KDateTime::KDateTime()
  : d(new KDateTimePrivate)
{
}

KDateTime::KDateTime(const QDate &date, const KTimezone *tz)
  : d(new KDateTimePrivate(QDateTime(date), tz))
{
}

KDateTime::KDateTime(const QDate &date, const QTime &time, const KTimezone *tz)
  : d(new KDateTimePrivate(QDateTime(date, time), tz))
{
}

KDateTime::KDateTime(const QDateTime &dt, const KTimezone *tz)
  : d(new KDateTimePrivate(dt, tz))
{
    if (dt.timeSpec() == Qt::UTC)
    {
        if (tz)
            d->dt = tz->toZoneTime(dt);
        else
            d->dt = KSystemTimezones::local()->toZoneTime(dt);
    }
}

KDateTime::KDateTime(const QDate &date, Qt::TimeSpec spec)
  : d(new KDateTimePrivate(QDateTime(date), 0, spec))
{
}

KDateTime::KDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
  : d(new KDateTimePrivate(QDateTime(date, time), 0, spec))
{
}

KDateTime::KDateTime(const QDateTime &dt, Qt::TimeSpec spec)
  : d(new KDateTimePrivate(dt, 0, spec))
{
    if (dt.timeSpec() != spec)
    {
        const KTimezone *local = KSystemTimezones::local();
        if (spec == Qt::UTC)
            d->dt = local->toUTC(dt);
        else
            d->dt = local->toZoneTime(dt);
    }
}

KDateTime::KDateTime(const KDateTime &other)
  : d(new KDateTimePrivate(*other.d))
{
}

KDateTime::~KDateTime()
{
  delete d;
}

bool      KDateTime::isNull() const              { return d->dt.isNull(); }
bool      KDateTime::isValid() const             { return d->dt.isValid(); }
QDate     KDateTime::date() const                { return d->dt.date(); }
QTime     KDateTime::time() const                { return d->dt.time(); }
QDateTime KDateTime::dateTime() const            { return d->dt; }
bool      KDateTime::isLocal() const             { return !d->tz && !d->utc; }
void      KDateTime::setDate(const QDate &date)  { d->dt.setDate(date); }
void      KDateTime::setTime(const QTime &time)  { d->dt.setTime(time); }

bool KDateTime::isUTC() const
{
    if (!d->tz)
        return d->utc;
    if (d->tz == KTimezones::utc())
        return true;
    return false;
}

const KTimezone *KDateTime::timeZone() const
{
    return d->tz ? d->tz : d->utc ? KTimezones::utc() : 0;
}

QDateTime KDateTime::toUTC() const
{
    if (d->utc)
        return d->dt;
    else
    {
        const KTimezone *tz = (d->tz ? d->tz : KSystemTimezones::local());
        return tz->toUTC(d->dt);
    }
}

QDateTime KDateTime::toLocal() const
{
    if (!d->tz && !d->utc)
        return d->dt;
    else
    {
        const KTimezone *tz = (d->tz ? d->tz : KTimezones::utc());
        QDateTime dt = d->dt;
        dt.setTimeSpec(Qt::LocalTime);
        return tz->convert(KSystemTimezones::local(), dt);
    }
}

uint KDateTime::toTime_t() const
{
    return toUTC().toTime_t();
}

void KDateTime::setTimeZone(Qt::TimeSpec spec)
{
    d->tz = 0;
    d->dt.setTimeSpec(spec);
    d->utc = (spec == Qt::UTC);
}

void KDateTime::setTimeZone(const KTimezone *tz)
{
    d->tz = tz;
    if (tz)
    {
        d->dt.setTimeSpec(Qt::LocalTime);
        d->utc = false;
    }
}

void KDateTime::setTime_t(uint seconds)
{
    QDateTime dt;
    dt.setTime_t(seconds);
    if (d->utc)
        d->dt = dt;
    else
    {
        const KTimezone *tz = (d->tz ? d->tz : KSystemTimezones::local());
        d->dt = tz->toZoneTime(dt);
    }
}

KDateTime KDateTime::addSecs(int secs) const
{
    if (d->utc)
        return KDateTime(toUTC().addSecs(secs), Qt::UTC);
    else
        return KDateTime(toUTC().addSecs(secs), d->tz);
}

KDateTime KDateTime::addDays(int days) const
{
    KDateTime dt(*this);
    dt.d->dt = d->dt.addDays(days);
    return dt;
}

KDateTime KDateTime::addMonths(int months) const
{
    KDateTime dt(*this);
    dt.d->dt = d->dt.addMonths(months);
    return dt;
}

KDateTime KDateTime::addYears(int years) const
{
    KDateTime dt(*this);
    dt.d->dt = d->dt.addYears(years);
    return dt;
}

int KDateTime::daysTo(const KDateTime &t2) const
{
    if (d->utc)
        return d->dt.daysTo(t2.toUTC());
    else
    {
        const KTimezone *tz = (d->tz ? d->tz : KSystemTimezones::local());
        QDateTime dt1 = d->dt;
        dt1.setTimeSpec(Qt::UTC);
        QDateTime dt2;
        if (t2.d->utc)
            dt2 = tz->toZoneTime(t2.d->dt);
        else
        {
            const KTimezone *tz2 = (t2.d->tz ? t2.d->tz : KSystemTimezones::local());
            dt2 = tz2->convert(tz, t2.d->dt);
            dt2.setTimeSpec(Qt::UTC);
        }
        return dt1.daysTo(dt2);
    }
}

int KDateTime::secsTo(const KDateTime &t2) const
{
    return toUTC().secsTo(t2.toUTC());
}

QString KDateTime::toString(const QString &format) const
{
    // Do the QDateTime conversion
    QString dtresult = d->dt.toString(format);
    if (dtresult.isEmpty())
        return dtresult;

    // Do the time zone conversion
    QString fmt, result;
    QChar status = QLatin1Char('0');
    for (int i = 0, end = dtresult.length();  ;  ++i)
    {
        if (i < end  &&  dtresult[i] == status  &&  fmt.length() < 4)
            fmt += dtresult[i];
        else if (!fmt.isEmpty())
        {
            int code = (fmt == QLatin1String("uu"))   ? 1
                     : (fmt == QLatin1String("uuu"))  ? 2
                     : (fmt == QLatin1String("uuuu")) ? 3
                     : (fmt == QLatin1String("ZZZ"))  ? 4
                     : (fmt == QLatin1String("ZZZZ")) ? 5 : 0;
            if (!code)
                result += fmt;
            else if (d->utc  ||  d->tz)
            {
                const KTimezone *tz = d->tz ? d->tz : KTimezones::utc();
                int offset = d->tz ? tz->offsetAtZoneTime(d->dt) : 0;
                switch (code)
                {
                    case 1:
                    case 2:
                    case 3:
                    {
                        QString s;
                        result += s.sprintf((code == 3 ? "%+02d:" : "%+02d"), \
offset/60);  int minutes = abs(offset) % 60;
                        if (code != 1  ||  minutes)
                            result += s.sprintf("%02d", minutes);
                        break;
                    }
                    case 4:
                        result += tz->abbreviation(toUTC());
                        break;
                    case 5:
                        result += tz->name();
                        break;
                }
            }
            fmt = QString();
            status = QLatin1Char('0');
        }
        if (i < end)
        {
            QChar ch = dtresult[i];
            if (ch == QLatin1Char('\''))    // skip text enclosed in single quotes
            {
                status = QLatin1Char('0');
                while (++i < end  &&  dtresult[i] != QLatin1Char('\''))
                    result += dtresult[i];
            }
            else if (ch == QLatin1Char('u') || ch == QLatin1Char('Z'))
                fmt = status = ch;
            else
            {
                if (ch == QLatin1Char('\\')  &&  i + 1 < end)
                    ++i;    // append escaped character
                result += dtresult[i];
                status = QLatin1Char('0');
            }
        }
        if (i >= end)
            break;
    }
    return result;
}

QString KDateTime::toString(Qt::DateFormat format) const
{
    QString result = d->dt.toString(format);
    if (!result.isEmpty())
    {
        if (d->utc)
        {
            if (format == Qt::ISODate)
                result += QLatin1Char('Z');
            else
                result += QLatin1String(" +0000");
        }
        else if (d->tz)
        {
            if (format != Qt::ISODate)
                result += QLatin1Char(' ');
            int offset = d->tz->offsetAtZoneTime(d->dt);
            QString s;
            result += s.sprintf("%+02d%02d", offset/60, abs(offset)%60);
        }
    }
    return result;
}

QDateTime KDateTime::fromString(const QString &string, Qt::DateFormat format)
{
    int n = string.count();
    if (!n)
        return QDateTime();

    if (format == Qt::ISODate  &&  string[n - 1] == QLatin1Char('Z'))
    {
        QDateTime dt = QDateTime::fromString(string.left(n - 1), Qt::ISODate);
        dt.setTimeSpec(Qt::UTC);
        return dt;
    }

    int offset = 0;
    QRegExp rx("([+-][\\d][\\d])(:?([\\d][\\d]))?$");
    int tzIndex = string.indexOf(rx);
    if (tzIndex < 0)
    {
        QDateTime dt = QDateTime::fromString(string, format);
        dt.setTimeSpec(Qt::LocalTime);
        return dt;
    }

    // Extract the UTC offset at the end of the string
    QStringList lst = rx.capturedTexts();
    offset = lst[1].toInt() * 3600;
    if (lst.count() > 3)
        offset += lst[3].toInt() * (offset >= 0 ? 60 : -60);
    QString str = string.left(tzIndex);
    if (format != Qt::ISODate)
        str = str.trimmed();
    QDateTime dt = QDateTime::fromString(str, format);
    if (!dt.isValid())
        return QDateTime();
    dt.setTimeSpec(Qt::UTC);
    dt.addSecs(offset);
    return dt;
}

QDateTime KDateTime::fromString(const QString &string, const QString &format)
{
    DateTimeParser parser(format);
    QDateTime dt = parser.fromString(string);
    if (!dt.isValid())
        return QDateTime(QDate(), QTime(-1, -1, -1));
    if (parser.utcOffset)
    {
        dt.setTimeSpec(Qt::UTC);
        return dt.addSecs(parser.utcOffset * 60);
    }
    return dt;
}

KDateTime KDateTime::fromString(const QString &string, const QString &format,
                                const KTimezones &zones, bool utcIfAmbiguous)
{
    DateTimeParser parser(format);
    QDateTime dt = parser.fromString(string);
    if (!dt.isValid())
        return KDateTime();
    const KTimezone *zone = 0;
    if (!parser.zoneName.isEmpty())
    {
        // A time zone name has been found.
        // Use the time zone with that name.
        zone = zones.zone(parser.zoneName);
    }
    else if (!parser.zoneAbbrev.isEmpty())
    {
        // A time zone abbreviation has been found.
        // Use the time zone which contains it, if any.
#warning Should this use utf8 conversion?
	QByteArray abbrev = parser.zoneAbbrev.toUtf8();
        const KTimezones::ZoneMap z = zones.zones();
	for (KTimezones::ZoneMap::ConstIterator it = z.begin(), end = z.end();  it != end;  \
++it)  {
            if (it.data()->abbreviations().indexOf(abbrev) >= 0)
            {
                if (zone)
                    return KDateTime();    // zone abbreviation is ambiguous
                zone = it.data();
            }
        }
    }
    else if (parser.utcOffset  ||  dt.timeSpec() == Qt::UTC)
    {
        // A UTC offset has been found.
        // Use the time zone which contains it, if any.
        const KTimezones::ZoneMap z = zones.zones();
	for (KTimezones::ZoneMap::ConstIterator it = z.begin(), end = z.end();  it != end;  \
++it)  {
            if (it.data()->utcOffsets().indexOf(parser.utcOffset) >= 0)
            {
                if (zone  ||  !parser.utcOffset)
                {
                    // UTC offset is used by more than one time zone
                    if (!utcIfAmbiguous)
                        return KDateTime();
                    dt.setTimeSpec(Qt::UTC);
                    return KDateTime(dt.addSecs(parser.utcOffset * 60), Qt::UTC);
                }
                zone = it.data();
            }
        }
        if (!parser.utcOffset)
        {
            // It's a UTC time
            dt.setTimeSpec(Qt::UTC);
            return KDateTime(dt, Qt::UTC);
        }
    }
    else
        return KDateTime(dt, Qt::LocalTime);

    return zone ? KDateTime(dt, zone) : KDateTime();
}

bool KDateTime::operator==(const KDateTime &other) const
{
    if (d->utc && other.d->utc  ||  d->tz == other.d->tz)
        return d->dt == other.d->dt;
    return toUTC() == other.toUTC();
}

bool KDateTime::operator<(const KDateTime &other) const
{
    if (d->utc && other.d->utc  ||  d->tz == other.d->tz)
        return d->dt < other.d->dt;
    return toUTC() < other.toUTC();
}

#if 0
QDataStream & operator<<(QDataStream &s, const KDateTime &dt)
{
    quint8 type = dt.isLocal() ? 0 : dt.isUTC() ? 1 : 2;
    s << dt.dateTime() << type;
//    if (type == 2)
//        s << *dt.timeZone();
    return s;
}

QDataStream & operator>>(QDataStream &s, KDateTime &kdt)
{
    quint8 type;
    QDateTime dt;
    s >> dt >> type;
    if (type == 2)
    {
        KTimezone *tz = new KTimezone;
//        s >> *tz;
        kdt = KDateTime(dt, tz);
    }
    else
    {
        Qt::TimeSpec spec = (type ? Qt::UTC : Qt::LocalTime);
        dt.setTimeSpec(spec);
//        kdt = KDateTime(dt, spec);
    }
    return s;
}
#endif



/*----------------------------------------------------------------------------*
 *  Internal parsing classes.
 *  Based on Qt internal QDateTime code.
 *----------------------------------------------------------------------------*/

class FormatSection
{
public:
    FormatSection(int ind, const QString &sep);
    FormatSection(int ind = -1, DateTimeParser::Section typ = \
DateTimeParser::NoSection);  int length() const;
    static int length(DateTimeParser::Section t);

    int index;
    QString chars;
    DateTimeParser::Section type;
};


FormatSection DateTimeParser::firstSection = FormatSection(0, \
DateTimeParser::FirstSection); FormatSection DateTimeParser::lastSection = \
FormatSection(-1, DateTimeParser::LastSection);

FormatSection::FormatSection(int ind, const QString &sep)
    : index(ind), chars(sep), type(DateTimeParser::Separator)
{
}

FormatSection::FormatSection(int ind, DateTimeParser::Section typ)
    : index(ind), type(typ)
{
}

int FormatSection::length() const
{
    return type == DateTimeParser::Separator ? chars.size() : \
FormatSection::length(type); }

int FormatSection::length(DateTimeParser::Section t)
{
    switch (t) {
    case DateTimeParser::Day1: case DateTimeParser::Month1: case \
DateTimeParser::Hour1: case DateTimeParser::Minute1:  case DateTimeParser::Second1: \
case DateTimeParser::MSecond1: case DateTimeParser::Quote: return 1;

    case DateTimeParser::Day2: case DateTimeParser::Month2: case \
DateTimeParser::Year2: case DateTimeParser::Hour2:  case DateTimeParser::Minute2: \
case DateTimeParser::Second2: case DateTimeParser::APLower: case \
DateTimeParser::APUpper:  case DateTimeParser::UTC2: return 2;

    case DateTimeParser::Day3: case DateTimeParser::Month3: case \
DateTimeParser::MSecond3: case DateTimeParser::UTC3: case DateTimeParser::Zone3: \
return 3;

    case DateTimeParser::Day4: case DateTimeParser::Month4: case \
DateTimeParser::Year4: case DateTimeParser::UTC4: case DateTimeParser::Zone4: return \
4;

    default:
        qWarning("%s:%d DateTimeParser::length() %d should never be called here", \
__FILE__, __LINE__, t);  return 0;
    }
}



DateTimeParser::DateTimeParser(const QString &f)
    : display(0)
{
    parseFormat(f);
}

bool DateTimeParser::withinBounds(DateTimeParser::Section t, int num)
{
    int min, max;
    if (t == DateTimeParser::Year2) {
        min = 0; max = 99;
    } else if (t == DateTimeParser::Day3 || t == DateTimeParser::Day4) {
        min = 1; max = 7;
    } else if (t == DateTimeParser::Year4) {
        min = 1752; max = 7999;
    } else if (t & DateTimeParser::MonthMask) {
        min = 1; max = 12;
    } else if (t & DateTimeParser::DayMask) {
        min = 1; max = 31;
    } else if (t & DateTimeParser::HourMask) {
        min = 0; max = 23;
    } else if (t & DateTimeParser::MinuteMask) {
        min = 0; max = 59;
    } else if (t & DateTimeParser::SecondMask) {
        min = 0; max = 59;
    } else if (t & DateTimeParser::MSecondMask) {
        min = 0; max = 999;
    } else if (t == DateTimeParser::UTC2) {
        min = -23; max = 23;
    } else if (t & DateTimeParser::UTCMask) {
        min = -2359; max = 2359;
    } else {
        qWarning("%s:%d DateTimeParser::withinBounds() %0x should never be called \
with this argument", __FILE__, __LINE__, t);  return false;
    }

    return num >= min && num <= max;
}

int DateTimeParser::getNumber(int index, const QString &str, int mindigits, int \
maxdigits, bool *ok, int *digits) {
    if (str.size() < index + mindigits) {
        *ok = false;
        *digits = 0;
        return 0;
    }
    *digits = 0;
    int i = index;

    while (i < str.size() && str.at(i++).isNumber() && *digits < maxdigits)
        ++(*digits);

    if (*digits < mindigits) {
        *ok = false;
        *digits = 0;
        return 0;
    } else {
        return str.mid(index, *digits).toInt(ok);
    }
}

bool DateTimeParser::isSpecial(const QChar &c) const
{
    switch (c.cell()) {
    case 'd': case 'M': case 'y':
        return true;
    case 'h': case 'm': case 's': case 'z': case 'a': case 'p': case 'A': case 'P':
        return true;
    case 'u': case 'Z':
        return true;
    case '\'': return true;
    default: return false;
    }
}

FormatSection DateTimeParser::findNextFormat(const QString &str, const int start)
{
    const char quote = '\'';
    int i = start;
    DateTimeParser::Section typ = DateTimeParser::NoSection;
    while (i < str.size()) {
        const QChar &ch = str.at(i);
        if (isSpecial(ch)) {
            const QString rest = str.mid(i);
            switch (ch.cell()) {
            case quote: typ = DateTimeParser::Quote; break;
            case 'd':
                if (rest.startsWith(QLatin1String("dddd"))) {
                    typ = DateTimeParser::Day4;
                } else if (rest.startsWith(QLatin1String("ddd"))) {
                    typ = DateTimeParser::Day3;
                } else if (rest.startsWith(QLatin1String("dd"))) {
                    typ = DateTimeParser::Day2;
                } else {
                    typ = DateTimeParser::Day1;
                }
                break;
            case 'M':
                if (rest.startsWith(QLatin1String("MMMM"))) {
                    typ = DateTimeParser::Month4;
                } else if (rest.startsWith(QLatin1String("MMM"))) {
                    typ = DateTimeParser::Month3;
                } else if (rest.startsWith(QLatin1String("MM"))) {
                    typ = DateTimeParser::Month2;
                } else {
                    typ = DateTimeParser::Month1;
                }
                break;

            case 'y':
                if (rest.startsWith(QLatin1String("yyyy"))) {
                    typ = DateTimeParser::Year4;
                } else if (rest.startsWith(QLatin1String("yy"))) {
                    typ = DateTimeParser::Year2;
                }
                break;

            case 'h':
                if (rest.startsWith(QLatin1String("hh"))) {
                    typ = DateTimeParser::Hour2;
                } else {
                    typ = DateTimeParser::Hour1;
                }
                break;

            case 'm':
                if (rest.startsWith(QLatin1String("mm"))) {
                    typ = DateTimeParser::Minute2;
                } else {
                    typ = DateTimeParser::Minute1;
                }
                break;

            case 's':
                if (rest.startsWith(QLatin1String("ss"))) {
                    typ = DateTimeParser::Second2;
                } else {
                    typ = DateTimeParser::Second1;
                }
                break;

            case 'z':
                if (rest.startsWith(QLatin1String("zzz"))) {
                    typ = DateTimeParser::MSecond3;
                } else {
                    typ = DateTimeParser::MSecond1;
                }
                break;

            case 'a':
                if (rest.count() > 1 && rest.at(1) == QLatin1Char('p')) {
                    typ = DateTimeParser::APLower;
                }
                break;

            case 'A':
                if (rest.count() > 1 && rest.at(1) == QLatin1Char('P')) {
                    typ = DateTimeParser::APUpper;
                }
                break;

            case 'u':
                if (rest.startsWith(QLatin1String("uuuu"))) {
                    typ = DateTimeParser::UTC4;
                } else if (rest.startsWith(QLatin1String("uuu"))) {
                    typ = DateTimeParser::UTC3;
                } else if (rest.startsWith(QLatin1String("uu"))) {
                    typ = DateTimeParser::UTC2;
                }
                break;

            case 'Z':
                if (rest.startsWith(QLatin1String("ZZZZ"))) {
                    typ = DateTimeParser::Zone4;
                } else if (rest.startsWith(QLatin1String("ZZZ"))) {
                    typ = DateTimeParser::Zone3;
                }
                break;

            default: qFatal("Should never happen"); break;
            }

            if (typ != DateTimeParser::NoSection) {
                if (i == start) {
                    return FormatSection(start, typ);
                } else {
                    break; // found a separator before this section
                }
            }
        }
        ++i;
    }
    return FormatSection(start, str.mid(start, i - start));
}

void DateTimeParser::parseFormat(const QString &f)
{
    const char quote = '\'';
    display = 0;
    format = f;
    sect.clear();

    int i = 0;
    while (i < format.size()) {
        FormatSection s;
        if (format.at(i) == quote) {
            int nextQuote = format.indexOf(quote, i + 1);
            if (nextQuote == -1)
                nextQuote = format.size() + 1;
            s = FormatSection(i, format.mid(i, nextQuote - i + 1));
        } else {
            s = findNextFormat(format, i);
        }
        if (s.type == DateTimeParser::Separator && !sect.isEmpty() && \
sect.last().type == DateTimeParser::Separator) {  sect.last().chars += s.chars;
        } else {
            sect << s;
            display |= s.type;
        }
        i = s.index + s.length();
    }
}

QDateTime DateTimeParser::fromString(const QString &string)
{
    const char quote = '\'';
    int msec = -1;
    int sec = -1;
    int minute = -1;
    int hour = -1;
    int day = -1;
    int month = -1;
    int year = -1;
    int ampm = -1;
    int dayOfWeek = -1;
    int utcOff = -99999;
    zoneName = QString();
    zoneAbbrev = QString();
    utcOffset = 0;

    int index = 0;
    int i = 0;
    while (i<sect.size()) {
        if (index >= string.size()) {
            return QDateTime();
        }
        int *num = 0;
        QString (*nameFunction)(int) = 0;
        const char * const * nameArray = 0;
        int max = -1;
        int min = 1;
        const FormatSection &s = sect.at(i);
        switch (s.type) {
        case DateTimeParser::Separator: {
            QString sep = s.chars;
            sep.remove(quote);

            if (string.mid(index, sep.length()) != sep) {
                return QDateTime();
            }
            index += sep.size();
            break; }

        case DateTimeParser::APLower: {
        case DateTimeParser::APUpper:
            const QChar a = s.type == DateTimeParser::APLower ? QLatin1Char('a') : \
                QLatin1Char('A');
            const QChar p = s.type == DateTimeParser::APLower ? QLatin1Char('p') : \
                QLatin1Char('P');
            const QChar m = s.type == DateTimeParser::APLower ? QLatin1Char('m') : \
QLatin1Char('M');

            if ((string.at(index) != a && string.at(index) != p)
                || string.size() < index + 2
                || string.at(index + 1) != m) {
                return QDateTime();
            }
            int newampm = string.at(index) == a ? 0 : 1;
            if (ampm != -1 && newampm != ampm) {
                return QDateTime();
            }
            ampm = newampm;
            index += 2;
            break; }

#ifndef QT_NO_TEXTDATE
        case DateTimeParser::Day3: num = &day; nameFunction = &QDate::shortDayName; \
                nameArray = qt_shortDayNames; max = 7; break;
        case DateTimeParser::Day4: num = &day; nameFunction = &QDate::longDayName; \
                nameArray = qt_longDayNames; max = 7; break;
        case DateTimeParser::Month3: num = &month; nameFunction = \
                &QDate::shortMonthName; nameArray = qt_shortMonthNames; max = 12; \
                break;
        case DateTimeParser::Month4: num = &month; nameFunction = \
&QDate::longMonthName; nameArray = qt_longMonthNames; max = 12; break; #else
        case DateTimeParser::Day3: num = &day; max = 7; break;
        case DateTimeParser::Day4: num = &day; max = 7; break;
        case DateTimeParser::Month3: num = &month; max = 12; break;
        case DateTimeParser::Month4: num = &month; max = 12; break;
#endif

        case DateTimeParser::Day1: num = &day; max = 2; break;
        case DateTimeParser::Month1: num = &month; max = 2; break;
        case DateTimeParser::Hour1: num = &hour; max = 2; break;
        case DateTimeParser::Minute1: num = &minute; max = 2; break;
        case DateTimeParser::Second1: num = &sec; max = 2; break;
        case DateTimeParser::MSecond1: num = &msec; max = 3; break;
        case DateTimeParser::Day2: num = &day; min = 2; max = 2; break;
        case DateTimeParser::Month2: num = &month; min = 2; max = 2; break;
        case DateTimeParser::Year2: num = &year; min = 2; max = 2; break;
        case DateTimeParser::Hour2: num = &hour; min = 2; max = 2; break;
        case DateTimeParser::Minute2: num = &minute; min = 2; max = 2; break;
        case DateTimeParser::Second2: num = &sec; min = 2; max = 2; break;
        case DateTimeParser::MSecond3: num = &msec; min = 3; max = 3; break;
        case DateTimeParser::Year4: num = &year; min = 4; max = 4; break;

        case DateTimeParser::UTC2:
        case DateTimeParser::UTC3:
        case DateTimeParser::UTC4:
        {
            if (!zoneName.isEmpty() || !zoneAbbrev.isEmpty())
                return QDateTime();
            int sign;
            QChar ch = string[index++];
            if (ch == QLatin1Char('+'))
                sign = 1;
            else if (ch == QLatin1Char('-'))
                sign = -1;
            else
                return QDateTime();
            bool ok;
            int digits;
            int hours = getNumber(index, string, 2, 2, &ok, &digits);
            if (!ok || hours < -14 || hours > 14)
                return QDateTime();
            index += 2;
            int minutes = 0;
            switch (s.type)
            {
                case DateTimeParser::UTC2:
                    break;
                case DateTimeParser::UTC4:
                    if (index >= string.size() || string[index++] != \
QLatin1Char(':'))  return QDateTime();
                    // fall through to UTC3
                case DateTimeParser::UTC3:
                    minutes = getNumber(index, string, 2, 2, &ok, &digits);
                    if (!ok || minutes < 0 || minutes > 59)
                        return QDateTime();
                    index += 2;
                    break;
                default:
		    break;
            }
            minutes += hours * 60;
            minutes *= sign;
            if (utcOff != -99999 && utcOff != minutes)
                return QDateTime();
            utcOff = minutes;
            break;
        }
        case DateTimeParser::Zone3:
        {
            if (utcOff != -99999 || !zoneName.isEmpty())
                return QDateTime();
            int ix = index;
            while (index < string.size() && string[index].isLetterOrNumber())
                ++index;
            QString z = string.mid(ix, index - ix);
            if (!zoneAbbrev.isEmpty() && z != zoneAbbrev)
                return QDateTime();
            zoneAbbrev = z;
            break;
        }
        case DateTimeParser::Zone4:
        {
            if (utcOff != -99999 || !zoneAbbrev.isEmpty())
                return QDateTime();
            QRegExp rx("^[\\w/]*");    // allow alphanumerics, _, /
            if (string.indexOf(rx, index) < 0)
                return QDateTime();
            QString z = rx.capturedTexts()[0];
            if (!zoneName.isEmpty() && z != zoneName)
                return QDateTime();
            zoneName = z;
            index += z.size();
            break;
        }

        default:
            qWarning("%s:%d DateTimeParser::fromString() %d should never be called \
here", __FILE__, __LINE__, s.type);  return QDateTime();
        }

        if (nameFunction) {
            const QString rest = string.mid(index);
            int add = -1;
            int j;
            for (j=min; j<=max; ++j) {
                const QString tmp = nameFunction(j);
                if (rest.startsWith(tmp)) {
                    add = tmp.size();
                    break;
                }
                const QLatin1String tmp2(nameArray[j - 1]);
                if (rest.startsWith(tmp2)) {
                    add = int(strlen(tmp2.latin1()));
                    break;
                }
            }
            if (j > max || (*num != -1 && *num != j) || add == -1) {
                return QDateTime();
            }
            *num = j;
            index += add;
        } else if (num) {
            bool ok;
            int digits;
            int number = getNumber(index, string, min, max, &ok, &digits);
            if (!ok || !withinBounds(s.type, number) || (*num != -1 && *num != \
number)) {  return QDateTime();
            }

            *num = number;
            index += digits;
        }
        ++i;
    }
    if (index < string.size()) {
        return QDateTime();
    }

    if (month == -1)
        month = 1;
    if (year == -1)
        year = QDate::currentDate().year();
    if (dayOfWeek != -1) {
        if (day != -1) {
            QDate dt(year, month, day);
            if (dt.dayOfWeek() != dayOfWeek) {
                return QDateTime();
            }
        } else {
            QDate dt(year, month, 1);
            if (dt.dayOfWeek() < dayOfWeek) {
                dt = dt.addDays(dayOfWeek - dt.dayOfWeek());
            } else if (dt.dayOfWeek() > dayOfWeek) {
                dt = dt.addDays(7 + dayOfWeek - dt.dayOfWeek());
            }
            day = dt.day();
        }
    }
    if (day == -1)
        day = 1;
    if (hour == -1)
        hour = 0;
    if (minute == -1)
        minute = 0;
    if (sec == -1)
        sec = 0;
    if (msec == -1)
        msec = 0;
    if (ampm == 0){
        if (hour == 12) {
            hour = 0;
        } else if (hour > 12) {
            return QDateTime();
        }
    } else if (ampm == 1) {
        if (hour < 12) {
            hour += 12;
        } else if (hour > 12) {
            return QDateTime();
        }
    }

    QDateTime dt(QDate(year, month, day), QTime(hour, minute, sec, msec),
                 (utcOff == 0 ? Qt::UTC : Qt::LocalTime));
    if (!dt.isValid())
        return QDateTime();

    if (utcOff != -99999)
        utcOffset = utcOff;

    return dt;
}


["kdatetime.h" (text/x-c++hdr)]

/*
    This file is part of the KDE libraries
    Copyright (c) 2005 David Jarvie <software@astrojar.org.uk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

/** @file
 * Date/times with associated time zone
 * @author David Jarvie <software@astrojar.org.uk>.
 */

#ifndef _KDATETIME_H_
#define _KDATETIME_H_

#include <ktimezones.h>
#include "kdelibs_export.h"

class KDateTimePrivate;

/**
 * @short A class representing a date and time with an associated time zone
 *
 * Topics:
 *  - @ref intro
 *  - @ref manipulation
 *  - @ref compatibility
 *
 * @section intro Introduction
 *
 * The class KDateTime combines a date and time with support for an
 * associated time zone. When manipulating KDateTime objects, their time zones
 * are automatically taken into account.
 *
 * The time zones which KDateTime supports are:
 * - the UTC time zone
 * - a specified KTimezone object
 * - local clock time, using the current system time zone. In this case, if the
 *   system time zone changes, the UTC time for the instance will change
 *   correspondingly.
 *
 * To set the time zone to a given value use one of the setTimeZone() methods,
 * to get the time zone call timeZone(), isUTC() or isLocal().
 *
 * @section manipulation Date and Time Manipulation
 *
 * A KDateTime object can be created by passing a date and time in its
 * constructor, together with a time zone specification.
 *
 * If both the date and time are null, isNull() returns true.
 * If both the date and the time are valid, isValid() returns true.
 *
 * A KDateTime object can be converted to QDateTime by using toUTC() or
 * toLocal(), or to a UNIX time stamp since 1st January 1970 by toTime_t().
 * There is no facility in this class to convert to another KTimezone: use
 * KTimezone::convert() to do this.
 *
 * The date and time can be set either in the constructor, or afterwards by
 * calling setDate() and setTime(). date() and time() return the date and time.
 *
 * You can increment or decrement the date/time using addSecs(), addDays(),
 * addMonths() and addYears(). The interval between two date/time values can
 * be found using secsTo() or daysTo().
 *
 * The comparison operators (operator==(), operator<(), etc.) all take the time
 * zone properly into account; if the two KDateTime objects have different time
 * zones, they are first converted to UTC before the comparison is performed.
 *
 * @section compatibility QDateTime Compatibility
 *
 * KDateTime's interface is designed to be as compatible as possible with that
 * of QDateTime, but with adjustments to cater for time zone handling. Because
 * QDateTime lacks virtual methods, KDateTime is not inherited from QDateTime,
 * but instead is implemented using a private QDateTime object.
 * @todo maybe other notes here?
 *
 * @see KTimezone, KSystemTimezones, QDateTime, QDate, QTime
 * @author David Jarvie \<software@astrojar.org.uk\>.
 * @since 4.0
 */
class KDECORE_EXPORT KDateTime
{
  public:
    /**
     * Constructs an invalid date/time using local clock time.
     */
    KDateTime();

    /**
     * Constructs a date/time with associated time zone. The time is
     * set to 00:00:00.
     *
     * @param date date in the time zone @p tz
     * @param tz   time zone
     */
    KDateTime(const QDate &date, const KTimezone *tz);

    /**
     * Constructs a date/time with associated time zone.
     *
     * @param date date in the time zone @p tz
     * @param time time in the time zone @p tz
     * @param tz   time zone
     */
    KDateTime(const QDate &date, const QTime &time, const KTimezone *tz);

    /**
     * Constructs a date/time with associated time zone.
     * If @p dt is specified as a UTC time (i.e. @c dt.timeSpec() is @c Qt::UTC),
     * it is first converted to local time in time zone @p tz before being stored.
     *
     * @param dt date and time
     * @param tz time zone
     */
    KDateTime(const QDateTime &dt, const KTimezone *tz);

    /**
     * Constructs a date/time expressed in either UTC or local clock time. The
     * time component is set to 00:00:00.
     *
     * @param date date in the time zone indicated by @p spec
     * @param spec @c Qt::UTC to use UTC time zone, or @c Qt::LocalTime to use
     *             local clock time
     */
    explicit KDateTime(const QDate &date, Qt::TimeSpec spec = Qt::LocalTime);

    /**
     * Constructs a date/time expressed in either UTC or local clock time.
     *
     * @param date date in the time zone indicated by @p spec
     * @param time time in the time zone indicated by @p spec
     * @param spec @c Qt::UTC to use UTC time zone, or @c Qt::LocalTime to use
     *             local clock time
     */
    KDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec = Qt::LocalTime);

    /**
     * Constructs a date/time expressed in either UTC or local clock time.
     * If @p dt is given with a different time specification than @p spec (one
     * of @p spec and @c dt.timeSpec() is @c Qt::UTC, and the other is
     * @c Qt::LocalTime), @p dt is first converted to either UTC or local time
     * (as given by @p spec) before being stored. The conversion is done using
     * the current system time zone.
     *
     * @param dt   date and time
     * @param spec @c Qt::UTC to use UTC time zone, or @c Qt::LocalTime to use
     *             local clock time
     */
    explicit KDateTime(const QDateTime &dt, Qt::TimeSpec spec = Qt::LocalTime);

    KDateTime(const KDateTime &other);
    ~KDateTime();

    KDateTime &operator=(const KDateTime &other);

    /**
     * Returns whether the date/time is null.
     *
     * @return @c true if both date and time are null, else @c false
     * @see isValid(), QDateTime::isNull()
     */
    bool isNull() const;

    /**
     * Returns whether the date/time is valid.
     *
     * @return @c true if both date and time are valid, else @c false
     * @see isNull(), QDateTime::isValid()
     */
    bool isValid() const;

    /**
     * Returns the date part of the date/time. The value returned should be
     * interpreted in terms of the instance's time zone.
     *
     * @return date value
     * @see time(), dateTime()
     */
    QDate date() const;

    /**
     * Returns the time part of the date/time. The value returned should be
     * interpreted in terms of the instance's time zone.
     *
     * @return time value
     * @see date(), dateTime()
     */
    QTime time() const;

    /**
     * Returns the date/time component of the instance, ignoring the time
     * zone. The value returned should be interpreted in terms of the
     * instance's time zone.
     *
     * @return date/time
     * @see date(), time()
     */
    QDateTime dateTime() const;

    /**
     * Returns the time zone for the date/time. If the date/time is specified
     * as a UTC time, a UTC time zone is always returned.
     *
     * @return time zone, or null if a local clock time
     * @see isUTC(), isLocal()
     */
    const KTimezone *timeZone() const;

    /**
     * Returns whether the date/time is a local clock time.
     *
     * @return @c true if local clock time
     * @see isUTC(), timeZone()
     */
    bool isLocal() const;

    /**
     * Returns whether the date/time is a UTC time.
     *
     * @return @c true if UTC
     * @see isLocal(), timeZone()
     */
    bool isUTC() const;

    /**
     * Returns the time converted to UTC.
     *
     * @return converted time
     * @see toLocal(), toTime_t(), KTimezone::convert()
     */
    QDateTime toUTC() const;

    /**
     * Returns the time converted to the local clock time.
     *
     * @return converted time
     * @see toUTC(), KTimezone::convert()
     */
    QDateTime toLocal() const;

    /**
     * Converts the time to a UTC time, measured in seconds since 00:00:00 UTC
     * 1st January 1970 (as returned by time(2)).
     *
     * @return converted time, or -1 if the date is out of range for time_t
     * @see setTime_t()
     */
    uint toTime_t() const;

    /**
     * Sets the date part of the date/time.
     *
     * @param date new date value
     * @see date(), setTime(), setTimeZone(), setTime_t()
     */
    void setDate(const QDate &date);

    /**
     * Sets the time part of the date/time.
     *
     * @param time new time value
     * @see time(), setDate(), setTimeZone(), setTime_t()
     */
    void setTime(const QTime &time);

    /**
     * Sets the date/time part of the instance, leaving the time zone unaffected.
     * If @p dt is a local time (\code dt.timeSpec() == Qt::LocalTime \endcode)
     * and the instance is either UTC or has a specified time zone, or if @p dt
     * is UTC and the instance is in local clock time, @p dt is first converted
     * to the instance's time zone or local time (as appropriate) before being
     * stored. If converting to or from local time, the conversion is done using
     * the current system time zone.
     *
     * @param dt date and time
     */
    void setDateTime(const QDateTime &dt);

    /**
     * Sets the stored time to be expressed as either UTC or local clock time.
     * Any previous time zone is forgotten. The stored time value is left
     * unchanged, so that if the time zone or UTC/local clock time indicator has
     * changed, it will now represent a different UTC time.
     *
     * @param spec @c Qt::UTC to use UTC time zone, or @c Qt::LocalTime to use
     *             local clock time
     * @see timeZone(), setTimeZone(const KTimezone*)
     */
    void setTimeZone(Qt::TimeSpec spec);

    /**
     * Sets the time zone in which the date/time is expressed.
     * The stored time value is left unchanged, so that if the time zone has
     * changed, it will now represent a different UTC time.
     *
     * To set the time zone to UTC or to local time, use setTimeZone(Qt::TimeSpec).
     *
     * @param tz new time zone, or null to change to local clock time
     * @see timeZone(), setTimeZone(Qt::TimeSpec)
     */
    void setTimeZone(const KTimezone *tz);

    /**
     * Sets the time to a UTC time, measured in seconds since 00:00:00 UTC
     * 1st January 1970 (as returned by time(2)). If the KDateTime instance is
     * expressed in either a time zone or as local clock time, the UTC time is
     * first converted to the instance's time zone (the current system time
     * zone if using local clock time) before being stored.
     *
     * @param seconds UTC time, measured in seconds since 00:00:00 UTC
     *                1st January 1970 (as returned by time(2))
     * @see setTime(), setDate(), toTime_t()
     */
    void setTime_t(uint seconds);

    /**
     * Returns a date/time @p secs seconds later than the stored date/time.
     * The calculation is done in UTC to ensure that clock changes (e.g. daylight
     * savings) in the time zpme do not affect the result. The result is
     * expressed in the same time zone as the original instance.
     *
     * @return resultant date/time
     * @see addDays(), addMonths(), addYears(), secsTo()
     */
    KDateTime addSecs(int secs) const;

    /**
     * Returns a date/time @p days days later than the stored date/time.
     * The result is expressed in the same time zone as the original instance.
     *
     * @return resultant date/time
     * @see addSecs(), addMonths(), addYears(), daysTo()
     */
    KDateTime addDays(int days) const;

    /**
     * Returns a date/time @p months months later than the stored date/time.
     * The result is expressed in the same time zone as the original instance.
     *
     * @return resultant date/time
     * @see addSecs(), addDays(), addYears(), daysTo()
     */
    KDateTime addMonths(int months) const;

    /**
     * Returns a date/time @p years years later than the stored date/time.
     * The result is expressed in the same time zone as the original instance.
     *
     * @return resultant date/time
     * @see addSecs(), addDays(), addMonths(), daysTo()
     */
    KDateTime addYears(int years) const;

    /**
     * Calculates the number of days from this date/time to the @p other date/time.
     * In calculating the result, @p other is first converted to this instance's
     * time zone. The number of days difference is then calculated ignoring
     * the time parts of the two date/times. For example, if this date/time
     * was 13:00 on 1 January 2000, and @p other was 02:00 on 2 January 2000,
     * the result would be 1.
     *
     * @param other other date/time
     * @return number of days difference
     * @see secsTo(), addDays()
     */
    int daysTo(const KDateTime &other) const;

    /**
     * Returns the number of seconds from this date/time to the @p other date/time.
     * Before performing the comparison, the two datetimes are converted to UTC
     * to ensure that the result is correct if one of the two datetimes has
     * daylight saving time (DST) and the other doesn't.
     *
     * @param other other date/time
     * @return number of seconds difference
     * @see addSecs(), daysTo()
     */
    int secsTo(const KDateTime &other) const;

    /**
     * Returns the date/time as a string. The @p format parameter determines the
     * format of the result string. The @p format codes used for the date and time
     * components are those defined for QDateTime::toString(). For the time zone
     * component, the following codes may be used:
     *
     * ZZZ  - the abbreviated time zone code, e.g. UTC, EDT, BST.
     * ZZZZ - the name of the time zone, e.g. Europe/London. This is system dependent.
     * uu   - the UTC offset of the time zone in hours, e.g. -02. If the offset
     *        is not a whole number of hours, the output is the same as for "uuu".
     * uuu  - the UTC offset of the time zone in hours and minutes, e.g. -0200.
     * uuuu - the UTC offset of the time zone in hours and minutes, e.g. +02:00.
     *
     * Note that only one of these codes may be used.
     *
     * @param format format for the string
     * @return formatted string
     * @see fromString(), QDateTime::toString()
     */
    QString toString(const QString &format) const;

    /**
     * Returns the date/time as a string. The @p format parameter determines the
     * format of the result string. The result string is that returned by
     * QDateTime::toString(@p format), with the time zone offset appended. The
     * time zone offset format depends on both the date/time value and the
     * @p format parameter, as follows:
     * - blank if the date/time value is local clock time
     * - 'Z' if the date/time value is UTC and the format is Qt::ISODate
     * - ±hhmm otherwise.
     *
     * @param format Qt::ISODate, Qt::TextDate or Qt::LocalDate. See
     *               QDateTime::toString() description for details.
     * @return formatted string
     * @see fromString(), QDateTime::toString()
     */
    QString toString(Qt::DateFormat format = Qt::ISODate) const;

    /**
     * Returns the QDateTime represented by @p string, using the @p format given.
     * The permissible @p format codes are:
     * - @c Qt::ISODate:  ISO 8601 format YYYY-MM-DDThh:mm:ssTZ, where TZ is:
     *                    -- blank for local time
     *                    -- Z for UTC
     *                    -- ±hh[[:]mm] to specify an offset from UTC.
     *                    If a local time is specified, the QDateTime value
     *                    returned is a local clock time. Otherwise, the value
     *                    returned is a UTC time. (If the string contains an
     *                    offset from UTC, this cannot be converted to a
     *                    KTimezone since there is no unique correspondence
     *                    between a UTC offset at a single moment in time and
     *                    a time zone. So the specified time is adjusted to UTC
     *                    and that value is returned.)
     * - @c Qt::TextDate: default Qt format. This can only be used to specify a
     *                    local time. An example is "Wed May 20 03:40:13 1998".
     *
     * This method is the inverse of toString(Qt::DateFormat), except that it
     * can only return a UTC or local clock time. Time zone information cannot
     * be returned since an offset from UTC cannot be converted unambiguously
     * to a time zone since there is no unique correspondence between
     *
     * @param string string to convert
     * @param format format code
     * @return QDateTime value as either a UTC or local clock time, or an
     *         invalid QDateTime if either parameter is invalid
     * @see toString(), QString::fromString()
     */
    static QDateTime fromString(const QString &string, Qt::DateFormat format = Qt::ISODate);

    /**
     * Returns the QDateTime represented by @p string, using the @p format given.
     * The @p format codes are the same as those for toString(), but time zone
     * names (codes ZZZ and ZZZZ) are not allowed since they cannot be
     * interpreted. Any UTC offset is used to adjust the resultant QDateTime. If
     * a UTC offset is present, the time spec of the result will be @c Qt::UTC;
     * otherwise the result will be @c Qt::LocalTime.
     *
     * @param string string to convert
     * @param format format string
     * @return QDateTime value, or an invalid QDateTime if either parameter is
     *         invalid
     * @see toString()
     */
    static QDateTime fromString(const QString &string, const QString &format);

    /**
     * Returns the KDateTime represented by @p string, using the @p format
     * given, and using a specified time zone collection as the source of
     * time zone definitions. The @p format codes are the same as those for
     * toString(). Only one time zone or UTC offset code may be used.
     *
     * If any time zone information is present in the string, the function
     * attempts to find a matching time zone in the @p zones collection. A time
     * zone name (format code ZZZZ) will provide an unambiguous look up in
     * @p zones. Any other type of time zone information (an abbreviated time
     * zone code (ZZZ) or UTC offset (uu, uuu, uuuu) is searched for in 
     * @p zones and if only one time zone is found to match, the result is set
     * to that zone. If more than one match is found, the action taken is
     * determined by @p utcIfAmbiguous: if @p utcIfAmbiguous is true and
     * a UTC offset is specified, a UTC time will be returned; otherwise an
     * invalid KDateTime is returned. If the time zone information does not
     * match any of the time zones in @p zones, an invalid KDateTime is returned.
     *
     * If no time zone information is present in the string, a local clock time
     * is returned.
     *
     * @param string string to convert
     * @param format format string
     * @param zones time zone collection 
     * @return KDateTime value, or an invalid KDateTime if a parameter is
     *         invalid, if time zone information doesn't match any in @p zones,
     *         or if the time zone information is ambiguous and @p utcIfAmbiguous
     *         is false
     * @see toString()
     */
    static KDateTime fromString(const QString &string, const QString &format,
                                const KTimezones &zones, bool utcIfAmbiguous = false);

    /**
     * Check whether this date/time is simultaneous with another.
     * The comparison takes time zones into account; if the two instances have
     * different time zones, they are first converted to UTC before comparing.
     *
     * @return @c true if the two instances represent the same time, @c false otherwise
     */
    bool operator==(const KDateTime &other) const;
    bool operator!=(const KDateTime &other) const { return !(*this == other); }

    /**
     * Check whether this date/time is earlier than another.
     * The comparison takes time zones into account; if the two instances have
     * different time zones, they are first converted to UTC before comparing.
     *
     * @return @c true if this instance represents an earlier time than @p other,
     *         @c false otherwise
     */
    bool operator<(const KDateTime &other) const;
    bool operator<=(const KDateTime &other) const { return !(other < *this); }
    bool operator>(const KDateTime &other) const { return other < *this; }
    bool operator>=(const KDateTime &other) const { return !(*this < other); }

    friend QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime);
    friend QDataStream & operator>>(QDataStream &in, KDateTime &dateTime);

  private:
    KDateTimePrivate *d;
};

#if 0
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime);
QDataStream & operator>>(QDataStream &in, KDateTime &dateTime);
#endif

#endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic