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

List:       kde-core-devel
Subject:    Proposed new KDateTime class
From:       David Jarvie <lists () astrojar ! org ! uk>
Date:       2005-11-08 22:00:28
Message-ID: 200511082200.28776.lists () astrojar ! org ! uk
[Download RAW message or body]

Now that the time zone classes have been updated, there is a need to be able 
to handle date/times which have an associated time zone. I attach a proposed 
new kdecore class, KDateTime, which represents a date/time with an associated 
time zone. The aim is to make time zone handling as automatic as possible 
when manipulating dates and times. Its interface is very similar to 
QDateTime, but it is not inherited from QDateTime mainly because QDateTime's 
methods are not virtual.

The code compiles, but I until I finish the test program is untested. Note 
that if the new class is committed, the time zone classes will need to be 
amended to handle the new class.

Comments please. (Note that I am going away and won't be able to respond for a 
few days.)

-- 
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 <QDateTime>
#include <kdebug.h>
#include <kdatetime.h>


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::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);
    }
}

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

void KDateTime::setTimeSpec(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 secsSince1Jan1970UTC)
{
    QDateTime dt;
    dt.setTime_t(secsSince1Jan1970UTC);
    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());
}

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();
}

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); }

["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;


/**
 * The KDateTime class represents a date/time with an associated time zone.
 *
 * The associated time zone has three possibilities:
 * - a UTC time zone
 * - a specified KTimezone
 * - a local clock time, using the current system time zone. If the system
 *   time zone changes, the UTC time for the instance will change
 *   correspondingly.
 *
 * @short A date/time with an associated time zone
 * @see KTimezone
 * @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, or null to use local clock time
     */
    explicit KDateTime(const QDate &date, const KTimezone *tz = 0);

    /**
     * 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, or null to use local clock time
     */
    KDateTime(const QDate &date, const QTime &time, const KTimezone *tz = 0);

    /**
     * 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 before being stored. The conversion is
     * done using the supplied timezone @p tz, or if that is null, using the
     * current system time zone.
     *
     * @param dt date and time
     * @param tz time zone, or null to use local clock time
     */
    explicit KDateTime(const QDateTime &dt, const KTimezone *tz = 0);

    /**
     *
     * @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
     */
    KDateTime(const QDate &date, Qt::TimeSpec spec);

    /**
     * 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);

    /**
     * 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 date date and time
     * @param spec @c Qt::UTC to use UTC time zone, or @c Qt::LocalTime to use
     *             local clock time
     */
    KDateTime(const QDateTime &dt, Qt::TimeSpec spec);

    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
     */
    bool isNull() const;

    /**
     * Returns whether the date/time is valid.
     *
     * @return @c true if both date and time are valid, else @c false
     */
    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
     */
    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
     */
    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
     */
    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
     */
    const KTimezone *timeZone() const;

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

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

    /**
     * Converts the time to a UTC time.
     *
     * @return converted time 
     */
    QDateTime toUTC() 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 or
     *         @p utcDateTime.timeSpec() is not Qt::UTC 
     */
    uint toTime_t() const;

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

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

    /**
     * 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
     */
    void setTimeSpec(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.
     *
     * @param tz new time zone, or null to change to local clock time
     */
    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 secsSince1Jan1970UTC UTC time, measured in seconds since 00:00:00 UTC
     *                             1st January 1970 (as returned by time(2))
     */
    void setTime_t(uint secsSince1Jan1970UTC);

    /**
     * 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
     */
    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
     */
    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
     */
    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
     */
    KDateTime addYears(int years) const;

    /**
     * Calculates the number of days from this date/time to @p dt2.
     * In calculating the result, @p dt2 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 dt2 was 02:00 on 2 January 2000,
     * the result would be 1.
     *
     * @return number of days difference
     */
    int daysTo(const KDateTime &dt2) const;

    /**
     * Returns the number of seconds from this datetime to @p dt2.
     * 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 dt2 other date/time
     * @return number of seconds difference
     */
    int secsTo(const KDateTime &dt2) const;

    /**
     * Check whether this date/time is simultaneous with another.
     * Before comparing the instances, they are converted to the same time zone.
     *
     * @return @c true if the two instances represent the same time, @c false otherwise
     */
    bool operator==(const KDateTime &other) const;
    inline bool operator!=(const KDateTime &other) const { return !(*this == other); }

    /**
     * Check whether this date/time is earlier than another.
     * Before comparing the instances, they are converted to the same time zone.
     *
     * @return @c true if the this instance represent an earlier time than @p other,
     *         @c false otherwise
     */
    bool operator<(const KDateTime &other) const;
    inline bool operator<=(const KDateTime &other) const { return !(other < *this); }
    inline bool operator>(const KDateTime &other) const { return other < *this; }
    inline bool operator>=(const KDateTime &other) const { return !(*this < other); }

  private:
    KDateTimePrivate *d;
};

#endif


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

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