General Purpose Geodetic Library
SgMJD.cpp
Go to the documentation of this file.
1 /*
2  *
3  * This file is a part of Space Geodetic Library. The library is used by
4  * nuSolve, a part of CALC/SOLVE system, and designed to make analysis of
5  * geodetic VLBI observations.
6  * Copyright (C) 2010-2020 Sergei Bolotin.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include <iostream>
24 #include <stdlib.h>
25 
26 
27 #include <QtCore/QDataStream>
28 
29 #include <SgLogger.h>
30 #include <SgMathSupport.h>
31 #include <SgMJD.h>
32 
33 
34 
35 /*=======================================================================================================
36 *
37 * METHODS:
38 *
39 *======================================================================================================*/
40 //
41 // static first:
42 double SgMJD::calcPartOfDay(int hour, int min, double sec)
43 {
44  return sec/DAY2SEC + (double)min/1440.0 + (double)hour/24.0;
45 };
46 
47 
48 
49 // static:
50 // where did I get this code?
51 // TODO: check & upgrade
52 int SgMJD::calcDayNumber(int year, int month, int day)
53 {
54  unsigned int century, yrsInCent;
55  if (year<=57) //? should we get rid of this?
56  year += 2000;
57  if (year<=99) //? should we get rid of this too?
58  year += 1900;
59  if (month>2)
60  month -= 3;
61  else
62  {
63  month += 9;
64  year--;
65  };
66  century = year/100;
67  yrsInCent = year - 100*century;
68  return -678882 + day + (146097*century)/4 + (1461*yrsInCent)/4 + (153*month + 2)/5;
69 };
70 
71 
72 
73 // the reverse procedure:
74 // TODO: check & upgrade
75 void SgMJD::MJD_reverse(int date, double time,
76  int& nYear, int& nMonth, int& nDay, int& nHour, int& nMin, double& dSec)
77 {
78  if (time>=1.0)
79  {
80  time--;
81  date++;
82  };
83  // integer days:
84  unsigned int x;
85  unsigned int j=date + 678882;
86  nYear = (j*4 - 1)/146097;
87  j = j*4 - 146097*nYear - 1;
88  x = j/4;
89  j = (x*4 + 3) / 1461;
90  nYear = 100*nYear + j;
91  x = x*4 + 3 - 1461*j;
92  x = (x + 4)/4;
93  nMonth = (5*x - 3)/153;
94  x = 5*x - 3 - 153*nMonth;
95  nDay = (x + 5)/5;
96  if (nMonth < 10)
97  nMonth += 3;
98  else
99  {
100  nMonth -= 9;
101  nYear++;
102  };
103 
104  // part of day:
105  double dTmp=time*DAY2SEC + 1.0E-7;
106  nHour = (int)floor(dTmp/3600.0);
107  nMin = (int)floor((dTmp - 3600.0*nHour)/60.0);
108  dSec = dTmp - 3600.0*nHour - 60.0*nMin;
109  if (dSec >= 1.0E-7)
110  dSec -= 1.0E-7;
111  else
112  dSec = 0.0;
113 };
114 
115 
116 
117 //
118 // here we use Qt library (should we roll back to LibC?):
120 {
121  QDateTime d(QDate::currentDate(), QTime::currentTime());
122  SgMJD currentEpoch( d.date().year(), d.date().month(), d.date().day(),
123  d.time().hour(), d.time().minute(),
124  d.time().second()+d.time().msec()*0.001);
125  return currentEpoch;
126 };
127 //
128 // end of statics.
129 //
130 
131 
132 
133 //
134 //
136 {
137  while(time_>=1.0)
138  {
139  time_--;
140  date_++;
141  };
142  while(time_<0.0)
143  {
144  time_++;
145  date_--;
146  };
147 };
148 
149 
150 
151 //
152 QDateTime SgMJD::toQDateTime() const
153 {
154  int nYr, nMo, nDy, nHr, nMi, nSec, nMsec;
155  double dSec;
156 
157  SgMJD::MJD_reverse(date_, time_, nYr, nMo, nDy, nHr, nMi, dSec);
158  nSec = (int)floor(dSec);
159  nMsec = (int)floor((dSec - nSec)*1000.0);
160  return QDateTime(QDate(nYr, nMo, nDy), QTime(nHr, nMi, nSec, nMsec), Qt::UTC);
161 };
162 
163 
164 
165 //
166 void SgMJD::setTime(double dTime)
167 {
168  time_ = dTime;
169  normalize();
170 };
171 
172 
173 
174 //
176 {
177  // split input on two parts:
178  int nDays=(int)trunc(days);
179  double dPart=days - nDays;
180  // make operation:
181  date_ += nDays;
182  time_ += dPart;
183  normalize();
184  return *this;
185 };
186 
187 
188 
189 //
191 {
192  // split input on two parts:
193  int nDays=(int)trunc(days);
194  double dPart=days - nDays;
195  // make operation:
196  date_ -= nDays;
197  time_ -= dPart;
198  normalize();
199  return *this;
200 };
201 
202 
203 
204 //
205 int SgMJD::calcYear() const
206 {
207  int nYear, nMonth, nDay, nHour, nMin;
208  double dSec;
209  MJD_reverse(date_, time_, nYear, nMonth, nDay, nHour, nMin, dSec);
210  return nYear;
211 };
212 
213 
214 
215 //
216 int SgMJD::calcMonth() const
217 {
218  int nYear, nMonth, nDay, nHour, nMin;
219  double dSec;
220  MJD_reverse(date_, time_, nYear, nMonth, nDay, nHour, nMin, dSec);
221  return nMonth;
222 };
223 
224 
225 
226 //
227 int SgMJD::calcDay() const
228 {
229  int nYear, nMonth, nDay, nHour, nMin;
230  double dSec;
231  MJD_reverse(date_, time_, nYear, nMonth, nDay, nHour, nMin, dSec);
232  return nDay;
233 };
234 
235 
236 
237 //
239 {
240  return date_ - calcDayNumber(calcYear(), 1, 1) + 1;
241 };
242 
243 
244 
245 // similar to month number, it is in the range [1..7]:
247 {
248  int i = (date_ - 55291)%7;//today is Monday, 5th of April 2010, MJD is 55291.
249  return (i<0?i+7:i)+1;
250 };
251 
252 
253 
254 // sets up epoch:
255 void SgMJD::setUpEpoch(int nYear, int nMonth, int nDay, int nHour, int nMin, double dSec)
256 {
257  if (nMonth != 0)
258  date_ = calcDayNumber(nYear, nMonth, nDay);
259  else // month==0 and day is DOY like in sinex
260  date_ = calcDayNumber(nYear, 1, 1) + nDay - 1;
261  time_ = calcPartOfDay(nHour, nMin, dSec);
262  normalize();
263 };
264 
265 
266 
267 // parses input string and sets epoch:
268 bool SgMJD::fromString(Format F, const QString& s, bool isReset)
269 {
270  int i, nYear, nMonth, nDay, nHour, nMin;
271  double dSec, d;
272  bool isOk;
273  QString tmp;
274  isOk = false;
275 
276  if (isReset)
277  *this = tZero;
278 
279  if (s=="UNKNOWN")
280  {
281  // complain?
282  return isOk;
283  };
284 
285  switch(F)
286  {
287  case F_Verbose:
288  // Verbose representation of an epoch:
289  // 0123456789012345678901234567
290  // 12 Apr, 2010; 01:03:25.2000
291  if (s.length()<27)
292  {
293  // complain
294  return isOk;
295  };
296  nDay = s.mid(0,2).toInt(&isOk);
297  if (!isOk)
298  {
299  // complain
300  return isOk;
301  };
302  nMonth = 0;
303  tmp = s.mid(3,3);
304  for (i=0; i<12; i++)
305  if (tmp.startsWith(shortMonthNames_[i]))
306  nMonth = i + 1;
307  if (nMonth==0) // month not found
308  {
309  // complain
310  return isOk;
311  };
312  nYear = s.mid(8,4).toInt(&isOk);
313  if (!isOk)
314  {
315  // complain
316  return isOk;
317  };
318  nHour = s.mid(14,2).toInt(&isOk);
319  if (!isOk)
320  {
321  // complain
322  return isOk;
323  };
324  nMin = s.mid(17,2).toInt(&isOk);
325  if (!isOk)
326  {
327  // complain
328  return isOk;
329  };
330  dSec = s.mid(20,7).toDouble(&isOk);
331  if (!isOk)
332  {
333  // complain
334  return isOk;
335  };
336  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, dSec);
337  break;
338 
339  case F_VerboseLong: // is there a sence to make parsering for it?
340  // Mon, the 12th of Apr, 2010; 01hr 03min 25.2000sec
341  break;
342 
343  case F_Simple:
344  case F_YYYYMMDDHHMMSSSS:
345  // 0123456789012345678901
346  // 2010/04/12 01:03:25.2
347  if (s.length()<19)
348  {
349  // complain
350  return isOk;
351  };
352  nDay = s.mid(8,2).toInt(&isOk);
353  if (!isOk)
354  {
355  // complain
356  return isOk;
357  };
358  nMonth = s.mid(5,2).toInt(&isOk);
359  if (!isOk)
360  {
361  // complain
362  return isOk;
363  };
364  nYear = s.mid(0,4).toInt(&isOk);
365  if (!isOk)
366  {
367  // complain
368  return isOk;
369  };
370  nHour = s.mid(11,2).toInt(&isOk);
371  if (!isOk)
372  {
373  // complain
374  return isOk;
375  };
376  nMin = s.mid(14,2).toInt(&isOk);
377  if (!isOk)
378  {
379  // complain
380  return isOk;
381  };
382  dSec = s.mid(17,4).toDouble(&isOk);
383  if (!isOk)
384  {
385  // complain
386  return isOk;
387  };
388  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, dSec);
389  break;
390 
391  case F_YYYYMMDDSSSSSS:
392  // 012345678901234
393  // 20100412038051
394  if (s.length()<14)
395  {
396  // complain
397  return isOk;
398  };
399  nDay = s.mid(6,2).toInt(&isOk);
400  if (!isOk)
401  {
402  // complain
403  return isOk;
404  };
405  nMonth = s.mid(4,2).toInt(&isOk);
406  if (!isOk)
407  {
408  // complain
409  return isOk;
410  };
411  nYear = s.mid(0,4).toInt(&isOk);
412  if (!isOk)
413  {
414  // complain
415  return isOk;
416  };
417  dSec = s.mid(8,6).toDouble(&isOk);
418  if (!isOk)
419  {
420  // complain
421  return isOk;
422  };
423  setUpEpoch(nYear, nMonth, nDay, 0, 0, dSec/10.0);
424  break;
425 
426 
427  case F_YYYYMMDDDD:
428  // 012345678901234
429  // 20100412.04
430  if (s.length()<11)
431  {
432  // complain
433  return isOk;
434  };
435  nDay = s.mid(6,2).toInt(&isOk);
436  if (!isOk)
437  {
438  // complain
439  return isOk;
440  };
441  nMonth = s.mid(4,2).toInt(&isOk);
442  if (!isOk)
443  {
444  // complain
445  return isOk;
446  };
447  nYear = s.mid(0,4).toInt(&isOk);
448  if (!isOk)
449  {
450  // complain
451  return isOk;
452  };
453  dSec = s.mid(9).toDouble(&isOk);
454  if (!isOk)
455  {
456  // complain
457  return isOk;
458  };
459  setUpEpoch(nYear, nMonth, nDay, 0, 0, dSec*86400.0);
460  break;
461 
462 
463  case F_INTERNAL: //MJDate:TimeInSeconds
464  // 01234567890123456789
465  // 055298:03805.200000
466  if (s.length()<19)
467  {
468  // complain
469  return isOk;
470  };
471  if (s.mid(6,1)!=":")
472  {
473  // complain
474  return isOk;
475  };
476  nDay = s.mid(0,6).toInt(&isOk);
477  if (!isOk)
478  {
479  // complain
480  return isOk;
481  };
482  dSec = s.mid(7,12).toDouble(&isOk);
483  if (!isOk)
484  {
485  // complain
486  return isOk;
487  };
488  date_ = nDay;
489  time_ = dSec/DAY2SEC;
490  break;
491 
492  case F_ECCDAT:
493  // 01234567890123456
494  // 2010.04.12-01.03
495  if (s.length()<16)
496  {
497  // complain
498  return isOk;
499  };
500  nYear = s.mid(0,4).toInt(&isOk);
501  if (!isOk)
502  {
503  // complain
504  return isOk;
505  };
506  nMonth = s.mid(5,2).toInt(&isOk);
507  if (!isOk)
508  {
509  // complain
510  return isOk;
511  };
512  nDay = s.mid(8,2).toInt(&isOk);
513  if (!isOk)
514  {
515  // complain
516  return isOk;
517  };
518  nHour = s.mid(11,2).toInt(&isOk);
519  if (!isOk)
520  {
521  // complain
522  return isOk;
523  };
524  nMin = s.mid(14,2).toInt(&isOk);
525  if (!isOk)
526  {
527  // complain
528  return isOk;
529  };
530  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, 0.0);
531  break;
532 
533  case F_SOLVE_SPLFL:
534  case F_SOLVE_SPLFL_V2:
535  case F_SOLVE_SPLFL_V3:
536  // 01234567890123456789
537  // 2012.01.20-09:14:28
538  if (s.length()<19)
539  {
540  // complain
541  return isOk;
542  };
543  nYear = s.mid(0,4).toInt(&isOk);
544  if (!isOk)
545  {
546  // complain
547  return isOk;
548  };
549  nMonth = s.mid(5,2).toInt(&isOk);
550  if (!isOk)
551  {
552  // complain
553  return isOk;
554  };
555  nDay = s.mid(8,2).toInt(&isOk);
556  if (!isOk)
557  {
558  // complain
559  return isOk;
560  };
561  nHour = s.mid(11,2).toInt(&isOk);
562  if (!isOk)
563  {
564  // complain
565  return isOk;
566  };
567  nMin = s.mid(14,2).toInt(&isOk);
568  if (!isOk)
569  {
570  // complain
571  return isOk;
572  };
573  dSec = s.mid(17).toDouble(&isOk);
574  if (!isOk)
575  {
576  // complain
577  return isOk;
578  };
579  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, dSec);
580  break;
581 
582  case F_SOLVE_SPLFL_LONG:
583  // 012345678901234567890123
584  // 2012.01.20-09:32:00.960
585  if (s.length()<23)
586  {
587  // complain
588  return isOk;
589  };
590  nYear = s.mid(0,4).toInt(&isOk);
591  if (!isOk)
592  {
593  // complain
594  return isOk;
595  };
596  nMonth = s.mid(5,2).toInt(&isOk);
597  if (!isOk)
598  {
599  // complain
600  return isOk;
601  };
602  nDay = s.mid(8,2).toInt(&isOk);
603  if (!isOk)
604  {
605  // complain
606  return isOk;
607  };
608  nHour = s.mid(11,2).toInt(&isOk);
609  if (!isOk)
610  {
611  // complain
612  return isOk;
613  };
614  nMin = s.mid(14,2).toInt(&isOk);
615  if (!isOk)
616  {
617  // complain
618  return isOk;
619  };
620  dSec = s.mid(17,6).toDouble(&isOk);
621  if (!isOk)
622  {
623  // complain
624  return isOk;
625  };
626  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, dSec);
627  break;
628 
629  case F_FS_LOG:
630  // 012345678901234567890123
631  // 2020.195.11:15:34.11
632  if (s.length()<17)
633  {
634  // complain
635  return isOk;
636  };
637  nYear = s.mid(0,4).toInt(&isOk);
638  if (!isOk)
639  {
640  // complain
641  return isOk;
642  };
643  nDay = s.mid(5,3).toInt(&isOk);
644  if (!isOk)
645  {
646  // complain
647  return isOk;
648  };
649  nHour = s.mid(9,2).toInt(&isOk);
650  if (!isOk)
651  {
652  // complain
653  return isOk;
654  };
655  nMin = s.mid(12,2).toInt(&isOk);
656  if (!isOk)
657  {
658  // complain
659  return isOk;
660  };
661  dSec = s.mid(15,5).toDouble(&isOk);
662  if (!isOk)
663  {
664  // complain
665  return isOk;
666  };
667  setUpEpoch(nYear, 0, nDay, nHour, nMin, dSec);
668  break;
669 
670  case F_SOLVE_SPLFL_SHORT:
671  // 01234567890123456789
672  // 12/01/20 00:02
673  if (s.length()<14)
674  {
675  // complain
676  return isOk;
677  };
678  nYear = s.mid(0,2).toInt(&isOk);
679  nYear += (nYear<65)?2000:1900;
680  if (!isOk)
681  {
682  // complain
683  return isOk;
684  };
685  nMonth = s.mid(3,2).toInt(&isOk);
686  if (!isOk)
687  {
688  // complain
689  return isOk;
690  };
691  nDay = s.mid(6,2).toInt(&isOk);
692  if (!isOk)
693  {
694  // complain
695  return isOk;
696  };
697  nHour = s.mid(9,2).toInt(&isOk);
698  if (!isOk)
699  {
700  // complain
701  return isOk;
702  };
703  nMin = s.mid(12,2).toInt(&isOk);
704  if (!isOk)
705  {
706  // complain
707  return isOk;
708  };
709  setUpEpoch(nYear, nMonth, nDay, nHour, nMin, 0.0);
710  break;
711 
712  case F_MJD:
713  // 01234567890
714  // 55298.0440
715  if (s.length()<10)
716  {
717  // complain
718  return isOk;
719  };
720  d = s.toDouble(&isOk);
721  if (!isOk)
722  {
723  // complain
724  return isOk;
725  };
726  date_ = (int)floor(d);
727  time_ = d - (double)date_;
728  break;
729 
730  case F_UNIX:
731  // 0123456789012345
732  // 1271034205.2000
733  if (s.length()<15)
734  {
735  // complain
736  return isOk;
737  };
738  d = s.toDouble(&isOk);
739  if (!isOk)
740  {
741  // complain
742  return isOk;
743  };
744  *this = SgMJD(tUnix0 + d/86400.0);
745  break;
746 
747  case F_SINEX:
748  // 0123456789012
749  // 10:102:03805
750  if (s.length()<12)
751  {
752  // complain
753  return isOk;
754  };
755  nYear = s.mid(0,2).toInt(&isOk);
756  if (!isOk)
757  {
758  // complain
759  return isOk;
760  };
761  nDay = s.mid(3,3).toInt(&isOk);
762  if (!isOk)
763  {
764  // complain
765  return isOk;
766  };
767  dSec = s.mid(7,5).toDouble(&isOk);
768  if (!isOk)
769  {
770  // complain
771  return isOk;
772  };
773  setUpEpoch(nYear<=50? nYear+2000 : nYear+1900, 0, nDay, 0, 0, dSec);
774  break;
775 
776 
777  case F_ISO: // e.g.,
778  *this = SgMJD(QDateTime::fromString(s, Qt::ISODate));
779  break;
780 
781  case F_RFC2822: // e.g.,
782  *this = SgMJD(QDateTime::fromString(s, Qt::RFC2822Date));
783  break;
784 
785 
786  // date only:
787  case F_Date:
788  // 012345678901
789  // 2010 Apr 12
790  if (s.length()<11)
791  {
792  // complain
793  return isOk;
794  };
795  nDay = s.mid(9,2).toInt(&isOk);
796  if (!isOk)
797  {
798  // complain
799  return isOk;
800  };
801  nMonth = 0;
802  tmp = s.mid(5,3);
803  for (i=0; i<12; i++)
804  if (tmp.startsWith(shortMonthNames_[i]))
805  nMonth = i + 1;
806  if (nMonth==0) // month not found
807  {
808  // complain
809  return isOk;
810  };
811  nYear = s.mid(0,4).toInt(&isOk);
812  if (!isOk)
813  {
814  // complain
815  return isOk;
816  };
817  setUpEpoch(nYear, nMonth, nDay, 0, 0, 0.0);
818  break;
819 
820  case F_DDMonYYYY:
821  // 0123456789012
822  // 12 Apr, 2010
823  if (s.length()<12)
824  {
825  // complain
826  return isOk;
827  };
828  nDay = s.mid(0,2).toInt(&isOk);
829  if (!isOk)
830  {
831  // complain
832  return isOk;
833  };
834  nMonth = 0;
835  tmp = s.mid(3,3);
836  for (i=0; i<12; i++)
837  if (tmp.startsWith(shortMonthNames_[i]))
838  nMonth = i + 1;
839  if (nMonth==0) // month not found
840  {
841  // complain
842  return isOk;
843  };
844  nYear = s.mid(8,4).toInt(&isOk);
845  if (!isOk)
846  {
847  // complain
848  return isOk;
849  };
850  setUpEpoch(nYear, nMonth, nDay, 0, 0, 0.0);
851  break;
852 
853  case F_YYYYMMDD:
854  case F_yyyymmdd:
855  // 01234567890
856  // 2010 04 12
857  if (s.length()<10)
858  {
859  // complain
860  return isOk;
861  };
862  nYear = s.mid(0,4).toInt(&isOk);
863  if (!isOk)
864  {
865  // complain
866  return isOk;
867  };
868  nMonth = s.mid(5,2).toInt(&isOk);
869  if (!isOk)
870  {
871  // complain
872  return isOk;
873  };
874  nDay = s.mid(8,2).toInt(&isOk);
875  if (!isOk)
876  {
877  // complain
878  return isOk;
879  };
880  setUpEpoch(nYear, nMonth, nDay, 0, 0, 0.0);
881  break;
882 
883  case F_YYMonDD:
884  // 01234567
885  // 10Apr12
886  if (s.length()<7)
887  {
888  // complain
889  return isOk;
890  };
891  nDay = s.mid(5,2).toInt(&isOk);
892  if (!isOk)
893  {
894  // complain
895  return isOk;
896  };
897  nMonth = 0;
898  tmp = s.mid(2,3);
899  for (i=0; i<12; i++)
900  if (tmp.startsWith(shortMonthNames_[i], Qt::CaseInsensitive ))
901  nMonth = i + 1;
902  if (nMonth==0) // month not found
903  {
904  // complain
905  return isOk;
906  };
907  nYear = s.mid(0,2).toInt(&isOk);
908  if (!isOk)
909  {
910  // complain
911  return isOk;
912  };
913  setUpEpoch(nYear<=50? nYear+2000 : nYear+1900, nMonth, nDay, 0, 0, 0.0);
914  break;
915 
916  case F_YYYYMonDD:
917  // 0123456789
918  // 2016Mar01
919  if (s.length()<9)
920  {
921  // complain
922  return isOk;
923  };
924  nDay = s.mid(7,2).toInt(&isOk);
925  if (!isOk)
926  {
927  // complain
928  return isOk;
929  };
930  nMonth = 0;
931  tmp = s.mid(4,3);
932  for (i=0; i<12; i++)
933  if (tmp.startsWith(shortMonthNames_[i], Qt::CaseInsensitive ))
934  nMonth = i + 1;
935  if (nMonth==0) // month not found
936  {
937  // complain
938  return isOk;
939  };
940  nYear = s.mid(0,4).toInt(&isOk);
941  if (!isOk)
942  {
943  // complain
944  return isOk;
945  };
946  setUpEpoch(nYear, nMonth, nDay, 0, 0, 0.0);
947  break;
948 
949  case F_Year:
950  // 01234567
951  // 2010.28
952  if (s.length()<7)
953  {
954  // complain
955  return isOk;
956  };
957  d = s.toDouble(&isOk);
958  if (!isOk)
959  {
960  // complain
961  return isOk;
962  };
963  date_ = calcDayNumber((int)floor(d), 1, 1); // MJD on the begin of the year
964  time_ = 365.25*fmod(d, 1.0);
965  normalize();
966  break;
967 
968  case F_SINEX_S:
969  // 0123456
970  // 10:102
971  if (s.length()<6)
972  {
973  // complain
974  return isOk;
975  };
976  nYear = s.mid(0,2).toInt(&isOk);
977  if (!isOk)
978  {
979  // complain
980  return isOk;
981  };
982  nDay = s.mid(3,3).toInt(&isOk);
983  if (!isOk)
984  {
985  // complain
986  return isOk;
987  };
988  setUpEpoch(nYear<=50? nYear+2000 : nYear+1900, 0, nDay, 0, 0, 0.0);
989  break;
990 
991  // unsupported formats (just time):
992  case F_Time:
993  return isOk;
994  break;
995  case F_HHMMSS:
996  return isOk;
997  break;
998  case F_TimeShort:
999  return isOk;
1000  break;
1001  };
1002  return true;
1003 };
1004 
1005 
1006 
1007 // makes formatted output:
1008 QString SgMJD::toString(Format F) const
1009 {
1010  QString s("UNKNOWN");
1011  QString th;
1012  int nYear, nMonth, nDay, nHour, nMin;
1013  double dSec;
1014 
1015  if (date_==0)
1016  return s;
1017 
1018  MJD_reverse(date_, time_, nYear, nMonth, nDay, nHour, nMin, dSec);
1019  switch(F)
1020  {
1021  // date and time:
1022  case F_Verbose: // e.g., 12 Apr, 2010; 01:03:25.2000
1023  s.sprintf("%02d %s, %04d; %02d:%02d:%07.4f",
1024  nDay, shortMonthNames_[nMonth-1], nYear,
1025  nHour, nMin, dSec);
1026  break;
1027 
1028  case F_VerboseLong: // e.g., Mon, the 12th of Apr, 2010; 01hr 03min 25.2000sec
1029  switch (nDay)
1030  {
1031  case 1:
1032  case 21:
1033  case 31:
1034  th="st";
1035  break;
1036  case 2:
1037  case 22:
1038  th="nd";
1039  break;
1040  case 3:
1041  case 23:
1042  th="rd";
1043  break;
1044  default:
1045  th="th";
1046  };
1047  s.sprintf("%s, the %d%s of %s, %04d; %02dhr %02dmin %07.4fsec",
1048  qPrintable(dayOfWeek2Str()), nDay, qPrintable(th), shortMonthNames_[nMonth-1], nYear,
1049  nHour, nMin, dSec);
1050  break;
1051 
1052  case F_YYYYMMDDHHMMSSSS: // e.g., 2010/04/12 01:03:25.2
1053  s.sprintf("%04d/%02d/%02d %02d:%02d:%04.1f", nYear, nMonth, nDay, nHour, nMin, dSec);
1054  break;
1055  case F_Simple: // e.g., 2010/04/12 01:03:25
1056  s.sprintf("%04d/%02d/%02d %02d:%02d:%02d", nYear, nMonth, nDay, nHour, nMin, (int)(round(dSec)));
1057  break;
1058 
1059  case F_YYYYMMDDSSSSSS: // e.g., 20100412038051
1060  s.sprintf("%04d%02d%02d%06d", nYear, nMonth, nDay, nHour*36000 + nMin*600 + (int)(round(dSec*10.0)));
1061  break;
1062 
1063  case F_YYYYMMDDDD: // e.g., 20100412.04
1064  s.sprintf("%04d%02d%02d.%02d", nYear, nMonth, nDay, (int)round((nHour*3600 + nMin*60 + dSec)/864.0));
1065  break;
1066 
1067  case F_INTERNAL: // e.g., 055298:03805.200000
1068  s.sprintf("%06d:%012.6f", date_, time_*DAY2SEC);
1069  break;
1070 
1071  case F_ECCDAT: // e.g., 2010.04.12-01.03
1072  s.sprintf("%04d.%02d.%02d-%02d.%02d", nYear, nMonth, nDay, nHour, nMin);
1073  break;
1074 
1075  case F_SOLVE_SPLFL: // e.g., 2012.01.20-09:14:28
1076  s.sprintf("%04d.%02d.%02d-%02d:%02d:%02d", nYear, nMonth, nDay, nHour, nMin, (int)(round(dSec)));
1077  break;
1078 
1079  case F_SOLVE_SPLFL_V2: // e.g., 2014.11.18-18:30:31.0
1080  s.sprintf("%04d.%02d.%02d-%02d:%02d:%04.1f", nYear, nMonth, nDay, nHour, nMin, dSec);
1081  break;
1082 
1083  case F_SOLVE_SPLFL_V3: // e.g., 2014.11.18-18:30:31.05
1084  s.sprintf("%04d.%02d.%02d-%02d:%02d:%05.2f", nYear, nMonth, nDay, nHour, nMin, dSec);
1085  break;
1086 
1087  case F_SOLVE_SPLFL_SHORT: // e.g., 12/01/20 00:02
1088  nYear -= (nYear/100)*100;
1089  s.sprintf("%02d/%02d/%02d %02d:%02d", nYear, nMonth, nDay, nHour, nMin);
1090  break;
1091 
1092  case F_SOLVE_SPLFL_LONG: // e.g., 2012.01.20-09:32:00.960
1093  s.sprintf("%04d.%02d.%02d-%02d:%02d:%06.3f", nYear, nMonth, nDay, nHour, nMin, dSec);
1094  break;
1095 
1096  case F_FS_LOG:
1097  // 012345678901234567890123
1098  // 2020.195.11:15:34.11
1099  s.sprintf("%04d.%03d.%02d:%02d:%05.2f", nYear, calcDayOfYear(), nHour, nMin, dSec);
1100  break;
1101 
1102  case F_MJD: // e.g., 55298.0440
1103  s.sprintf("%10.4f", date_ + time_);
1104  break;
1105 
1106  case F_UNIX: // e.g., 1271034205.2000
1107  s.sprintf("%.4f", DAY2SEC*(*this - tUnix0));
1108  break;
1109 
1110  case F_SINEX: // e.g., 10:102:03805
1111  if (*this==tZero)
1112  s="00:000:00000";
1113  else
1114  s.sprintf("%02d:%03d:%05d",
1115  nYear-100*(nYear/100), calcDayOfYear(), (int)round(time_*DAY2SEC));
1116  break;
1117 
1118  case F_ISO: // e.g.,
1119  s = toQDateTime().toString(Qt::ISODate);
1120  break;
1121 
1122  case F_RFC2822: // e.g.,
1123  s = toQDateTime().toString(Qt::RFC2822Date);
1124  break;
1125 
1126  // date only:
1127  case F_Date: // e.g., 2010 Apr 12
1128  s.sprintf("%04d %s %02d", nYear, shortMonthNames_[nMonth-1], nDay);
1129  break;
1130 
1131  case F_DDMonYYYY: // e.g., 12 Apr, 2010
1132  s.sprintf("%02d %s, %04d", nDay, shortMonthNames_[nMonth-1], nYear);
1133  break;
1134 
1135  case F_YYYYMMDD: // e.g., 2010 04 12
1136  default:
1137  s.sprintf("%04d %02d %02d", nYear, nMonth, nDay);
1138  break;
1139 
1140  case F_yyyymmdd:
1141  s.sprintf("%04d.%02d.%02d", nYear, nMonth, nDay);
1142  break;
1143 
1144  case F_YYMonDD: // e.g., 10Apr12
1145  s.sprintf("%02d%s%02d", nYear-100*(nYear/100), shortMonthNames_[nMonth-1], nDay);
1146  break;
1147 
1148  case F_YYYYMonDD: // e.g., 2016Mar01
1149  s.sprintf("%04d%s%02d", nYear, shortMonthNames_[nMonth-1], nDay);
1150  break;
1151 
1152  case F_Year: // e.g., 2010.28
1153  s.sprintf("%7.2f", nYear + calcDayOfYear()/365.25);
1154  break;
1155 
1156  case F_SINEX_S: // e.g., 10:102
1157  s.sprintf("%02d:%03d", nYear-100*(nYear/100), calcDayOfYear());
1158  break;
1159 
1160  // time only:
1161  case F_Time: // e.g., 01:03:25.2
1162  if (dSec>59.9)
1163  {
1164  dSec = 0.0;
1165  nMin++;
1166  };
1167  if (nMin==60)
1168  {
1169  nHour++;
1170  nMin = 0;
1171  };
1172  s.sprintf("%02d:%02d:%04.1f", nHour, nMin, dSec);
1173  break;
1174 
1175  case F_HHMMSS: // e.g., 01:03:25
1176  s.sprintf("%02d:%02d:%02d", nHour, nMin, (int)floor(dSec));
1177  break;
1178 
1179  case F_TimeShort: // e.g., 01:03
1180  if (dSec>30.0)
1181  nMin++;
1182  if (nMin==60)
1183  {
1184  nHour++;
1185  nMin = 0;
1186  };
1187  s.sprintf("%02d:%02d", nHour, nMin);
1188  break;
1189  };
1190  return s;
1191 };
1192 
1193 
1194 
1195 // converts week's idx to string:
1196 QString SgMJD::dayOfWeek2Str() const
1197 {
1198  int dayOfWeek=calcDayOfWeek();
1199  if (1<=dayOfWeek && dayOfWeek<=7)
1200  return shortWeekdayNames_[dayOfWeek-1];
1201  else
1202  {
1204  QString().sprintf(": dayOfWeek2Str(): for the date %d dayOfWeek (%d) is out of ranges",
1205  date_, dayOfWeek));
1206  exit(1);
1207  };
1208 };
1209 
1210 
1211 
1212 // converts week's idx to string:
1214 {
1215  int dayOfWeek=calcDayOfWeek();
1216  if (1<=dayOfWeek && dayOfWeek<=7)
1217  return longWeekdayNames_[dayOfWeek-1];
1218  else
1219  {
1221  QString().sprintf(": dayOfWeek2LongStr(): for the date %d dayOfWeek (%d) is out of ranges",
1222  date_, dayOfWeek));
1223  exit(1);
1224  };
1225 };
1226 
1227 
1228 
1229 //
1231 {
1232  int yr, mn, dy;
1233  int hr, mi;
1234  double sc;
1235  MJD_reverse(date_, time_, yr, mn, dy, hr, mi, sc);
1236  QDateTime d(QDate(yr, mn, dy), QTime(hr, mi, (int)(round(sc))), Qt::LocalTime);
1237  QDateTime dUtc = d.toUTC();
1238  SgMJD epoch(dUtc.date().year(), dUtc.date().month(), dUtc.date().day(),
1239  dUtc.time().hour(), dUtc.time().minute(),
1240  dUtc.time().second()+dUtc.time().msec()*0.001);
1241  return epoch;
1242 };
1243 
1244 
1245 
1246 //
1248 {
1249  int yr, mn, dy;
1250  int hr, mi;
1251  double sc;
1252  MJD_reverse(date_, time_, yr, mn, dy, hr, mi, sc);
1253  QDateTime d(QDate(yr, mn, dy), QTime(hr, mi, (int)(round(sc))), Qt::UTC);
1254  QDateTime dLoc = d.toLocalTime();
1255  SgMJD epoch(dLoc.date().year(), dLoc.date().month(), dLoc.date().day(),
1256  dLoc.time().hour(), dLoc.time().minute(),
1257  dLoc.time().second()+dLoc.time().msec()*0.001);
1258  return epoch;
1259 };
1260 
1261 
1262 
1263 //
1264 double SgMJD::gmst() const
1265 {
1266  double dGmst, dGmst0h=0.0, dT_u=0.0, dT_u2=0.0, r;
1267 
1268  /*
1269  IERS Technical Note 21,
1270  IERS Conventions (1996)
1271  page 21 says:
1272 
1273  "Apparent Geenwich Sidereal Time GST at the date t of observations, must be derived
1274  from the following expressions:
1275 
1276  (i) the relationship between Greenwich Mean Sidereal Time (GMST) and Universal.
1277  Time as given by Aoki et al. (1982):
1278 
1279  with T'_u = d'_u/36525, d'_u being the number of days elapsed since.
1280  2000 January 1, 12h UT1, takin on values +/- 0.5, +/- 1.5, ...,"
1281  */
1282  dT_u = (date_ - tEphem)/36525.0;
1283  dT_u2 = dT_u*dT_u;
1284  dGmst0h = (24110.54841 + 8640184.812866*dT_u + 0.093104*dT_u2 - 6.2e-6*dT_u*dT_u2)/DAY2SEC; //days
1285 
1286  /*
1287  "where r is the ratio of universal to sidereal time as given by Aoki et al. (1992),"
1288  */
1289  r = 1.002737909350795 + 5.9006e-11*dT_u - 5.9e-15*dT_u2;
1290 
1291  /*
1292  "(ii) the interval of GMST from 0h UT1 to the hour of the observation in UT1,"
1293  */
1294  dGmst = dGmst0h + r*time_; // days
1295  dGmst = fmod(dGmst, 1.0); // days
1296  if (dGmst < 0.0)
1297  dGmst += 1.0;
1298 
1299  dGmst *= 2.0*M_PI; // rad
1300  return dGmst;
1301 };
1302 
1303 
1304 
1305 //
1306 void SgMJD::toYMDHMS_tr(int& nYear, int& nMonth, int& nDay, int& nHour, int& nMin, double& dSec) const
1307 {
1308  MJD_reverse(date_, time_, nYear, nMonth, nDay, nHour, nMin, dSec);
1309  dSec = 1.0e-8*round(dSec*1.0e8);
1310 };
1311 
1312 
1313 
1314 //
1316 {
1317  s << date_ << time_;
1318  if (s.status() != QDataStream::Ok)
1319  {
1321  ": saveIntermediateResults(): error writting data");
1322  return false;
1323  };
1324  return s.status() == QDataStream::Ok;
1325 };
1326 
1327 
1328 
1329 //
1331 {
1332  int date;
1333  double time;
1334  //
1335  s >> date >> time;
1336  if (s.status() != QDataStream::Ok)
1337  {
1339  ": loadIntermediateResults(): error reading data: " +
1340  (s.status()==QDataStream::ReadPastEnd?"read past end of the file":"read corrupt data"));
1341  return false;
1342  };
1343  date_ = date;
1344  time_ = time;
1345  //
1346  return s.status()==QDataStream::Ok;
1347 };
1348 /*=====================================================================================================*/
1349 
1350 
1351 
1352 
1353 
1354 
1355 /*=======================================================================================================
1356 *
1357 * FRIENDS:
1358 *
1359 *======================================================================================================*/
1360 //
1361 
1362 
1363 
1364 
1365 
1366 
1367 /*=====================================================================================================*/
1368 //
1369 // aux functions:
1370 //
1371 QString interval2Str(double days)
1372 {
1373  int nYears=0, nMonths=0, nDays=0, nHours=0, nMins=0;
1374  double dSecs=0.0;
1375  QString str("");
1376  bool isSignPositive=(days>=0.0);
1377 
1378  if (!isSignPositive)
1379  {
1380  days = -days;
1381  str = "-(";
1382  };
1383 
1384  if (days>=366.0)
1385  {
1386  nYears = (int)floor(days/365.25);
1387  days -= 365.25*nYears;
1388  };
1389  if (days>=31.0) // here mean month, 365.25/12, is 30 days 10hr and 30 min
1390  {
1391  nMonths = (int)floor(days*12.0/365.25);
1392  days -= nMonths*365.25/12.0;
1393  };
1394  if (days>=1.0)
1395  {
1396  nDays = (int)floor(days);
1397  days -= (double)nDays;
1398  };
1399 
1400  // ok, here days < 1.0, convert it to seconds:
1401  days *= DAY2SEC;
1402  nHours = (int)(days/3600.0);
1403  nMins = (int)((days - 3600.0*nHours)/60.0);
1404  dSecs = days - 3600.0*nHours - 60.0*nMins;
1405 
1406  if (nYears==0 && nMonths==0 && nDays==0 && nHours==0 && nMins==0 && dSecs<1.0)
1407  str += QString().sprintf("%.6g sec", dSecs); // special case of intervals, dt<1sec
1408  else
1409  {
1410  if (nYears)
1411  str += QString().sprintf("%d year%s ", nYears, nYears==1?"":"s");
1412  if (nMonths)
1413  str += QString().sprintf("%d month%s ", nMonths, nMonths==1?"":"s");
1414  if (nDays)
1415  str += QString().sprintf("%d day%s ", nDays, nDays==1?"":"s");
1416  if (nHours)
1417  str += QString().sprintf("%02dhr ", nHours);
1418  if (nMins)
1419  str += QString().sprintf("%02dmin ", nMins);
1420  str += QString().sprintf("%05.2fsec", dSecs);
1421 
1422 // Str += QString().sprintf("%02dhr %02dmin %05.2fsec", nHours, nMins, dSecs);
1423  };
1424  if (!isSignPositive)
1425  str += ")";
1426  return str;
1427 };
1428 
1429 
1430 
1431 // i/o:
1432 //
1433 
1434 
1435 /*=====================================================================================================*/
1436 //
1437 // constants:
1438 //
1439 const char *SgMJD::shortMonthNames_[] =
1440 {
1441  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1442  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1443 };
1444 
1445 const char *SgMJD::longMonthNames_[] =
1446 {
1447  "January", "February", "March", "April", "May", "June",
1448  "July", "August", "September", "October", "November", "December"
1449 };
1450 
1451 const char *SgMJD::shortWeekdayNames_[] =
1452 {
1453  "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
1454 };
1455 
1456 const char *SgMJD::longWeekdayNames_[] =
1457 {
1458  "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
1459 };
1460 
1461 
1462 const SgMJD tEphem(51544.5); // J2000 1Jan 12h 0m 0.0s
1463 const SgMJD tZero (1957,10, 4); // Sputnik 1 was launched on October 4, 1957
1464 const SgMJD tInf (2100, 1, 1); //
1465 const SgMJD tUnix0(1970, 1, 1); // Unix zero epoch
1466 /*=====================================================================================================*/
SgLogger * logger
Definition: SgLogger.cpp:231
QString interval2Str(double days)
Definition: SgMJD.cpp:1371
const SgMJD tUnix0(1970, 1, 1)
const SgMJD tZero(1957, 10, 4)
const SgMJD tInf(2100, 1, 1)
const SgMJD tEphem(51544.5)
#define DAY2SEC
radians to mas:
Definition: SgMathSupport.h:69
virtual void write(LogLevel, quint32, const QString &, bool=false)
Definition: SgLogger.cpp:88
@ IO_BIN
Definition: SgLogger.h:64
@ TIME
Definition: SgLogger.h:80
Definition: SgMJD.h:59
QString dayOfWeek2LongStr() const
Definition: SgMJD.cpp:1213
bool fromString(Format format, const QString &str, bool isReset=true)
Definition: SgMJD.cpp:268
int date_
Definition: SgMJD.h:354
void setTime(double dTime)
Definition: SgMJD.cpp:166
Format
Definition: SgMJD.h:62
@ F_Verbose
Definition: SgMJD.h:65
@ F_FS_LOG
Another version from spoolfile format: 2012.01.20-09:32:00.960.
Definition: SgMJD.h:79
@ F_SOLVE_SPLFL_LONG
Another version from spoolfile format: 12/01/20 00:02.
Definition: SgMJD.h:78
@ F_YYYYMMDD
Another format for a date: 02 Apr, 2010.
Definition: SgMJD.h:88
@ F_yyyymmdd
Date in digits: 2010 04 02.
Definition: SgMJD.h:89
@ F_YYYYMMDDHHMMSSSS
Long verbose: Fri, the 2nd of Apr, 2010; 17hr 02min 43.6400sec.
Definition: SgMJD.h:67
@ F_SOLVE_SPLFL_SHORT
Another spoolfile represenation of epoch: 2012.01.20-09:14:28.05.
Definition: SgMJD.h:77
@ F_DDMonYYYY
Date: 2010 Apr 02.
Definition: SgMJD.h:87
@ F_ECCDAT
Digits, MJD and seconds : 055288:61363.6400.
Definition: SgMJD.h:73
@ F_YYYYMMDDDD
Digits, date and seconds: 20100402613636.
Definition: SgMJD.h:71
@ F_RFC2822
ISO date format realized by Qt (Qt::ISODate)
Definition: SgMJD.h:84
@ F_SINEX
UNUX seconds: 1270227763.6400.
Definition: SgMJD.h:82
@ F_VerboseLong
Verbose output: 02 Apr, 2010; 17:02:43.6400.
Definition: SgMJD.h:66
@ F_SINEX_S
Year: 2010.25.
Definition: SgMJD.h:93
@ F_YYYYMonDD
Date in digits: 2010.04.02.
Definition: SgMJD.h:90
@ F_UNIX
Just MJD: 55288.7102.
Definition: SgMJD.h:81
@ F_YYMonDD
Date, short: 2016Mar01.
Definition: SgMJD.h:91
@ F_MJD
Field System logs: 2020.195.11:15:34.11.
Definition: SgMJD.h:80
@ F_YYYYMMDDSSSSSS
Digits: 2010/04/02 17:02:43.
Definition: SgMJD.h:70
@ F_ISO
SINEX format: 10:092:61364.
Definition: SgMJD.h:83
@ F_HHMMSS
Just time: 17:02:43.6.
Definition: SgMJD.h:96
@ F_SOLVE_SPLFL_V2
A spoolfile represenation of epoch: 2012.01.20-09:14:28.
Definition: SgMJD.h:75
@ F_Simple
Digits: 2010/04/02 17:02:43.6.
Definition: SgMJD.h:68
@ F_Date
RFC2822 date format realized by Qt (Qt::RFC2822Date)
Definition: SgMJD.h:86
@ F_SOLVE_SPLFL_V3
Another spoolfile represenation of epoch: 2012.01.20-09:14:28.0.
Definition: SgMJD.h:76
@ F_SOLVE_SPLFL
That was used in ECC.dat files: 2010.04.02-17.02.
Definition: SgMJD.h:74
@ F_Year
Date, more shortly: 10Apr02.
Definition: SgMJD.h:92
@ F_Time
SINEX, short version: 10:092.
Definition: SgMJD.h:95
@ F_TimeShort
Time, seconds are integer: 17:02:43.
Definition: SgMJD.h:97
@ F_INTERNAL
Digits, date and time: 20100402.71.
Definition: SgMJD.h:72
QString className() const
Definition: SgMJD.h:486
SgMJD toUtc() const
Definition: SgMJD.cpp:1230
QString toString(Format format=F_Verbose) const
Definition: SgMJD.cpp:1008
static const char * shortMonthNames_[]
Definition: SgMJD.h:362
static const char * longWeekdayNames_[]
Definition: SgMJD.h:365
bool saveIntermediateResults(QDataStream &) const
Definition: SgMJD.cpp:1315
void toYMDHMS_tr(int &nYear, int &nMonth, int &nDay, int &nHour, int &nMin, double &dSec) const
Definition: SgMJD.cpp:1306
static const char * shortWeekdayNames_[]
Definition: SgMJD.h:364
double time_
integer part of the epoch;
Definition: SgMJD.h:355
bool loadIntermediateResults(QDataStream &)
Definition: SgMJD.cpp:1330
static int calcDayNumber(int year, int month, int day)
Definition: SgMJD.cpp:52
void normalize()
part of the day, in days.
Definition: SgMJD.cpp:135
double gmst() const
Definition: SgMJD.cpp:1264
int calcDayOfYear() const
Definition: SgMJD.cpp:238
static SgMJD currentMJD()
Definition: SgMJD.cpp:119
int calcDay() const
Definition: SgMJD.cpp:227
SgMJD & operator-=(double days)
Definition: SgMJD.cpp:190
static double calcPartOfDay(int hour, int min, double sec)
Definition: SgMJD.cpp:42
int calcDayOfWeek() const
Definition: SgMJD.cpp:246
void setUpEpoch(int year, int month, int day, int hour, int min, double sec)
Definition: SgMJD.cpp:255
SgMJD()
Definition: SgMJD.h:384
static void MJD_reverse(int date, double time, int &nYear, int &nMonth, int &nDay, int &nHour, int &nMin, double &dSec)
Definition: SgMJD.cpp:75
static const char * longMonthNames_[]
Definition: SgMJD.h:363
SgMJD & operator+=(double days)
Definition: SgMJD.cpp:175
SgMJD toLocal() const
Definition: SgMJD.cpp:1247
QDateTime toQDateTime() const
Definition: SgMJD.cpp:152
QString dayOfWeek2Str() const
Definition: SgMJD.cpp:1196
int calcMonth() const
Definition: SgMJD.cpp:216
int calcYear() const
Definition: SgMJD.cpp:205