00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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 {
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
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
00110
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
00121
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
00131
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
00150 ExtDate test;
00151
00152
00153 if ( isEmptyRule() ) return -1;
00154
00155
00156 if ( StartWeek==0 ) return StartDay;
00157
00158
00159 else if ( StartWeek==5 ) {
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 {
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
00173 ExtDate test;
00174
00175
00176 if ( isEmptyRule() ) return -1;
00177
00178
00179 if ( RevertWeek==0 ) return RevertDay;
00180
00181
00182 else if ( RevertWeek==5 ) {
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 {
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
00196 if ( isEmptyRule() ) return false;
00197
00198
00199
00200
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
00210
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
00224 return true;
00225 }
00226
00227 void TimeZoneRule::nextDSTChange_LTime( const KStarsDateTime &date ) {
00228 KStarsDateTime result;
00229
00230
00231 if ( isEmptyRule() ) result = KStarsDateTime( INVALID_DAY );
00232
00233 else if ( deltaTZ() ) {
00234
00235
00236
00237
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
00246
00247
00248
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
00265 if ( isEmptyRule() ) next_change_ltime = KStarsDateTime( INVALID_DAY );
00266
00267 if ( deltaTZ() ) {
00268
00269
00270
00271
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
00280
00281
00282
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
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
00306 KStarsDateTime result = local_date.addSecs( int( TZoffset * -3600) );
00307
00308
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 <ime, const double TZoffset, const bool time_runs_forward,
00317 const bool automaticDSTchange ) {
00318
00333
00334 if ( isEmptyRule() ) return;
00335
00336
00337 bool wasDSTactive(false);
00338
00339 if ( deltaTZ() != 0.0 ) {
00340 wasDSTactive = true;
00341 }
00342
00343
00344 bool active_with_houroffset = isDSTActive(ltime.addSecs( int(HourOffset * -3600) ) );
00345 bool active_normal = isDSTActive( ltime );
00346
00347
00348 KStarsDateTime ValidLTime = ltime;
00349
00350 if ( active_with_houroffset != active_normal && ValidLTime.date().month() == StartMonth ) {
00351
00352 kdDebug() << "Current time = Starttime: invalid local time due to daylight saving time" << endl;
00353
00354
00355
00356 if ( automaticDSTchange ) {
00357
00358 setDST( !wasDSTactive );
00359
00360 if ( wasDSTactive ) {
00361
00362 ValidLTime = ltime.addSecs( int( HourOffset * - 3600) );
00363 } else {
00364
00365
00366 ValidLTime = ltime.addSecs( int( HourOffset * 3600) );
00367 }
00368 } else {
00369
00370 setDST( wasDSTactive );
00371 if ( wasDSTactive ) {
00372
00373
00374 ValidLTime = ltime.addSecs( int( HourOffset * 3600) );
00375 } else {
00376
00377
00378 ValidLTime = ltime.addSecs( int( HourOffset * -3600) );
00379 }
00380 }
00381
00382 } else {
00383
00384
00385 active_with_houroffset = isDSTActive(ltime.addSecs( int(HourOffset * 3600) ) );
00386 if ( active_with_houroffset != active_normal && RevertMonth == ValidLTime.date().month() ) {
00387
00388 kdDebug() << "Current time = Reverttime" << endl;
00389
00390
00391
00392 if ( automaticDSTchange ) {
00393
00394 setDST( !wasDSTactive );
00395 } else {
00396
00397 setDST( wasDSTactive );
00398 }
00399
00400 } else {
00401
00402 setDST( active_normal );
00403 }
00404 }
00405
00406
00407
00408 if (time_runs_forward) {
00409
00410 nextDSTChange_LTime( ValidLTime );
00411 nextDSTChange( next_change_ltime, TZoffset );
00412 } else {
00413
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 }