• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kstars

timezonerule.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           timezonerule.cpp  -  description
00003                              -------------------
00004     begin                : Tue Apr 2 2002
00005     copyright            : (C) 2002 by Jason Harris
00006     email                : kstars@30doradus.org
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <kdebug.h>
00019 #include <klocale.h>
00020 
00021 #include "timezonerule.h"
00022 #include "kstarsdatetime.h"
00023 
00024 TimeZoneRule::TimeZoneRule() {
00025     //Build the empty TimeZoneRule.
00026     StartMonth = 0;
00027     RevertMonth = 0;
00028     StartDay = 0;
00029     RevertDay = 0;
00030     StartWeek = -1;
00031     RevertWeek = -1;
00032     StartTime = QTime();
00033     RevertTime = QTime();
00034     HourOffset = 0.0;
00035     dTZ = 0.0;
00036 }
00037 
00038 TimeZoneRule::TimeZoneRule( const QString &smonth, const QString &sday, const QTime &stime,
00039             const QString &rmonth, const QString &rday, const QTime &rtime, const double &dh ) {
00040     dTZ = 0.0;
00041     if ( smonth != "0" ) {
00042         StartMonth = initMonth( smonth );
00043         RevertMonth = initMonth( rmonth );
00044 
00045         if ( StartMonth && RevertMonth && initDay( sday, StartDay, StartWeek ) &&
00046                     initDay( rday, RevertDay, RevertWeek ) && stime.isValid() && rtime.isValid() ) {
00047             StartTime = stime;
00048             RevertTime = rtime;
00049             HourOffset = dh;
00050         } else {
00051             kdWarning() << i18n( "Error parsing TimeZoneRule, setting to empty rule." ) << endl;
00052             StartMonth = 0;
00053             RevertMonth = 0;
00054             StartDay = 0;
00055             RevertDay = 0;
00056             StartWeek = -1;
00057             RevertWeek = -1;
00058             StartTime = QTime();
00059             RevertTime = QTime();
00060             HourOffset = 0.0;
00061         }
00062     } else { //Empty rule
00063         StartMonth = 0;
00064         RevertMonth = 0;
00065         StartDay = 0;
00066         RevertDay = 0;
00067         StartWeek = -1;
00068         RevertWeek = -1;
00069         StartTime = QTime();
00070         RevertTime = QTime();
00071         HourOffset = 0.0;
00072     }
00073 }
00074 
00075 TimeZoneRule::~TimeZoneRule() {
00076 }
00077 
00078 void TimeZoneRule::setDST( bool activate ) {
00079     if ( activate ) {
00080         kdDebug() << i18n( "Daylight Saving Time active" ) << endl;
00081         dTZ = HourOffset;
00082     } else {
00083         kdDebug() << i18n( "Daylight Saving Time inactive" ) << endl;
00084         dTZ = 0.0;
00085     }
00086 }
00087 
00088 int TimeZoneRule::initMonth( const QString &mn ) {
00089 //Check whether the argument is a three-letter English month code.
00090     QString ml = mn.lower();
00091     if ( ml == "jan" ) return 1;
00092     else if ( ml == "feb" ) return 2;
00093     else if ( ml == "mar" ) return 3;
00094     else if ( ml == "apr" ) return 4;
00095     else if ( ml == "may" ) return 5;
00096     else if ( ml == "jun" ) return 6;
00097     else if ( ml == "jul" ) return 7;
00098     else if ( ml == "aug" ) return 8;
00099     else if ( ml == "sep" ) return 9;
00100     else if ( ml == "oct" ) return 10;
00101     else if ( ml == "nov" ) return 11;
00102     else if ( ml == "dec" ) return 12;
00103 
00104     kdWarning() << i18n( "Could not parse " ) << mn << i18n( " as a valid month code." ) << endl;
00105     return false;
00106 }
00107 
00108 bool TimeZoneRule::initDay( const QString &dy, int &Day, int &Week ) {
00109 //Three possible ways to express a day.
00110 //1. simple integer; the calendar date...set Week=0 to indicate that Date is not the day of the week
00111     bool ok;
00112     int day = dy.toInt( &ok );
00113     if ( ok ) {
00114         Day = day;
00115         Week = 0;
00116         return true;
00117     }
00118 
00119     QString dl = dy.lower();
00120 //2. 3-letter day of week string, indicating the last of that day of the month
00121 //   ...set Week to 5 to indicate the last weekday of the month
00122     if ( dl == "mon" ) { Day = 1; Week = 5; return true; }
00123     else if ( dl == "tue" ) { Day = 2; Week = 5; return true; }
00124     else if ( dl == "wed" ) { Day = 3; Week = 5; return true; }
00125     else if ( dl == "thu" ) { Day = 4; Week = 5; return true; }
00126     else if ( dl == "fri" ) { Day = 5; Week = 5; return true; }
00127     else if ( dl == "sat" ) { Day = 6; Week = 5; return true; }
00128     else if ( dl == "sun" ) { Day = 7; Week = 5; return true; }
00129 
00130 //3. 1,2 or 3 followed by 3-letter day of week string; this indicates
00131 //   the (1st/2nd/3rd) weekday of the month.
00132     int wn = dl.left(1).toInt();
00133     if ( wn >0 && wn <4 ) {
00134         QString dm = dl.mid( 1, dl.length() ).lower();
00135         if ( dm == "mon" ) { Day = 1; Week = wn; return true; }
00136         else if ( dm == "tue" ) { Day = 2; Week = wn; return true; }
00137         else if ( dm == "wed" ) { Day = 3; Week = wn; return true; }
00138         else if ( dm == "thu" ) { Day = 4; Week = wn; return true; }
00139         else if ( dm == "fri" ) { Day = 5; Week = wn; return true; }
00140         else if ( dm == "sat" ) { Day = 6; Week = wn; return true; }
00141         else if ( dm == "sun" ) { Day = 7; Week = wn; return true; }
00142     }
00143 
00144     kdWarning() << i18n( "Could not parse " ) << dy << i18n( " as a valid day code." ) << endl;
00145     return false;
00146 }
00147 
00148 int TimeZoneRule::findStartDay( const KStarsDateTime &d ) {
00149     // Determine the calendar date of StartDay for the month and year of the given date.
00150     ExtDate test;
00151 
00152     // TimeZoneRule is empty, return -1
00153     if ( isEmptyRule() ) return -1;
00154 
00155     // If StartWeek=0, just return the integer.
00156     if ( StartWeek==0 ) return StartDay;
00157 
00158     // Since StartWeek was not zero, StartDay is the day of the week, not the calendar date
00159     else if ( StartWeek==5 ) { // count back from end of month until StartDay is found.
00160         for ( test = ExtDate( d.date().year(), d.date().month(), d.date().daysInMonth() );
00161                     test.day() > 21; test = test.addDays( -1 ) )
00162             if ( test.dayOfWeek() == StartDay ) break;
00163     } else { // Count forward from day 1, 8 or 15 (depending on StartWeek) until correct day of week is found
00164         for ( test = ExtDate( d.date().year(), d.date().month(), (StartWeek-1)*7 + 1 );
00165                     test.day() < 7*StartWeek; test = test.addDays( 1 ) )
00166             if ( test.dayOfWeek() == StartDay ) break;
00167     }
00168     return test.day();
00169 }
00170 
00171 int TimeZoneRule::findRevertDay( const KStarsDateTime &d ) {
00172     // Determine the calendar date of RevertDay for the month and year of the given date.
00173     ExtDate test;
00174 
00175     // TimeZoneRule is empty, return -1
00176     if ( isEmptyRule() ) return -1;
00177 
00178     // If RevertWeek=0, just return the integer.
00179     if ( RevertWeek==0 ) return RevertDay;
00180 
00181     // Since RevertWeek was not zero, RevertDay is the day of the week, not the calendar date
00182     else if ( RevertWeek==5 ) { //count back from end of month until RevertDay is found.
00183         for ( test = ExtDate( d.date().year(), d.date().month(), d.date().daysInMonth() );
00184                     test.day() > 21; test = test.addDays( -1 ) )
00185             if ( test.dayOfWeek() == RevertDay ) break;
00186     } else { //Count forward from day 1, 8 or 15 (depending on RevertWeek) until correct day of week is found
00187         for ( test = ExtDate( d.date().year(), d.date().month(), (RevertWeek-1)*7 + 1 );
00188                     test.day() < 7*RevertWeek; test = test.addDays( 1 ) )
00189             if ( test.dayOfWeek() == StartDay ) break;
00190     }
00191     return test.day();
00192 }
00193 
00194 bool TimeZoneRule::isDSTActive( const KStarsDateTime &date ) {
00195     // The empty rule always returns false
00196     if ( isEmptyRule() ) return false;
00197 
00198     // First, check whether the month is outside the DST interval.  Note that
00199     // the interval check is different if StartMonth > RevertMonth (indicating that
00200     // the DST interval includes the end of the year).
00201     int month = date.date().month();
00202     
00203     if ( StartMonth < RevertMonth ) {
00204         if ( month < StartMonth || month > RevertMonth ) return false;
00205     } else {
00206         if ( month < StartMonth && month > RevertMonth ) return false;
00207     }
00208     
00209     // OK, if the month is equal to StartMonth or Revert Month, we have more
00210     // detailed checking to do...
00211     int day = date.date().day();
00212 
00213     if ( month == StartMonth ) {
00214         int sday = findStartDay( date );
00215         if ( day < sday ) return false;
00216         if ( day==sday && date.time() < StartTime ) return false;
00217     } else if ( month == RevertMonth ) {
00218         int rday = findRevertDay( date );
00219         if ( day > rday ) return false;
00220         if ( day==rday && date.time() > RevertTime ) return false;
00221     }
00222 
00223     // passed all tests, so we must be in DST.
00224     return true;
00225 }
00226 
00227 void TimeZoneRule::nextDSTChange_LTime( const KStarsDateTime &date ) {
00228     KStarsDateTime result;
00229 
00230     // return a very remote date if the rule is the empty rule.
00231     if ( isEmptyRule() ) result = KStarsDateTime( INVALID_DAY );
00232 
00233     else if ( deltaTZ() ) {
00234         // Next change is reverting back to standard time.
00235 
00236         //y is the year for the next DST Revert date.  It's either the current year, or
00237         //the next year if the current month is already past RevertMonth
00238         int y = date.date().year();
00239         if ( RevertMonth < date.date().month() ) ++y;
00240 
00241         result = KStarsDateTime( ExtDate( y, RevertMonth, 1 ), RevertTime );
00242         result = KStarsDateTime( ExtDate( y, RevertMonth, findRevertDay( result ) ), RevertTime );
00243 
00244     } else {
00245         // Next change is starting DST.
00246 
00247         //y is the year for the next DST Start date.  It's either the current year, or
00248         //the next year if the current month is already past StartMonth
00249         int y = date.date().year();
00250         if ( StartMonth < date.date().month() ) ++y;
00251 
00252         result = KStarsDateTime( ExtDate( y, StartMonth, 1 ), StartTime );
00253         result = KStarsDateTime( ExtDate( y, StartMonth, findStartDay( result ) ), StartTime );
00254     }
00255 
00256     kdDebug() << i18n( "Next Daylight Savings Time change (Local Time): " ) << result.toString() << endl;
00257     next_change_ltime = result;
00258 }
00259 
00260 
00261 void TimeZoneRule::previousDSTChange_LTime( const KStarsDateTime &date ) {
00262     KStarsDateTime result;
00263 
00264     // return a very remote date if the rule is the empty rule
00265     if ( isEmptyRule() ) next_change_ltime = KStarsDateTime( INVALID_DAY );
00266 
00267     if ( deltaTZ() ) {
00268         // Last change was starting DST.
00269 
00270         //y is the year for the previous DST Start date.  It's either the current year, or
00271         //the previous year if the current month is earlier than StartMonth
00272         int y = date.date().year();
00273         if ( StartMonth > date.date().month() ) --y;
00274 
00275         result = KStarsDateTime( ExtDate( y, StartMonth, 1 ), StartTime );
00276         result = KStarsDateTime( ExtDate( y, StartMonth, findStartDay( result ) ), StartTime );
00277 
00278     } else if ( StartMonth ) {
00279         //Last change was reverting to standard time.
00280 
00281         //y is the year for the previous DST Start date.  It's either the current year, or
00282         //the previous year if the current month is earlier than StartMonth
00283         int y = date.date().year();
00284         if ( RevertMonth > date.date().month() ) --y;
00285 
00286         result = KStarsDateTime( ExtDate( y, RevertMonth, 1 ), RevertTime );
00287         result = KStarsDateTime( ExtDate( y, RevertMonth, findRevertDay( result ) ), RevertTime );
00288     }
00289 
00290     kdDebug() << i18n( "Previous Daylight Savings Time change (Local Time): " ) << result.toString() << endl;
00291     next_change_ltime = result;
00292 }
00293 
00295 void TimeZoneRule::nextDSTChange( const KStarsDateTime &local_date, const double TZoffset ) {
00296     // just decrement timezone offset and hour offset
00297     KStarsDateTime result = local_date.addSecs( int( (TZoffset + deltaTZ()) * -3600) );
00298 
00299     kdDebug() << i18n( "Next Daylight Savings Time change (UTC): " ) << result.toString() << endl;
00300     next_change_utc = result;
00301 }
00302 
00304 void TimeZoneRule::previousDSTChange( const KStarsDateTime &local_date, const double TZoffset ) {
00305     // just decrement timezone offset
00306     KStarsDateTime result = local_date.addSecs( int( TZoffset * -3600) );
00307 
00308     // if prev DST change is a revert change, so the revert time is in daylight saving time
00309     if ( result.date().month() == RevertMonth )
00310         result = result.addSecs( int(HourOffset * -3600) );
00311     
00312     kdDebug() << i18n( "Previous Daylight Savings Time change (UTC): " ) << result.toString() << endl;
00313     next_change_utc = result;
00314 }
00315 
00316 void TimeZoneRule::reset_with_ltime( KStarsDateTime &ltime, const double TZoffset, const bool time_runs_forward,
00317         const bool automaticDSTchange ) {
00318 
00333     //don't need to do anything for empty rule
00334     if ( isEmptyRule() ) return;
00335 
00336     // check if DST is active before resetting with new time
00337     bool wasDSTactive(false);
00338     
00339     if ( deltaTZ() != 0.0 ) { 
00340         wasDSTactive = true;
00341     }
00342 
00343     // check if current time is start time, this means if a DST change happend in last hour(s)
00344     bool active_with_houroffset = isDSTActive(ltime.addSecs( int(HourOffset * -3600) ) );
00345     bool active_normal = isDSTActive( ltime );
00346 
00347     // store a valid local time
00348     KStarsDateTime ValidLTime = ltime;
00349 
00350     if ( active_with_houroffset != active_normal && ValidLTime.date().month() == StartMonth ) {
00351         // current time is the start time
00352         kdDebug() << "Current time = Starttime: invalid local time due to daylight saving time" << endl;
00353 
00354         // set a correct local time because the current time doesn't exists
00355         // if automatic DST change happend, new DST setting is the opposite of current setting
00356         if ( automaticDSTchange ) {
00357             // revert DST status
00358             setDST( !wasDSTactive );
00359             // new setting DST is inactive, so subtract hour offset to new time
00360             if ( wasDSTactive ) {
00361                 // DST inactive
00362                 ValidLTime = ltime.addSecs( int( HourOffset * - 3600) );
00363             } else {
00364                 // DST active
00365                 // add hour offset to new time
00366                 ValidLTime = ltime.addSecs( int( HourOffset * 3600) );
00367             }
00368         } else {  // if ( automaticDSTchange )
00369         // no automatic DST change happend, so stay in current DST mode
00370             setDST( wasDSTactive );
00371             if ( wasDSTactive ) {
00372                 // DST active
00373                 // add hour offset to current time, because time doesn't exists
00374                 ValidLTime = ltime.addSecs( int( HourOffset * 3600) );
00375             } else {
00376                 // DST inactive
00377                 // subtrace hour offset to current time, because time doesn't exists
00378                 ValidLTime = ltime.addSecs( int( HourOffset * -3600) );
00379             }
00380         }  // else { // if ( automaticDSTchange )
00381 
00382     } else {  // if ( active_with_houroffset != active_normal && ValidLTime.date().month() == StartMonth )
00383         // If current time was not start time, so check if current time is revert time
00384         // this means if a DST change happend in next hour(s)
00385         active_with_houroffset = isDSTActive(ltime.addSecs( int(HourOffset * 3600) ) );
00386         if ( active_with_houroffset != active_normal && RevertMonth == ValidLTime.date().month() ) {
00387             // current time is the revert time
00388             kdDebug() << "Current time = Reverttime" << endl;
00389 
00390             // we don't kneed to change the local time, because local time always exists, but
00391             // some times exists twice, so we have to reset DST status
00392             if ( automaticDSTchange ) {
00393                 // revert DST status
00394                 setDST( !wasDSTactive );
00395             } else {
00396                 // no automatic DST change so stay in current DST mode
00397                 setDST( wasDSTactive );
00398             }
00399 
00400         } else {
00401             //Current time was neither starttime nor reverttime, so use normal calculated DST status
00402             setDST( active_normal );
00403         }
00404     }  // if ( active_with_houroffset != active_normal && ValidLTime.date().month() == StartMonth )
00405 
00406 //  kdDebug() << "Using Valid Local Time = " << ValidLTime.toString() << endl;
00407 
00408     if (time_runs_forward) {
00409         // get next DST change time in local time
00410         nextDSTChange_LTime( ValidLTime );
00411         nextDSTChange( next_change_ltime, TZoffset );
00412     } else {
00413         // get previous DST change time in local time
00414         previousDSTChange_LTime( ValidLTime );
00415         previousDSTChange( next_change_ltime, TZoffset );
00416     }
00417     ltime = ValidLTime;
00418 }
00419 
00420 
00421 bool TimeZoneRule::equals( TimeZoneRule *r ) {
00422     if ( StartDay == r->StartDay && RevertDay == r->RevertDay &&
00423             StartWeek == r->StartWeek && RevertWeek == r->RevertWeek &&
00424             StartMonth == r->StartMonth && RevertMonth == r->RevertMonth &&
00425             StartTime == r->StartTime && RevertTime == r->RevertTime &&
00426             isEmptyRule() == r->isEmptyRule() )
00427         return true;
00428     else
00429         return false;
00430 }

kstars

Skip menu "kstars"
  • Main Page
  • Modules
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • keduca
  • kstars
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal