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