File indexing completed on 2024-04-28 07:32:29
0001 /* 0002 SPDX-FileCopyrightText: 2004 Jason Harris <jharris@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kstarsdatetime.h" 0008 0009 #include "dms.h" 0010 #include "ksnumbers.h" 0011 0012 #include <KLocalizedString> 0013 0014 #include <kstars_debug.h> 0015 0016 KStarsDateTime::KStarsDateTime() : QDateTime() 0017 { 0018 setTimeSpec(Qt::UTC); 0019 setDJD(J2000); 0020 } 0021 0022 KStarsDateTime::KStarsDateTime(const KStarsDateTime &kdt) : QDateTime() 0023 { 0024 *this = kdt; 0025 } 0026 0027 KStarsDateTime& KStarsDateTime::operator=(const KStarsDateTime &kdt) noexcept 0028 { 0029 setDJD(kdt.djd()); 0030 setTimeSpec(kdt.timeSpec()); 0031 //utcoffset deprecated 0032 //setUtcOffset(kdt.utcOffset()); 0033 return *this; 0034 } 0035 0036 /*KStarsDateTime::KStarsDateTime( const QDateTime &kdt ) : 0037 QDateTime( kdt ) 0038 { 0039 //don't call setDJD() because we don't need to compute the time; just set DJD directly 0040 QTime _t = kdt.time(); 0041 QDate _d = kdt.date(); 0042 long double jdFrac = ( _t.hour()-12 + ( _t.minute() + ( _t.second() + _t.msec()/1000.)/60.)/60.)/24.; 0043 DJD = static_cast<long double>( _d.toJulianDay() ) + jdFrac; 0044 }*/ 0045 0046 KStarsDateTime::KStarsDateTime(const QDateTime &qdt) : QDateTime(qdt) //, QDateTime::Spec::UTC() ) 0047 { 0048 // FIXME: This method might be buggy. Need to write some tests -- asimha (Oct 2016) 0049 QTime _t = qdt.time(); 0050 QDate _d = qdt.date(); 0051 long double jdFrac = (_t.hour() - 12 + (_t.minute() + (_t.second() + _t.msec() / 1000.) / 60.) / 60.) / 24.; 0052 DJD = static_cast<long double>(_d.toJulianDay()) + jdFrac; 0053 setTimeSpec(qdt.timeSpec()); 0054 //setUtcOffset(qdt.utcOffset()); 0055 } 0056 0057 KStarsDateTime::KStarsDateTime(const QDate &_d, const QTime &_t, Qt::TimeSpec timeSpec) 0058 : //QDateTime( _d, _t, QDateTime::Spec::UTC() ) 0059 QDateTime(_d, _t, timeSpec) 0060 { 0061 //don't call setDJD() because we don't need to compute the time; just set DJD directly 0062 long double jdFrac = (_t.hour() - 12 + (_t.minute() + (_t.second() + _t.msec() / 1000.) / 60.) / 60.) / 24.; 0063 DJD = static_cast<long double>(_d.toJulianDay()) + jdFrac; 0064 } 0065 0066 KStarsDateTime::KStarsDateTime(long double _jd) : QDateTime() 0067 { 0068 setTimeSpec(Qt::UTC); 0069 setDJD(_jd); 0070 } 0071 0072 //KStarsDateTime KStarsDateTime::currentDateTime( QDateTime::Spec spec ) { 0073 KStarsDateTime KStarsDateTime::currentDateTime() 0074 { 0075 KStarsDateTime dt(QDateTime::currentDateTime()); 0076 // if ( dt.time().hour()==0 && dt.time().minute()==0 ) // midnight or right after? 0077 // dt.setDate( QDateTime::currentDateTime(spec).date() ); // fetch date again 0078 0079 return dt; 0080 } 0081 0082 KStarsDateTime KStarsDateTime::currentDateTimeUtc() 0083 { 0084 KStarsDateTime dt(QDateTime::currentDateTimeUtc()); 0085 //if ( dt.time().hour()==0 && dt.time().minute()==0 ) // midnight or right after? 0086 // dt.setDate( QDateTime::currentDateTime(spec).date() ); // fetch date again 0087 0088 return dt; 0089 } 0090 0091 KStarsDateTime KStarsDateTime::fromString(const QString &s) 0092 { 0093 //DEBUG 0094 qCDebug(KSTARS) << "Date string: " << s; 0095 0096 KStarsDateTime dtResult(QDateTime::fromString(s, Qt::TextDate)); 0097 0098 if (dtResult.isValid()) 0099 return dtResult; 0100 0101 dtResult = KStarsDateTime(QDateTime::fromString(s, Qt::ISODate)); 0102 if (dtResult.isValid()) 0103 return dtResult; 0104 0105 //dtResult = QDateTime::fromString( s, QDateTime::RFCDate ); 0106 dtResult = KStarsDateTime(QDateTime::fromString(s, Qt::RFC2822Date)); 0107 if (dtResult.isValid()) 0108 return dtResult; 0109 0110 qCWarning(KSTARS) << "Could not parse Date/Time string:" << s; 0111 qCWarning(KSTARS) << "Valid date formats:"; 0112 qCWarning(KSTARS) << " 1950-02-25 ; 1950-02-25T05:30:00"; 0113 qCWarning(KSTARS) << " 25 Feb 1950 ; 25 Feb 1950 05:30:00"; 0114 qCWarning(KSTARS) << " Sat Feb 25 1950 ; Sat Feb 25 05:30:00 1950"; 0115 return KStarsDateTime(QDateTime()); //invalid 0116 } 0117 0118 void KStarsDateTime::setDJD(long double _jd) 0119 { 0120 //QDateTime::setTimeSpec( QDateTime::Spec::UTC() ); 0121 //QDateTime::setTimeSpec(Qt::UTC); 0122 0123 DJD = _jd; 0124 long int ijd = (long int)_jd; 0125 double dayfrac = _jd - (double)ijd + 0.5; 0126 if (dayfrac > 1.0) 0127 { 0128 ijd++; 0129 dayfrac -= 1.0; 0130 } 0131 0132 QDate dd = QDate::fromJulianDay(ijd); 0133 QDateTime::setDate(dd); 0134 0135 double hour = 24. * dayfrac; 0136 int h = int(hour); 0137 int m = int(60. * (hour - h)); 0138 int s = int(60. * (60. * (hour - h) - m)); 0139 int ms = int(1000. * (60. * (60. * (hour - h) - m) - s)); 0140 0141 QDateTime::setTime(QTime(h, m, s, ms)); 0142 } 0143 0144 void KStarsDateTime::setDate(const QDate &_d) 0145 { 0146 //Save the JD fraction 0147 long double jdFrac = djd() - static_cast<long double>(date().toJulianDay()); 0148 0149 //set the integer portion of the JD and add back the JD fraction: 0150 setDJD(static_cast<long double>(_d.toJulianDay()) + jdFrac); 0151 } 0152 0153 KStarsDateTime KStarsDateTime::addSecs(double s) const 0154 { 0155 long double ds = static_cast<long double>(s) / 86400.; 0156 KStarsDateTime kdt(djd() + ds); 0157 kdt.setTimeSpec(timeSpec()); 0158 return kdt; 0159 } 0160 0161 void KStarsDateTime::setTime(const QTime &_t) 0162 { 0163 KStarsDateTime _dt(date(), _t, timeSpec()); 0164 setDJD(_dt.djd()); 0165 } 0166 0167 dms KStarsDateTime::gst() const 0168 { 0169 dms gst0 = GSTat0hUT(); 0170 0171 double hr = double(time().hour() - offsetFromUtc() / 3600.0); 0172 double mn = double(time().minute()); 0173 double sc = double(time().second()) + double(0.001 * time().msec()); 0174 double st = (hr + (mn + sc / 60.0) / 60.0) * SIDEREALSECOND; 0175 0176 dms gst = dms(gst0.Degrees() + st * 15.0).reduce(); 0177 return gst; 0178 } 0179 0180 dms KStarsDateTime::GSTat0hUT() const 0181 { 0182 double sinOb, cosOb; 0183 0184 // Mean greenwich sidereal time 0185 KStarsDateTime t0(date(), QTime(0, 0, 0)); 0186 long double s = t0.djd() - J2000; 0187 double t = s / 36525.0; 0188 double t1 = 6.697374558 + 2400.051336 * t + 0.000025862 * t * t + 0.000000002 * t * t * t; 0189 0190 // To obtain the apparent sidereal time, we have to correct the 0191 // mean greenwich sidereal time with nutation in longitude multiplied 0192 // by the cosine of the obliquity of the ecliptic. This correction 0193 // is called nutation in right ascention, and may amount to 0.3 secs. 0194 KSNumbers num(t0.djd()); 0195 num.obliquity()->SinCos(sinOb, cosOb); 0196 0197 // nutLong has to be in hours of time since t1 is hours of time. 0198 double nutLong = num.dEcLong() * cosOb / 15.0; 0199 t1 += nutLong; 0200 0201 dms gst; 0202 gst.setH(t1); 0203 return gst.reduce(); 0204 } 0205 0206 QTime KStarsDateTime::GSTtoUT(dms GST) const 0207 { 0208 dms gst0 = GSTat0hUT(); 0209 0210 //dt is the number of sidereal hours since UT 0h. 0211 double dt = GST.Hours() - gst0.Hours(); 0212 while (dt < 0.0) 0213 dt += 24.0; 0214 while (dt >= 24.0) 0215 dt -= 24.0; 0216 0217 //convert to solar time. dt is now the number of hours since 0h UT. 0218 dt /= SIDEREALSECOND; 0219 0220 int hr = int(dt); 0221 int mn = int(60.0 * (dt - double(hr))); 0222 int sc = int(60.0 * (60.0 * (dt - double(hr)) - double(mn))); 0223 int ms = int(1000.0 * (60.0 * (60.0 * (dt - double(hr)) - double(mn)) - double(sc))); 0224 0225 return (QTime(hr, mn, sc, ms)); 0226 } 0227 0228 void KStarsDateTime::setFromEpoch(double epoch) 0229 { 0230 if (epoch == 1950.0) // Assume Besselian 0231 setFromEpoch(epoch, BESSELIAN); 0232 else 0233 setFromEpoch(epoch, JULIAN); // Assume Julian 0234 } 0235 0236 bool KStarsDateTime::setFromEpoch(double epoch, EpochType type) 0237 { 0238 if (type != JULIAN && type != BESSELIAN) 0239 return false; 0240 else 0241 setDJD(epochToJd(epoch, type)); 0242 return true; 0243 } 0244 0245 bool KStarsDateTime::setFromEpoch(const QString &eName) 0246 { 0247 bool result; 0248 double epoch; 0249 epoch = stringToEpoch(eName, result); 0250 0251 if (!result) 0252 return false; 0253 return setFromEpoch(epoch, JULIAN); // We've already converted 0254 } 0255 0256 long double KStarsDateTime::epochToJd(double epoch, EpochType type) 0257 { 0258 switch (type) 0259 { 0260 case BESSELIAN: 0261 return B1900 + (epoch - 1900.0) * JD_PER_BYEAR; 0262 case JULIAN: 0263 return J2000 + (epoch - 2000.0) * 365.25; 0264 default: 0265 return NaN::d; 0266 } 0267 } 0268 0269 double KStarsDateTime::jdToEpoch(long double jd, KStarsDateTime::EpochType type) 0270 { 0271 // Definitions for conversion formulas are from: 0272 // 0273 // * http://scienceworld.wolfram.com/astronomy/BesselianEpoch.html 0274 // * http://scienceworld.wolfram.com/astronomy/JulianEpoch.html 0275 // 0276 0277 switch (type) 0278 { 0279 case KStarsDateTime::BESSELIAN: 0280 return 1900.0 + (jd - KStarsDateTime::B1900) / KStarsDateTime::JD_PER_BYEAR; 0281 case KStarsDateTime::JULIAN: 0282 return 2000.0 + (jd - J2000) / 365.24; 0283 default: 0284 return NaN::d; 0285 } 0286 } 0287 0288 double KStarsDateTime::stringToEpoch(const QString &eName, bool &ok) 0289 { 0290 double epoch = J2000; 0291 ok = false; 0292 0293 if (eName.isEmpty()) // By default, assume J2000 0294 return epoch; 0295 0296 if (eName.startsWith('J')) 0297 epoch = eName.midRef(1).toDouble(&ok); 0298 else if (eName.startsWith('B')) 0299 { 0300 epoch = eName.midRef(1).toDouble(&ok); 0301 epoch = jdToEpoch(epochToJd(epoch, BESSELIAN), JULIAN); // Convert Besselian epoch to Julian epoch 0302 } 0303 // Assume it's Julian 0304 else 0305 epoch = eName.toDouble(&ok); 0306 0307 return epoch; 0308 }