summaryrefslogtreecommitdiffstats
path: root/libkdeedu/extdate/extdatetime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkdeedu/extdate/extdatetime.cpp')
-rw-r--r--libkdeedu/extdate/extdatetime.cpp1148
1 files changed, 1148 insertions, 0 deletions
diff --git a/libkdeedu/extdate/extdatetime.cpp b/libkdeedu/extdate/extdatetime.cpp
new file mode 100644
index 00000000..36e3860d
--- /dev/null
+++ b/libkdeedu/extdate/extdatetime.cpp
@@ -0,0 +1,1148 @@
+/*************************************************************************
+** Definition of extended range date classe
+** (c) 2004 by Michel Guitel <michel.guitel@sap.ap-hop-paris.fr>
+** modifications by Jason Harris <kstars@30doradus.org>
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+**********************************************************************/
+
+#include "extdatetime.h"
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <assert.h>
+#include <time.h>
+
+static const uint SECS_PER_DAY = 86400;
+static const uint MSECS_PER_DAY = 86400000;
+static const uint SECS_PER_HOUR = 3600;
+static const uint MSECS_PER_HOUR= 3600000;
+static const uint SECS_PER_MIN = 60;
+static const uint MSECS_PER_MIN = 60000;
+
+/*****************************************************************************
+ ExtDate class
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Concepts :
+ * a date is represented internally by its Julian Day number, a simple count
+ * of the number of days since a remote, arbitrary date (01 January, 4713 BC).
+ * This date has Julian Day number zero.
+ *
+ * ***************************************************************************/
+
+uint ExtDate::m_monthLength[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+uint ExtDate::m_monthOrigin[] = { 0, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+QString ExtDate::m_shortMonthNames[12] = {
+ i18n("Short month name", "Jan"), i18n("Short month name", "Feb"),
+ i18n("Short month name", "Mar"), i18n("Short month name", "Apr"),
+ i18n("Short month name", "May"), i18n("Short month name", "Jun"),
+ i18n("Short month name", "Jul"), i18n("Short month name", "Aug"),
+ i18n("Short month name", "Sep"), i18n("Short month name", "Oct"),
+ i18n("Short month name", "Nov"), i18n("Short month name", "Dec")
+};
+QString ExtDate::m_shortDayNames[7] = {
+ i18n("Short day name", "Mon"), i18n("Short day name", "Tue"),
+ i18n("Short day name", "Wed"), i18n("Short day name", "Thu"),
+ i18n("Short day name", "Fri"), i18n("Short day name", "Sat"),
+ i18n("Short day name", "Sun")
+};
+QString ExtDate::m_longMonthNames[12] = {
+ i18n("Long month name", "January"), i18n("Long month name", "February"),
+ i18n("Long month name", "March"), i18n("Long month name", "April"),
+ i18n("Long month name", "May"), i18n("Long month name", "June"),
+ i18n("Long month name", "July"), i18n("Long month name", "August"),
+ i18n("Long month name", "September"), i18n("Long month name", "October"),
+ i18n("Long month name", "November"), i18n("Long month name", "December")
+};
+QString ExtDate::m_longDayNames[7] = {
+ i18n("Long day name", "Monday"), i18n("Long day name", "Tuesday"),
+ i18n("Long day name", "Wednesday"), i18n("Long day name", "Thursday"),
+ i18n("Long day name", "Friday"), i18n("Long day name", "Saturday"),
+ i18n("Long day name", "Sunday")
+};
+
+ExtDate::ExtDate( int y, int m, int d)
+{
+ if ( !isValid(y,m,d) ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "ExtDate: Invalid date %04d-%02d-%02d", y, m, d );
+#endif
+ m_year = 0;
+ m_month = 0;
+ m_day = 0;
+ m_jd = INVALID_DAY;
+ } else {
+ m_year = y;
+ m_month = m;
+ m_day = d;
+ m_jd = GregorianToJD(y, m, d);
+ }
+}
+
+ExtDate::ExtDate( long int jd ) {
+ m_jd = jd;
+ JDToGregorian( jd, m_year, m_month, m_day );
+}
+
+long int ExtDate::GregorianToJD( int year, int month, int day )
+{
+ int m, y, A, B, C, D;
+
+ if (month > 2) {
+ m = month;
+ y = year;
+ } else {
+ y = year - 1;
+ m = month + 12;
+ }
+
+/* If the date is after 10/15/1582, then take Pope Gregory's modification
+ to the Julian calendar into account */
+
+ if ( ( year >1582 ) ||
+ ( year ==1582 && month >9 ) ||
+ ( year ==1582 && month ==9 && day >15 ))
+ {
+ A = int(y/100);
+ B = 2 - A + int(A/4);
+ } else {
+ B = 0;
+ }
+
+ if (y < 0) {
+ C = int((365.25*y) - 0.75);
+ } else {
+ C = int(365.25*y);
+ }
+
+ D = int(30.6001*(m+1));
+
+ long int jd = B + C + D + day + 1720995;
+
+ return jd;
+}
+
+void ExtDate::JDToGregorian( long int jd, int &year, int &month, int &day )
+{
+ int a, b, c, d, e, alpha;
+
+ if (jd<2299161) {
+ a = jd;
+ } else {
+ alpha = int ((jd-1867216.25)/ 36524.25);
+ a = jd + 1 + alpha - int(alpha / 4.0);
+ }
+ b = a + 1524;
+ c = int ((b-122.1)/ 365.25);
+ d = int (365.25*c);
+ e = int ((b-d)/ 30.6001);
+
+ day = b-d-int(30.6001*e);
+ month = (e<14) ? e-1 : e-13;
+ year = (month>2) ? c-4716 : c-4715;
+}
+
+bool ExtDate::isValid() const
+{
+ return ( jd() != INVALID_DAY && isValid( year(), month(), day() ) );
+}
+
+int ExtDate::dayOfWeek() const
+{
+ //JD 2451545 (01 Jan 2000) was a Saturday, which is dayOfWeek=6.
+ int a_day = (( jd() - 2451545 + 6 ) % 7);
+ if ( a_day < 0 ) a_day += 7;
+ return (a_day == 0) ? 7 : a_day;
+}
+
+int ExtDate::dayOfYear() const
+{
+ return jd() - GregorianToJD( year(), 1, 1) + 1;
+}
+
+int ExtDate::daysInMonth() const
+{
+ if ( isValid() ) {
+ int m = month();
+ int d = m_monthLength[m-1];
+ if (m==2 && leapYear(year())) d++;
+ return d;
+ } else {
+ return 31;
+ }
+}
+
+int ExtDate::daysInYear() const
+{
+ if ( ! isValid() ) return 365;
+ return (leapYear(year()) ? 366 : 365);
+}
+
+int ExtDate::weekNumber( int *yearNum ) const
+{
+ //ISO 8601:
+ //Week 1 is the week containing the first Thursday of the year.
+ ExtDate day1( year(), 1, 1 ); //First day of the year
+
+ if ( day1.dayOfWeek() > 4 ) {
+ //Jan 1 is after Thursday, so it's in the previous year's last week.
+ //Set day1 to be the following Monday, which is the start of week 1
+ day1 = day1.addDays( 7 - day1.dayOfWeek() + 1 );
+ } else {
+ //Jan 1 is before Friday, so it is in Week 1.
+ //Set day1 to be the preceding Monday
+ day1 = day1.addDays( 1 - day1.dayOfWeek() );
+ }
+
+ //Is the target date prior to day1? If so, the target is in the
+ //last week of the previous year.
+ if ( day1.daysTo( *this ) < 0 ) {
+ if ( yearNum ) *yearNum = year() - 1;
+
+ //The last week of the year always contains Dec 28th (ISO 8601)
+ ExtDate lastDec28( year()-1, 12, 28 );
+ return lastDec28.weekNumber();
+ }
+
+ //If the target date is after Dec 28th, it's possible that it is in
+ //Week 1 of the following year.
+ ExtDate dec28( year(), 12, 28 );
+ if ( dayOfYear() > dec28.dayOfYear() && dayOfWeek() < 4 ) {
+ if ( yearNum ) *yearNum = year() + 1;
+ return 1;
+ }
+
+ //If we reach here, the week number will be in this year.
+ int week = 1 + int( day1.daysTo( *this )/7 );
+
+ if ( yearNum ) *yearNum = year();
+ return week;
+}
+
+#ifndef QT_NO_TEXTDATE
+QString ExtDate::shortMonthName( int month ) {return m_shortMonthNames[month-1];}
+QString ExtDate::shortDayName( int weekday ) {return m_shortDayNames[weekday-1];}
+QString ExtDate::longMonthName( int month ) {return m_longMonthNames[month-1];}
+QString ExtDate::longDayName( int weekday ) {return m_longDayNames[weekday-1];}
+#endif //QT_NO_TEXTDATE
+
+#ifndef QT_NO_TEXTSTRING
+#if !defined(QT_NO_SPRINTF)
+QString ExtDate::toString( Qt::DateFormat f) const
+{
+ QString a_format;
+
+ if ( ! isValid() ) return QString::null;
+
+ switch (f)
+ {
+ case Qt::TextDate : // Sat May 20 1995
+ a_format = "%a %b %e %Y";
+ break;
+
+ case Qt::ISODate : // YYYY-MM-DD
+ a_format = "%Y-%m-%d";
+ break;
+
+ case Qt::LocalDate : // local settings
+ a_format = KGlobal::locale()->dateFormat();
+ break;
+
+ default :
+ a_format = "toString : unknown format";
+ break;
+
+ }
+ return toString(a_format);
+}
+#endif
+
+QString ExtDate::toString( const QString& format ) const
+{
+ if ( ! isValid() ) return QString::null;
+
+ //We use the KDE Date format specs.
+ //Replace occurences of the following tokens with their
+ //corresponding values:
+ //
+ // %Y The year, including centuries prefix (e.g., "1984")
+ // %y The year, excluding centuries prefix (e.g., "84")
+ // %n Numerical month value (e.g., "3" for March)
+ // %m Numerical month value, two digits (e.g., "03" for March)
+ // %e Numerical day value (e.g., "3" on March 3rd)
+ // %d Numerical day value, two digits (e.g., "03" on March 3rd)
+ // %b Month name, short form (e.g., "Mar" for March)
+ // %B Month name, long form (e.g., "March")
+ // %a Weekday name, short form (e.g., "Wed" for Wednesday)
+ // %A Weekday name, long form (e.g., "Wednesday")
+
+ //All other characters are left as-is.
+
+ QString result( format );
+
+ result.replace( "%Y", QString().sprintf( "%d", year() ) );
+ result.replace( "%y", QString().sprintf( "%02d", (year() % 100) ) );
+ result.replace( "%n", QString().sprintf( "%d", month() ) );
+ result.replace( "%m", QString().sprintf( "%02d", month() ) );
+ result.replace( "%e", QString().sprintf( "%d", day() ) );
+ result.replace( "%d", QString().sprintf( "%02d", day() ) );
+ result.replace( "%b", shortMonthName( month() ) );
+ result.replace( "%B", longMonthName( month() ) );
+ result.replace( "%a", shortDayName( dayOfWeek() ) );
+ result.replace( "%A", longDayName( dayOfWeek() ) );
+
+ return result;
+}
+#endif
+
+bool ExtDate::setYMD( int y, int m, int d )
+{
+ if ( ! isValid(y,m,d) ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "ExtDate: Invalid date %04d-%02d-%02d", y, m, d );
+#endif
+ m_year = 0;
+ m_month = 0;
+ m_day = 0;
+ m_jd = INVALID_DAY;
+ return false;
+ } else {
+ m_year = y;
+ m_month = m;
+ m_day = d;
+ m_jd = GregorianToJD( y, m, d );
+ return true;
+ }
+}
+
+bool ExtDate::setJD( long int _jd ) {
+ if ( _jd == INVALID_DAY ) {
+ m_jd = _jd;
+ m_year = 0;
+ m_month = 0;
+ m_day = 0;
+ return false;
+ } else {
+ m_jd = _jd;
+ JDToGregorian( _jd, m_year, m_month, m_day );
+ return true;
+ }
+}
+
+ExtDate ExtDate::addDays( int days ) const
+{
+ ExtDate a_date;
+ a_date.setJD( jd() + days );
+ return a_date;
+}
+
+ExtDate ExtDate::addMonths( int months ) const
+{
+ int a_month = month() + months%12;
+ int a_year = year() + int(months/12);
+
+ while ( a_month < 1 ) {
+ a_month += 12;
+ a_year--;
+ }
+
+ while ( a_month > 12 ) {
+ a_month -= 12;
+ a_year++;
+ }
+
+ return ExtDate(a_year, a_month, day());
+}
+
+ExtDate ExtDate::addYears( int years ) const
+{
+ return ExtDate(year() + years, month(), day());
+}
+
+int ExtDate::daysTo( const ExtDate & a_date) const
+{
+ return a_date.jd() - jd();
+}
+
+ExtDate ExtDate::currentDate(Qt::TimeSpec ts)
+{
+ time_t a_current_time;
+ struct tm a_current_time_tm;
+
+ time(&a_current_time);
+ switch (ts)
+ {
+ case Qt::LocalTime :
+ localtime_r(&a_current_time, &a_current_time_tm);
+ break;
+
+ case Qt::UTC :
+ gmtime_r(&a_current_time, &a_current_time_tm);
+ break;
+
+ default :
+ assert(0);
+ break;
+ }
+ return ExtDate(a_current_time_tm.tm_year + 1900, a_current_time_tm.tm_mon + 1, a_current_time_tm.tm_mday);
+}
+
+#ifndef QT_NO_DATESTRING
+//Try both DateFormat values
+ExtDate ExtDate::fromString( const QString& s )
+{
+ ExtDate dResult = ExtDate::fromString( s, Qt::TextDate );
+ if ( dResult.isValid() ) return dResult;
+
+ dResult = ExtDate::fromString( s, Qt::ISODate );
+ if ( dResult.isValid() ) return dResult;
+ else return ExtDate(); //invalid
+}
+
+ExtDate ExtDate::fromString( const QString& s, Qt::DateFormat f )
+{
+ ExtDate dt = ExtDate(); //initialize invalid date
+ if ( s.isEmpty() ) { return dt; }
+ if ( f == Qt::LocalDate ) { //can't use LocalFormat
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QDate::fromString: Parameter out of range" );
+#endif
+ return dt;
+ }
+
+ switch( f ) {
+ case Qt::ISODate :
+ {
+ int year( s.mid( 0, 4 ).toInt() );
+ int month( s.mid( 5, 2 ).toInt() );
+ int day( s.mid( 8, 2 ).toInt() );
+
+ if ( year && month && day )
+ return ExtDate( year, month, day );
+ }
+ break;
+
+ default :
+#ifndef QT_NO_TEXTDATE
+ case Qt::TextDate :
+ {
+ //Three possible date formats:
+ //dd mth yyyy; mth dd yyyy; wkd mth dd yyyy
+ //"mth" is the word for the month (long or short form)
+ QStringList ss = QStringList::split( " ", s );
+ bool ok = false;
+ int month = -1;
+ uint imonth = 0;
+ uint iyear = 0;
+
+ //If neither of the first two words is a number, then we'll assume
+ //the first word is a superfluous "weekday" string
+ int day = ss[0].toInt( &ok );
+ if ( ! ok ) {
+ day = ss[1].toInt( &ok );
+ if ( ! ok ) {
+ day = ss[2].toInt( &ok );
+ if ( !ok ) return dt; //could not find a valid day number in first three words
+ imonth = 1; //the month must be the second word
+ iyear = 3; //the year must be the fourth word
+ } else {
+ //the month is either the first word, or the third.
+ imonth = 0;
+ iyear = 2;
+ }
+ } else {
+ //month is the second word
+ imonth = 1;
+ iyear = 2;
+ }
+
+ for ( uint i = 0; i < 12; i++ ) {
+ if ( ss[imonth] == shortMonthName( i+1 ) || ss[imonth] == longMonthName( i+1 ) ) {
+ month = i + 1;
+ break;
+ }
+ }
+
+ if ( month == -1 && imonth == 0 ) { //try the third word
+ imonth = 2;
+ iyear = 3;
+ for ( uint i = 0; i < 12; i++ ) {
+ if ( ss[imonth] == shortMonthName( i+1 ) || ss[imonth] == longMonthName( i+1 ) ) {
+ month = i + 1;
+ break;
+ }
+ }
+ }
+
+ if ( month > -1 ) ok = true;
+ if ( ! ok ) return dt; //could not parse month; return invalid
+
+ int year = ss[iyear].toInt( &ok );
+ if ( ! ok ) return dt; //could not parse year; return invalid
+
+ return ExtDate( year, month, day );
+
+ break;
+ }
+#else
+ break;
+#endif //ifndef QT_NO_TEXTDATE
+ }
+
+ return dt;
+}
+#endif //ifndef QT_NO_DATESTRING
+
+bool ExtDate::isValid( int y, int m, int d )
+{
+ if (m < 1 || m > 12) return false;
+ if (d < 1) return false;
+ if (m != 2 && d > (int) m_monthLength[m-1]) return false;
+ if (m == 2 && d > ( (int) m_monthLength[1] + (leapYear(y) ? 1 : 0))) return false;
+ return true;
+}
+
+QDate ExtDate::qdate() const {
+ QDate q( year(), month(), day() );
+
+ if ( q.isValid() )
+ return q;
+ else
+ return QDate();
+}
+
+bool ExtDate::leapYear( int year )
+{
+ // year is the year-number where JC birth is 0
+ if ((year % 4) != 0) return false;
+ // multiple of 4 : can be a leap year
+ // centennial years are NOT leap, but quadri-centennial ARE.
+ if ((year % 400) == 0) return true;
+ if ((year % 100) == 0) return false;
+ // year is multiple of 4 but not centennial so leap year !
+ return true;
+}
+
+int ExtDate::dayOfYear(int y, int m, int d)
+{
+ return m_monthOrigin[m-1] + d + ((m > 1) ? (leapYear(y) ? 1 : 0) : 0);
+}
+
+/*****************************************************************************
+ ExtDateTime member functions
+ *****************************************************************************/
+
+/*!
+ \class ExtDateTime extdatetime.h
+ \brief The ExtDateTime class provides date and time functions.
+
+ \ingroup time
+
+ A ExtDateTime object contains a calendar date and a clock time (a
+ "datetime"). It is a combination of the ExtDate and QTime classes.
+ It can read the current datetime from the system clock. It
+ provides functions for comparing datetimes and for manipulating a
+ datetime by adding a number of seconds, days, months or years.
+
+ A ExtDateTime object is typically created either by giving a date
+ and time explicitly in the constructor, or by using the static
+ function currentDateTime(), which returns a ExtDateTime object set
+ to the system clock's time. The date and time can be changed with
+ setDate() and setTime(). A datetime can also be set using the
+ setTime_t() function, which takes a POSIX-standard "number of
+ seconds since 00:00:00 on January 1, 1970" value. The fromString()
+ function returns a ExtDateTime given a string and a date format
+ which is used to interpret the date within the string.
+
+ The date() and time() functions provide access to the date and
+ time parts of the datetime. The same information is provided in
+ textual format by the toString() function.
+
+ ExtDateTime provides a full set of operators to compare two
+ ExtDateTime objects where smaller means earlier and larger means
+ later.
+
+ You can increment (or decrement) a datetime by a given number of
+ seconds using addSecs() or days using addDays(). Similarly you can
+ use addMonths() and addYears(). The daysTo() function returns the
+ number of days between two datetimes, and secsTo() returns the
+ number of seconds between two datetimes.
+
+ The range of a datetime object is constrained to the ranges of the
+ ExtDate and QTime objects which it embodies.
+
+ Methods in this class are reentrant.
+
+ \sa ExtDate QTime ExtDateTimeEdit
+*/
+
+
+/*!
+ \fn ExtDateTime::ExtDateTime()
+
+ Constructs a null datetime (i.e. null date and null time). A null
+ datetime is invalid, since the date is invalid.
+
+ \sa isValid()
+*/
+
+
+/*!
+ Constructs a datetime with date \a date and null (but valid) time
+ (00:00:00.000).
+*/
+
+ExtDateTime::ExtDateTime( const ExtDate &date )
+ : d(date)
+{
+}
+
+/*!
+ Constructs a datetime with date \a date and time \a time.
+*/
+
+ExtDateTime::ExtDateTime( const ExtDate &date, const QTime &time )
+ : d(date), t(time)
+{
+}
+
+
+/*!
+ \fn bool ExtDateTime::isNull() const
+
+ Returns TRUE if both the date and the time are null; otherwise
+ returns FALSE. A null datetime is invalid.
+
+ \sa ExtDate::isNull(), QTime::isNull()
+*/
+
+/*!
+ \fn bool ExtDateTime::isValid() const
+
+ Returns TRUE if both the date and the time are valid; otherwise
+ returns FALSE.
+
+ \sa ExtDate::isValid(), QTime::isValid()
+*/
+
+/*!
+ \fn ExtDate ExtDateTime::date() const
+
+ Returns the date part of the datetime.
+
+ \sa setDate(), time()
+*/
+
+/*!
+ \fn QTime ExtDateTime::time() const
+
+ Returns the time part of the datetime.
+
+ \sa setTime(), date()
+*/
+
+/*!
+ \fn void ExtDateTime::setDate( const ExtDate &date )
+
+ Sets the date part of this datetime to \a date.
+
+ \sa date(), setTime()
+*/
+
+/*!
+ \fn void ExtDateTime::setTime( const QTime &time )
+
+ Sets the time part of this datetime to \a time.
+
+ \sa time(), setDate()
+*/
+
+
+/*!
+ Returns the datetime as the number of seconds that have passed
+ since 1970-01-01T00:00:00, Coordinated Universal Time (UTC).
+
+ On systems that do not support timezones, this function will
+ behave as if local time were UTC.
+
+ \sa setTime_t()
+*/
+
+uint ExtDateTime::toTime_t() const
+{
+ tm brokenDown;
+ brokenDown.tm_sec = t.second();
+ brokenDown.tm_min = t.minute();
+ brokenDown.tm_hour = t.hour();
+ brokenDown.tm_mday = d.day();
+ brokenDown.tm_mon = d.month() - 1;
+ brokenDown.tm_year = d.year() - 1900;
+ brokenDown.tm_isdst = -1;
+ int secsSince1Jan1970UTC = (int) mktime( &brokenDown );
+ if ( secsSince1Jan1970UTC < -1 )
+ secsSince1Jan1970UTC = -1;
+ return (uint) secsSince1Jan1970UTC;
+}
+
+/*!
+ \overload
+
+ Convenience function that sets the date and time to local time
+ based on the given UTC time.
+*/
+
+void ExtDateTime::setTime_t( uint secsSince1Jan1970UTC )
+{
+ setTime_t( secsSince1Jan1970UTC, Qt::LocalTime );
+}
+
+/*!
+ Sets the date and time to \a ts time (\c Qt::LocalTime or \c
+ Qt::UTC) given the number of seconds that have passed since
+ 1970-01-01T00:00:00, Coordinated Universal Time (UTC). On systems
+ that do not support timezones this function will behave as if
+ local time were UTC.
+
+ On Windows, only a subset of \a secsSince1Jan1970UTC values are
+ supported, as Windows starts counting from 1980.
+
+ \sa toTime_t()
+*/
+void ExtDateTime::setTime_t( uint secsSince1Jan1970UTC, Qt::TimeSpec ts )
+{
+ time_t tmp = (time_t) secsSince1Jan1970UTC;
+ tm *brokenDown = 0;
+
+#if defined(Q_OS_UNIX) && defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
+ // posix compliant system
+ // use the reentrant versions of localtime() and gmtime() where available
+ tm res;
+ if ( ts == Qt::LocalTime )
+ brokenDown = localtime_r( &tmp, &res );
+ if ( !brokenDown ) {
+ brokenDown = gmtime_r( &tmp, &res );
+ if ( !brokenDown ) {
+ d.setJD( ExtDate::GregorianToJD( 1970, 1, 1 ) );
+ t.setHMS(0,0,0);
+ // t.ds = 0;
+ return;
+ }
+ }
+#else
+ if ( ts == Qt::LocalTime )
+ brokenDown = localtime( &tmp );
+ if ( !brokenDown ) {
+ brokenDown = gmtime( &tmp );
+ if ( !brokenDown ) {
+ d.setJD( ExtDate::GregorianToJD( 1970, 1, 1 ) );
+// t.ds = 0;
+ t.setHMS(0,0,0);
+ return;
+ }
+ }
+#endif
+
+ d.setJD( ExtDate::GregorianToJD( brokenDown->tm_year + 1900,
+ brokenDown->tm_mon + 1,
+ brokenDown->tm_mday ) );
+ t.setHMS( brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec );
+// t.ds = MSECS_PER_HOUR * brokenDown->tm_hour +
+// MSECS_PER_MIN * brokenDown->tm_min +
+// 1000 * brokenDown->tm_sec;
+}
+#ifndef QT_NO_DATESTRING
+#ifndef QT_NO_SPRINTF
+/*!
+ \overload
+
+ Returns the datetime as a string. The \a f parameter determines
+ the format of the string.
+
+ If \a f is \c Qt::TextDate, the string format is "Wed May 20
+ 03:40:13 1998" (using ExtDate::shortDayName(), ExtDate::shortMonthName(),
+ and QTime::toString() to generate the string, so the day and month
+ names will have localized names).
+
+ If \a f is \c Qt::ISODate, the string format corresponds to the
+ ISO 8601 extended specification for representations of dates and
+ times, which is YYYY-MM-DDTHH:MM:SS.
+
+ If \a f is \c Qt::LocalDate, the string format depends on the
+ locale settings of the system.
+
+ If the format \a f is invalid or the datetime is invalid, toString()
+ returns a null string.
+
+ \sa ExtDate::toString() QTime::toString()
+*/
+
+QString ExtDateTime::toString( Qt::DateFormat f ) const
+{
+ if ( !isValid() )
+ return QString::null;
+
+ if ( f == Qt::ISODate ) {
+ return d.toString( Qt::ISODate ) + "T" + t.toString( Qt::ISODate );
+ }
+#ifndef QT_NO_TEXTDATE
+ else if ( f == Qt::TextDate ) {
+ return toString( "%a %b %e %Y %H:%M:%S" );
+ }
+#endif
+ else if ( f == Qt::LocalDate ) {
+ return toString( KGlobal::locale()->dateFormat()
+ + " " + KGlobal::locale()->timeFormat() );
+ }
+
+ return QString::null;
+}
+#endif
+
+QString ExtDateTime::toString( const QString& format ) const
+{
+ if ( !isValid() )
+ return QString::null;
+
+ //Parse the date portion of the format string
+ QString result = date().toString( format );
+
+ //For the time format, use the following KDE format specs:
+ //Replace occurences of the following tokens with their
+ //corresponding values:
+ //
+ // %H Hour in 24h format, 2 digits
+ // %k Hour in 24h format, 1-2 digits
+ // %I Hour in 12h format, 2 digits
+ // %l Hour in 12h format, 1-2 digits
+ // %M Minute, 2 digits
+ // %S Seconds, 2 digits
+ // %p pm/am
+
+ int h = time().hour();
+
+ result.replace( "%H", QString().sprintf( "%02d", h ) );
+ result.replace( "%k", QString().sprintf( "%d", h ) );
+ result.replace( "%I", QString().sprintf( "%02d", ( h > 12 ) ? h-12 : h ) );
+ result.replace( "%l", QString().sprintf( "%d", ( h > 12 ) ? h-12 : h ) );
+ result.replace( "%M", QString().sprintf( "%02d", time().minute() ) );
+ result.replace( "%S", QString().sprintf( "%02d", time().second() ) );
+ result.replace( "%p", QString().sprintf( "%s", ( h > 12 ) ? "pm" : "am" ) );
+
+ return result;
+}
+#endif //QT_NO_DATESTRING
+
+/*!
+ Returns a ExtDateTime object containing a datetime \a ndays days
+ later than the datetime of this object (or earlier if \a ndays is
+ negative).
+
+ \sa daysTo(), addMonths(), addYears(), addSecs()
+*/
+
+ExtDateTime ExtDateTime::addDays( int ndays ) const
+{
+ return ExtDateTime( d.addDays(ndays), t );
+}
+
+/*!
+ Returns a ExtDateTime object containing a datetime \a nmonths months
+ later than the datetime of this object (or earlier if \a nmonths
+ is negative).
+
+ \sa daysTo(), addDays(), addYears(), addSecs()
+*/
+
+ExtDateTime ExtDateTime::addMonths( int nmonths ) const
+{
+ return ExtDateTime( d.addMonths(nmonths), t );
+}
+
+/*!
+ Returns a ExtDateTime object containing a datetime \a nyears years
+ later than the datetime of this object (or earlier if \a nyears is
+ negative).
+
+ \sa daysTo(), addDays(), addMonths(), addSecs()
+*/
+
+ExtDateTime ExtDateTime::addYears( int nyears ) const
+{
+ return ExtDateTime( d.addYears(nyears), t );
+}
+
+/*!
+ Returns a ExtDateTime object containing a datetime \a nsecs seconds
+ later than the datetime of this object (or earlier if \a nsecs is
+ negative).
+
+ \sa secsTo(), addDays(), addMonths(), addYears()
+*/
+
+ExtDateTime ExtDateTime::addSecs( int nsecs ) const
+{
+ long int dd = d.jd();
+ int tt = MSECS_PER_HOUR*t.hour() + MSECS_PER_MIN*t.minute() + 1000*t.second() + t.msec();
+ tt += nsecs*1000;
+
+ while ( tt < 0 ) {
+ tt += MSECS_PER_DAY;
+ --dd;
+ }
+
+ while ( tt > int(MSECS_PER_DAY) ) {
+ tt -= MSECS_PER_DAY;
+ ++dd;
+ }
+
+ ExtDateTime ret;
+ ret.setTime( QTime().addMSecs( tt ) );
+ ret.setDate( ExtDate( dd ) );
+
+ return ret;
+}
+
+/*!
+ Returns the number of days from this datetime to \a dt (which is
+ negative if \a dt is earlier than this datetime).
+
+ \sa addDays(), secsTo()
+*/
+
+int ExtDateTime::daysTo( const ExtDateTime &dt ) const
+{
+ return d.daysTo( dt.d );
+}
+
+/*!
+ Returns the number of seconds from this datetime to \a dt (which
+ is negative if \a dt is earlier than this datetime).
+
+ Example:
+ \code
+ ExtDateTime dt = ExtDateTime::currentDateTime();
+ ExtDateTime xmas( ExtDate(dt.date().year(),12,24), QTime(17,00) );
+ kdDebug( ) << "There are " << dt.secsTo(xmas) << " seconds to Christmas" << endl;
+ \endcode
+
+ \sa addSecs(), daysTo(), QTime::secsTo()
+*/
+
+int ExtDateTime::secsTo( const ExtDateTime &dt ) const
+{
+ return t.secsTo(dt.t) + d.daysTo(dt.d)*SECS_PER_DAY;
+}
+
+
+/*!
+ Returns TRUE if this datetime is equal to \a dt; otherwise returns FALSE.
+
+ \sa operator!=()
+*/
+
+bool ExtDateTime::operator==( const ExtDateTime &dt ) const
+{
+ return t == dt.t && d == dt.d;
+}
+
+/*!
+ Returns TRUE if this datetime is different from \a dt; otherwise
+ returns FALSE.
+
+ \sa operator==()
+*/
+
+bool ExtDateTime::operator!=( const ExtDateTime &dt ) const
+{
+ return t != dt.t || d != dt.d;
+}
+
+/*!
+ Returns TRUE if this datetime is earlier than \a dt; otherwise
+ returns FALSE.
+*/
+
+bool ExtDateTime::operator<( const ExtDateTime &dt ) const
+{
+ if ( d < dt.d )
+ return true;
+ return d == dt.d ? t < dt.t : false;
+}
+
+/*!
+ Returns TRUE if this datetime is earlier than or equal to \a dt;
+ otherwise returns FALSE.
+*/
+
+bool ExtDateTime::operator<=( const ExtDateTime &dt ) const
+{
+ if ( d < dt.d )
+ return true;
+ return d == dt.d ? t <= dt.t : false;
+}
+
+/*!
+ Returns TRUE if this datetime is later than \a dt; otherwise
+ returns FALSE.
+*/
+
+bool ExtDateTime::operator>( const ExtDateTime &dt ) const
+{
+ if ( d > dt.d )
+ return true;
+ return d == dt.d ? t > dt.t : false;
+}
+
+/*!
+ Returns TRUE if this datetime is later than or equal to \a dt;
+ otherwise returns FALSE.
+*/
+
+bool ExtDateTime::operator>=( const ExtDateTime &dt ) const
+{
+ if ( d > dt.d )
+ return true;
+ return d == dt.d ? t >= dt.t : false;
+}
+
+/*!
+ \overload
+
+ Returns the current datetime, as reported by the system clock.
+
+ \sa ExtDate::currentDate(), QTime::currentTime()
+*/
+
+ExtDateTime ExtDateTime::currentDateTime()
+{
+ return currentDateTime( Qt::LocalTime );
+}
+
+/*!
+ Returns the current datetime, as reported by the system clock, for the
+ TimeSpec \a ts. The default TimeSpec is LocalTime.
+
+ \sa ExtDate::currentDate(), QTime::currentTime(), Qt::TimeSpec
+*/
+
+ExtDateTime ExtDateTime::currentDateTime( Qt::TimeSpec ts )
+{
+ ExtDateTime dt;
+ dt.setDate( ExtDate::currentDate(ts) );
+ QTime t = t.currentTime(ts);
+ if ( t.hour()==0 && t.minute()==0 ) // midnight or right after?
+ dt.setDate( ExtDate::currentDate(ts) ); // fetch date again
+ dt.setTime( t );
+ return dt;
+}
+
+#ifndef QT_NO_DATESTRING
+/*!
+ Returns the ExtDateTime represented by the string \a s, using the
+ format \a f, or an invalid datetime if this is not possible.
+
+ Note for \c Qt::TextDate: It is recommended that you use the
+ English short month names (e.g. "Jan"). Although localized month
+ names can also be used, they depend on the user's locale settings.
+
+ \warning Note that \c Qt::LocalDate cannot be used here.
+*/
+ExtDateTime ExtDateTime::fromString( const QString& s )
+{
+ ExtDateTime dtResult = ExtDateTime::fromString( s, Qt::TextDate );
+ if ( dtResult.isValid() ) return dtResult;
+
+ dtResult = ExtDateTime::fromString( s, Qt::ISODate );
+
+ if ( dtResult.isValid() ) return dtResult;
+ else return ExtDateTime(); //invalid
+}
+
+ExtDateTime ExtDateTime::fromString( const QString& s, Qt::DateFormat f )
+{
+ ExtDateTime dt;
+
+ if ( ( s.isEmpty() ) || ( f == Qt::LocalDate ) ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "ExtDateTime::fromString: Parameter out of range" );
+#endif
+ dt.d.setJD( INVALID_DAY );
+ return dt;
+ }
+
+ if ( f == Qt::ISODate ) {
+ if ( s.length() <= 10 || ! s.contains( ':' ) ) { //no time specified
+ QTime t = QTime(0,0,0);
+ return ExtDateTime( ExtDate::fromString( s.mid(0,10), Qt::ISODate ) );
+ } else {
+ return ExtDateTime( ExtDate::fromString( s.mid(0,10), Qt::ISODate ),
+ QTime::fromString( s.mid(11), Qt::ISODate ) );
+ }
+ }
+#if !defined(QT_NO_REGEXP) && !defined(QT_NO_TEXTDATE)
+ else if ( f == Qt::TextDate ) {
+
+ //parse the time, if it exists.
+ QTime time;
+ QString sd = s;
+ int hour, minute, second;
+ int pivot = s.find( QRegExp(QString::fromLatin1("[0-9][0-9]:[0-9][0-9]:[0-9][0-9]")) );
+ if ( pivot != -1 ) {
+ hour = s.mid( pivot, 2 ).toInt();
+ minute = s.mid( pivot+3, 2 ).toInt();
+ second = s.mid( pivot+6, 2 ).toInt();
+ time.setHMS( hour, minute, second );
+
+ sd = s.left( pivot - 1 );
+ }
+
+ //sd is now just the date string.
+ ExtDate date = ExtDate::fromString( s, Qt::TextDate );
+ return ExtDateTime( date, time );
+ }
+
+#endif //QT_NO_REGEXP
+ return ExtDateTime();
+}
+#endif //QT_NO_DATESTRING
+
+
+#ifndef QT_NO_DATASTREAM
+KDE_EXPORT QDataStream &operator<<( QDataStream & ostream, const ExtDate & date)
+{
+ return ostream << (Q_UINT32)(date.jd());
+}
+
+KDE_EXPORT QDataStream &operator>>( QDataStream & ostream, ExtDate & date)
+{
+ Q_UINT32 julday;
+ ostream >> julday;
+ date.setJD( julday );
+ return ostream;
+}
+
+KDE_EXPORT QDataStream &operator<<( QDataStream & ostream, const ExtDateTime & dt)
+{
+ return ostream << dt.d << dt.t;
+}
+
+KDE_EXPORT QDataStream &operator>>( QDataStream & ostream, ExtDateTime & dt)
+{
+ ostream >> dt.d >> dt.t;
+ return ostream;
+}
+
+#endif // QT_NO_DATASTREAM