You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1151 lines
30 KiB
1151 lines
30 KiB
/*************************************************************************
|
|
** 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 <tqregexp.h>
|
|
|
|
#include <tdeglobal.h>
|
|
#include <tdelocale.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};
|
|
|
|
TQString 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")
|
|
};
|
|
TQString 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")
|
|
};
|
|
TQString 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")
|
|
};
|
|
TQString 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(TQT_CHECK_RANGE)
|
|
tqWarning( "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 TQT_NO_TEXTDATE
|
|
TQString ExtDate::shortMonthName( int month ) {return m_shortMonthNames[month-1];}
|
|
TQString ExtDate::shortDayName( int weekday ) {return m_shortDayNames[weekday-1];}
|
|
TQString ExtDate::longMonthName( int month ) {return m_longMonthNames[month-1];}
|
|
TQString ExtDate::longDayName( int weekday ) {return m_longDayNames[weekday-1];}
|
|
#endif //TQT_NO_TEXTDATE
|
|
|
|
#ifndef TQT_NO_TEXTSTRING
|
|
#if !defined(TQT_NO_SPRINTF)
|
|
TQString ExtDate::toString( TQt::DateFormat f) const
|
|
{
|
|
TQString a_format;
|
|
|
|
if ( ! isValid() ) return TQString();
|
|
|
|
switch (f)
|
|
{
|
|
case TQt::TextDate : // Sat May 20 1995
|
|
a_format = "%a %b %e %Y";
|
|
break;
|
|
|
|
case TQt::ISODate : // YYYY-MM-DD
|
|
a_format = "%Y-%m-%d";
|
|
break;
|
|
|
|
case TQt::LocalDate : // local settings
|
|
a_format = TDEGlobal::locale()->dateFormat();
|
|
break;
|
|
|
|
default :
|
|
a_format = "toString : unknown format";
|
|
break;
|
|
|
|
}
|
|
return toString(a_format);
|
|
}
|
|
#endif
|
|
|
|
TQString ExtDate::toString( const TQString& format ) const
|
|
{
|
|
if ( ! isValid() ) return TQString();
|
|
|
|
//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.
|
|
|
|
TQString result( format );
|
|
|
|
result.replace( "%Y", TQString().sprintf( "%d", year() ) );
|
|
result.replace( "%y", TQString().sprintf( "%02d", (year() % 100) ) );
|
|
result.replace( "%n", TQString().sprintf( "%d", month() ) );
|
|
result.replace( "%m", TQString().sprintf( "%02d", month() ) );
|
|
result.replace( "%e", TQString().sprintf( "%d", day() ) );
|
|
result.replace( "%d", TQString().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(TQT_CHECK_RANGE)
|
|
tqWarning( "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(TQt::TimeSpec ts)
|
|
{
|
|
time_t a_current_time;
|
|
struct tm a_current_time_tm;
|
|
|
|
time(&a_current_time);
|
|
switch (ts)
|
|
{
|
|
case TQt::LocalTime :
|
|
localtime_r(&a_current_time, &a_current_time_tm);
|
|
break;
|
|
|
|
case TQt::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 TQT_NO_DATESTRING
|
|
//Try both DateFormat values
|
|
ExtDate ExtDate::fromString( const TQString& s )
|
|
{
|
|
ExtDate dResult = ExtDate::fromString( s, TQt::TextDate );
|
|
if ( dResult.isValid() ) return dResult;
|
|
|
|
dResult = ExtDate::fromString( s, TQt::ISODate );
|
|
if ( dResult.isValid() ) return dResult;
|
|
else return ExtDate(); //invalid
|
|
}
|
|
|
|
ExtDate ExtDate::fromString( const TQString& s, TQt::DateFormat f )
|
|
{
|
|
ExtDate dt = ExtDate(); //initialize invalid date
|
|
if ( s.isEmpty() ) { return dt; }
|
|
if ( f == TQt::LocalDate ) { //can't use LocalFormat
|
|
#if defined(TQT_CHECK_RANGE)
|
|
tqWarning( "TQDate::fromString: Parameter out of range" );
|
|
#endif
|
|
return dt;
|
|
}
|
|
|
|
switch( f ) {
|
|
case TQt::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 TQT_NO_TEXTDATE
|
|
case TQt::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)
|
|
TQStringList ss = TQStringList::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 TQT_NO_TEXTDATE
|
|
}
|
|
|
|
return dt;
|
|
}
|
|
#endif //ifndef TQT_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;
|
|
}
|
|
|
|
TQDate ExtDate::qdate() const {
|
|
TQDate q( year(), month(), day() );
|
|
|
|
if ( q.isValid() )
|
|
return q;
|
|
else
|
|
return TQDate();
|
|
}
|
|
|
|
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 TQTime 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 TQTime objects which it embodies.
|
|
|
|
Methods in this class are reentrant.
|
|
|
|
\sa ExtDate TQTime 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 TQTime &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(), TQTime::isNull()
|
|
*/
|
|
|
|
/*!
|
|
\fn bool ExtDateTime::isValid() const
|
|
|
|
Returns TRUE if both the date and the time are valid; otherwise
|
|
returns FALSE.
|
|
|
|
\sa ExtDate::isValid(), TQTime::isValid()
|
|
*/
|
|
|
|
/*!
|
|
\fn ExtDate ExtDateTime::date() const
|
|
|
|
Returns the date part of the datetime.
|
|
|
|
\sa setDate(), time()
|
|
*/
|
|
|
|
/*!
|
|
\fn TQTime 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 TQTime &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, TQt::LocalTime );
|
|
}
|
|
|
|
/*!
|
|
Sets the date and time to \a ts time (\c TQt::LocalTime or \c
|
|
TQt::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, TQt::TimeSpec ts )
|
|
{
|
|
time_t tmp = (time_t) secsSince1Jan1970UTC;
|
|
tm *brokenDown = 0;
|
|
|
|
#if defined(Q_OS_UNIX) && defined(TQT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
|
|
// posix compliant system
|
|
// use the reentrant versions of localtime() and gmtime() where available
|
|
tm res;
|
|
if ( ts == TQt::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 == TQt::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 TQT_NO_DATESTRING
|
|
#ifndef TQT_NO_SPRINTF
|
|
/*!
|
|
\overload
|
|
|
|
Returns the datetime as a string. The \a f parameter determines
|
|
the format of the string.
|
|
|
|
If \a f is \c TQt::TextDate, the string format is "Wed May 20
|
|
03:40:13 1998" (using ExtDate::shortDayName(), ExtDate::shortMonthName(),
|
|
and TQTime::toString() to generate the string, so the day and month
|
|
names will have localized names).
|
|
|
|
If \a f is \c TQt::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 TQt::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() TQTime::toString()
|
|
*/
|
|
|
|
TQString ExtDateTime::toString( TQt::DateFormat f ) const
|
|
{
|
|
if ( !isValid() )
|
|
return TQString();
|
|
|
|
if ( f == TQt::ISODate ) {
|
|
return d.toString( TQt::ISODate ) + "T" + t.toString( TQt::ISODate );
|
|
}
|
|
#ifndef TQT_NO_TEXTDATE
|
|
else if ( f == TQt::TextDate ) {
|
|
return toString( "%a %b %e %Y %H:%M:%S" );
|
|
}
|
|
#endif
|
|
else if ( f == TQt::LocalDate ) {
|
|
return toString( TDEGlobal::locale()->dateFormat()
|
|
+ " " + TDEGlobal::locale()->timeFormat() );
|
|
}
|
|
|
|
return TQString();
|
|
}
|
|
#endif
|
|
|
|
TQString ExtDateTime::toString( const TQString& format ) const
|
|
{
|
|
if ( !isValid() )
|
|
return TQString();
|
|
|
|
//Parse the date portion of the format string
|
|
TQString 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", TQString().sprintf( "%02d", h ) );
|
|
result.replace( "%k", TQString().sprintf( "%d", h ) );
|
|
result.replace( "%I", TQString().sprintf( "%02d", ( h > 12 ) ? h-12 : h ) );
|
|
result.replace( "%l", TQString().sprintf( "%d", ( h > 12 ) ? h-12 : h ) );
|
|
result.replace( "%M", TQString().sprintf( "%02d", time().minute() ) );
|
|
result.replace( "%S", TQString().sprintf( "%02d", time().second() ) );
|
|
result.replace( "%p", TQString().sprintf( "%s", ( h > 12 ) ? "pm" : "am" ) );
|
|
|
|
return result;
|
|
}
|
|
#endif //TQT_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( TQTime().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), TQTime(17,00) );
|
|
kdDebug( ) << "There are " << dt.secsTo(xmas) << " seconds to Christmas" << endl;
|
|
\endcode
|
|
|
|
\sa addSecs(), daysTo(), TQTime::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(), TQTime::currentTime()
|
|
*/
|
|
|
|
ExtDateTime ExtDateTime::currentDateTime()
|
|
{
|
|
return currentDateTime( TQt::LocalTime );
|
|
}
|
|
|
|
/*!
|
|
Returns the current datetime, as reported by the system clock, for the
|
|
TimeSpec \a ts. The default TimeSpec is LocalTime.
|
|
|
|
\sa ExtDate::currentDate(), TQTime::currentTime(), TQt::TimeSpec
|
|
*/
|
|
|
|
ExtDateTime ExtDateTime::currentDateTime( TQt::TimeSpec ts )
|
|
{
|
|
ExtDateTime dt;
|
|
dt.setDate( ExtDate::currentDate(ts) );
|
|
TQTime 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 TQT_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 TQt::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 TQt::LocalDate cannot be used here.
|
|
*/
|
|
ExtDateTime ExtDateTime::fromString( const TQString& s )
|
|
{
|
|
ExtDateTime dtResult = ExtDateTime::fromString( s, TQt::TextDate );
|
|
if ( dtResult.isValid() ) return dtResult;
|
|
|
|
dtResult = ExtDateTime::fromString( s, TQt::ISODate );
|
|
|
|
if ( dtResult.isValid() ) return dtResult;
|
|
else return ExtDateTime(); //invalid
|
|
}
|
|
|
|
ExtDateTime ExtDateTime::fromString( const TQString& s, TQt::DateFormat f )
|
|
{
|
|
ExtDateTime dt;
|
|
|
|
if ( ( s.isEmpty() ) || ( f == TQt::LocalDate ) ) {
|
|
#if defined(TQT_CHECK_RANGE)
|
|
tqWarning( "ExtDateTime::fromString: Parameter out of range" );
|
|
#endif
|
|
dt.d.setJD( INVALID_DAY );
|
|
return dt;
|
|
}
|
|
|
|
if ( f == TQt::ISODate ) {
|
|
if ( s.length() <= 10 || ! s.contains( ':' ) ) { //no time specified
|
|
TQTime t = TQTime(0,0,0);
|
|
return ExtDateTime( ExtDate::fromString( s.mid(0,10), TQt::ISODate ) );
|
|
} else {
|
|
return ExtDateTime( ExtDate::fromString( s.mid(0,10), TQt::ISODate ),
|
|
TQTime::fromString( s.mid(11), TQt::ISODate ) );
|
|
}
|
|
}
|
|
#if !defined(TQT_NO_REGEXP) && !defined(TQT_NO_TEXTDATE)
|
|
else if ( f == TQt::TextDate ) {
|
|
|
|
//parse the time, if it exists.
|
|
TQTime time;
|
|
TQString sd = s;
|
|
int hour, minute, second;
|
|
int pivot = s.find( TQRegExp(TQString::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, TQt::TextDate );
|
|
return ExtDateTime( date, time );
|
|
}
|
|
|
|
#endif //TQT_NO_REGEXP
|
|
return ExtDateTime();
|
|
}
|
|
#endif //TQT_NO_DATESTRING
|
|
|
|
|
|
#ifndef TQT_NO_DATASTREAM
|
|
KDE_EXPORT TQDataStream &operator<<( TQDataStream & ostream, const ExtDate & date)
|
|
{
|
|
return ostream << (TQ_UINT32)(date.jd());
|
|
}
|
|
|
|
KDE_EXPORT TQDataStream &operator>>( TQDataStream & ostream, ExtDate & date)
|
|
{
|
|
TQ_UINT32 julday;
|
|
ostream >> julday;
|
|
date.setJD( julday );
|
|
return ostream;
|
|
}
|
|
|
|
KDE_EXPORT TQDataStream &operator<<( TQDataStream & ostream, const ExtDateTime & dt)
|
|
{
|
|
ostream << dt.d;
|
|
ostream << dt.t;
|
|
return ostream;
|
|
}
|
|
|
|
KDE_EXPORT TQDataStream &operator>>( TQDataStream & ostream, ExtDateTime & dt)
|
|
{
|
|
ostream >> dt.d >> dt.t;
|
|
return ostream;
|
|
}
|
|
|
|
#endif // TQT_NO_DATASTREAM
|