Loading...
Searching...
No Matches
julian-date.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2016 INESC TEC
4 * Copyright (c) 2021 CNES
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Code from https://gitlab.inesctec.pt/pmms/ns3-satellite
20 *
21 * Author: Pedro Silva <pmms@inesctec.pt>
22 * Author: Bastien Tauran <bastien.tauran@viveris.fr>
23 */
24
25#include "julian-date.h"
26
27#include "iers-data.h"
28#include "satellite-sgp4ext.h"
29#include "satellite-sgp4unit.h"
30
31#include "ns3/assert.h"
32#include "ns3/nstime.h"
33
34#include <algorithm>
35#include <cmath>
36#include <cstdio>
37#include <iomanip>
38#include <ostream>
39#include <sstream>
40#include <stdint.h>
41#include <string>
42#include <utility>
43#include <vector>
44
45namespace ns3
46{
47
48const uint32_t JulianDate::PosixYear = 1970;
49const uint32_t JulianDate::MinYear = 1992;
50const uint32_t JulianDate::MaxYear = 2099;
51const double JulianDate::PosixEpoch = 2440587.5;
52const uint32_t JulianDate::J2000Epoch = 2451545;
53const uint32_t JulianDate::Posix1992 = 8035;
54const uint32_t JulianDate::HourToMs = 3600000;
55const uint32_t JulianDate::DayToMs = HourToMs * 24;
56const Time JulianDate::TtToTai = MilliSeconds(32184);
57const Time JulianDate::TaiToGps = MilliSeconds(19000);
58
59std::ostream&
60operator<<(std::ostream& os, DateTime::TimeSystem ts)
61{
62 switch (ts)
63 {
64 case DateTime::UTC:
65 os << "UTC";
66 break;
67 case DateTime::TAI:
68 os << "TAI";
69 break;
70 case DateTime::TT:
71 os << "TT";
72 break;
73 case DateTime::UT1:
74 os << "UT1";
75 break;
76 case DateTime::GPST:
77 os << "GPS";
78 break;
79 case DateTime::POSIX:
80 os << "UTC";
81 break; // POSIX is printed as UTC
82 default:
83 break;
84 }
85
86 return os;
87}
88
90{
91 // the date since complete IERS data is available
92 m_days = static_cast<uint32_t>((MinYear - PosixYear) * 365.25);
93 m_ms_day = 0;
95}
96
98{
99 SetDate(jd);
100}
101
102JulianDate::JulianDate(uint32_t days, uint32_t ms_day)
103{
104 SetDate(days, ms_day);
105}
106
107JulianDate::JulianDate(const std::string& date, TimeSystem ts)
108{
109 SetDate(date, ts);
110}
111
112double
114{
115 double base = m_days + m_ms_day / static_cast<double>(DayToMs);
116
117 if (ts != DateTime::POSIX)
118 {
119 return base += PosixEpoch;
120 }
121
122 // transform base into Julian date, and add offset (if any)
123 return base + OffsetFromUtc(m_days, ts).GetDays();
124}
125
128{
129 return GregorianDate();
130}
131
134{
135 return (*this + OffsetFromUtc(m_days, ts)).GregorianDate();
136}
137
138std::string
140{
141 std::ostringstream oss;
142 DateTime dt = (*this + OffsetFromUtc()).GregorianDate();
143
144 oss << std::setfill('0');
145 oss << std::setw(4) << dt.year << "-" << std::setw(2) << dt.month << "-" << std::setw(2)
146 << dt.day << " " << std::setw(2) << dt.hours << ":" << std::setw(2) << dt.minutes << ":"
147 << std::setw(2) << dt.seconds << "." << std::setw(3) << dt.millisecs << " " << m_time_scale;
148
149 return oss.str();
150}
151
152std::string
154{
155 JulianDate jd = *this;
156
157 jd.m_time_scale = ts;
158
159 return jd.ToString();
160}
161
162std::pair<double, double>
164{
165 const std::vector<IersData::EopParameters>& v = IersData::EopValues;
166 uint32_t pos = m_days - Posix1992; // full days since 01 Jan 1992
167
168 // if there is data available
169 if (pos < v.size())
170 {
171 return std::make_pair(v[pos].xp, v[pos].yp);
172 }
173
174 return std::make_pair(0, 0);
175}
176
177double
179{
180 const std::vector<IersData::EopParameters>& v = IersData::EopValues;
181 uint32_t pos = m_days - Posix1992; // full days since 1 Jan 1992
182 double lod = (pos < v.size() ? v[pos].lod : 0); // LOD in milliseconds
183
184 // use IERS angular velocity formula with extra precision if LOD is available
185 // LOD is in milliseconds, and the result is in radians/s
186 return 7.2921151467064e-5 * (1.0 - lod / DayToMs);
187}
188
189// from http://aa.usno.navy.mil/faq/docs/GAST.php
190double
192{
194 return gstime((*this + Dut1(m_days)).GetDouble());
195
197
198 // JulianDate jdut1 = *this + Dut1 (m_days);
199
200 // from http://aa.usno.navy.mil/faq/docs/GAST.php
201 //
202 // 6.697374558 + 0.06570982441908*D0 + 1.00273790935*H + 0.000026*T²
203 //
204 // JD0 = jdut1.m_days + PosixEpoch
205 // D0 = jdut1.m_days + PosixEpoch - J2000Epoch
206 // H = jdut1.m_ms_day/HourToMs
207 // D = D0 + H/24
208 // T = D/36525.0 = (D0 + jdut1.m_ms_day/DayToMs)/36525.0
209
210 // double d0 = jdut1.m_days + PosixEpoch - J2000Epoch;
211 // double h = jdut1.m_ms_day/static_cast<double> (HourToMs);
212 // double t = (d0 + jdut1.m_ms_day/static_cast<double> (DayToMs))/36525.0;
213 // double gmst = 6.697374558 + 0.06570982441908*d0 + 1.00273790935*h +
214 // 0.000026*t*t;
215
216 // gmst = fmod(gmst * M_PI/12, 2*M_PI);
217
218 // return (gmst < 0 ? gmst+2*M_PI : gmst);
219}
220
221void
223{
224 // POSIX/Unix epoch is used internally
225 jd -= PosixEpoch;
226
227 m_days = static_cast<uint32_t>(jd);
228 m_ms_day = static_cast<uint32_t>((jd - m_days) * DayToMs);
230}
231
232void
233JulianDate::SetDate(uint32_t days, uint32_t ms_day)
234{
235 // POSIX/Unix epoch is used internally
236 m_days = days;
237 m_ms_day = ms_day;
239}
240
241void
242JulianDate::SetDate(const std::string& date, TimeSystem ts)
243{
244 double seconds;
245 DateTime dt;
246
247 NS_ASSERT_MSG(ts != DateTime::POSIX, "POSIX/Unix time scale is not valid for dates.");
248
249 // YYYY-MM-DD HH:MM:SS(.MMM)
250 std::sscanf(date.c_str(),
251 "%04u%*c%02u%*c%02u %02u%*c%02u%*c%lf",
252 &dt.year,
253 &dt.month,
254 &dt.day,
255 &dt.hours,
256 &dt.minutes,
257 &seconds);
258
259 NS_ASSERT_MSG(dt.year >= MinYear, "Complete EOP data is not available before that date!");
260
261 NS_ASSERT_MSG(dt.year <= MaxYear, "Dates beyond 2099 are not supported!");
262
263 dt.seconds = static_cast<uint32_t>(seconds);
264 dt.millisecs = static_cast<uint32_t>((seconds - dt.seconds) * 1000 + 0.5);
265
266 // based on formula from http://aa.usno.navy.mil/faq/docs/JD_Formula.php
267 m_days = 367 * dt.year - 7 * (dt.year + (dt.month + 9) / 12) / 4 + 275 * dt.month / 9 + dt.day -
268 static_cast<uint32_t>(PosixEpoch - 1721013.5);
269 m_ms_day = (dt.hours * 3600 + dt.minutes * 60 + dt.seconds) * 1000 + dt.millisecs;
270 m_time_scale = ts;
271
272 *this += OffsetToUtc();
273}
274
276JulianDate::operator+(const Time& t) const
277{
278 JulianDate jd;
279
280 // if time is negative, call operator- with a positive time
281 if (t.IsStrictlyNegative())
282 {
283 return *this - MilliSeconds(-t.GetMilliSeconds());
284 }
285
286 jd.m_days = static_cast<uint32_t>(t.GetDays());
287 jd.m_ms_day = static_cast<uint32_t>(t.GetMilliSeconds() % DayToMs);
288
289 jd.m_ms_day += m_ms_day;
290 jd.m_days += m_days + jd.m_ms_day / DayToMs;
291 jd.m_ms_day %= DayToMs;
293
294 return jd;
295}
296
297void
299{
300 *this = *this + t;
301}
302
304JulianDate::operator-(const Time& t) const
305{
306 JulianDate jd;
307
308 // if time is negative, call operator+ with a positive time
309 if (t.IsStrictlyNegative())
310 {
311 return *this + MilliSeconds(-t.GetMilliSeconds());
312 }
313
314 jd.m_days = static_cast<uint32_t>(t.GetDays());
315 jd.m_ms_day = static_cast<uint32_t>(t.GetMilliSeconds() % DayToMs);
316
317 if (jd.m_ms_day > m_ms_day)
318 {
319 jd.m_ms_day = DayToMs - (jd.m_ms_day - m_ms_day);
320 jd.m_days += 1;
321 }
322 else
323 {
324 jd.m_ms_day = m_ms_day - jd.m_ms_day;
325 }
326
327 jd.m_days = m_days - jd.m_days;
329
330 return jd;
331}
332
333void
335{
336 *this = *this - t;
337}
338
339Time
341{
342 Time t1 = ns3::Days(m_days) + ns3::MilliSeconds(m_ms_day);
343 Time t2 = ns3::Days(jd.m_days) + ns3::MilliSeconds(jd.m_ms_day);
344
345 return t1 - t2;
346}
347
348bool
349JulianDate::operator<(const JulianDate& jd) const
350{
351 if (m_days != jd.m_days)
352 {
353 return m_days < jd.m_days;
354 }
355
356 return m_ms_day < jd.m_ms_day;
357}
358
359bool
360JulianDate::operator<=(const JulianDate& jd) const
361{
362 if (m_days != jd.m_days)
363 {
364 return m_days < jd.m_days;
365 }
366
367 return m_ms_day <= jd.m_ms_day;
368}
369
370bool
372{
373 if (m_days != jd.m_days)
374 {
375 return m_days > jd.m_days;
376 }
377
378 return m_ms_day > jd.m_ms_day;
379}
380
381bool
383{
384 if (m_days != jd.m_days)
385 {
386 return m_days > jd.m_days;
387 }
388
389 return m_ms_day >= jd.m_ms_day;
390}
391
392bool
394{
395 if (m_days != jd.m_days)
396 {
397 return false;
398 }
399
400 return m_ms_day == jd.m_ms_day;
401}
402
403bool
405{
406 if (m_days != jd.m_days)
407 {
408 return true;
409 }
410
411 return m_ms_day != jd.m_ms_day;
412}
413
414std::ostream&
415operator<<(std::ostream& os, const JulianDate& jd)
416{
417 os << jd.ToString();
418
419 return os;
420}
421
422//
423//
424//
425
426bool
428{
429 // if the year is divisible by 4, it is a leap year
430 // [this works because we only consider dates between 1992 and 2099]
431 return ((year & 0x03) == 0);
432}
433
434Time
435JulianDate::TaiMinusUtc(uint32_t daysInPosix)
436{
437 const std::vector<uint32_t>& v = IersData::LeapSeconds;
438 std::vector<uint32_t>::const_iterator it;
439
440 it = std::lower_bound(v.begin(), v.end(), daysInPosix);
441
442 return MilliSeconds(((it - v.begin()) + IersData::BaseLeapSeconds) * 1000);
443}
444
445Time
446JulianDate::Dut1(uint32_t daysInPosix)
447{
448 const std::vector<IersData::EopParameters>& v = IersData::EopValues;
449 uint32_t pos = daysInPosix - Posix1992; // full days since 01 Jan 1992
450
451 return MilliSeconds(pos < v.size() ? v[pos].dut1 * 1000 : 0);
452}
453
456{
458}
459
461JulianDate::GregorianDate(uint32_t days, uint32_t ms_day)
462{
463 uint32_t month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
464 uint32_t d = days - Posix1992, days_of_year, leap_years;
465 Time t = MilliSeconds(ms_day);
466 DateTime dt;
467
468 // this formula only works if we consider an year that is multiple of 4
469 dt.year = static_cast<uint32_t>(d / 365.25) + MinYear;
470
471 leap_years = (dt.year - (MinYear + 1)) / 4;
472 days_of_year = d - ((dt.year - MinYear) * 365 + leap_years);
473
474 // if it is a leap year, February has 29 days
475 if (IsLeapYear(dt.year))
476 {
477 month_days[1] += 1;
478 }
479
480 for (uint32_t i = 0; i < 12; ++i)
481 {
482 if (days_of_year <= month_days[i])
483 {
484 dt.month = i + 1;
485
486 break;
487 }
488
489 days_of_year -= month_days[i];
490 }
491
492 dt.day = days_of_year;
493
494 dt.hours = static_cast<uint32_t>(t.GetHours());
495 t -= Hours(dt.hours);
496
497 dt.minutes = static_cast<uint32_t>(t.GetMinutes());
498 t -= Minutes(dt.minutes);
499
500 dt.seconds = static_cast<uint32_t>(t.GetSeconds());
501 t -= Seconds(dt.seconds);
502
503 dt.millisecs = static_cast<uint32_t>(t.GetMilliSeconds());
504
505 return dt;
506}
507
508Time
513
514Time
515JulianDate::OffsetFromUtc(uint32_t daysInPosix, TimeSystem ts)
516{
517 // already in sync for UTC and POSIX
518 Time offset = MilliSeconds(0);
519
520 switch (ts)
521 {
522 case DateTime::UT1:
523 offset = Dut1(daysInPosix);
524 break;
525 case DateTime::TAI:
526 offset = TaiMinusUtc(daysInPosix);
527 break;
528 case DateTime::TT:
529 offset = TtToTai + TaiMinusUtc(daysInPosix);
530 break;
531 case DateTime::GPST:
532 offset = TaiMinusUtc(daysInPosix) - TaiToGps;
533 break;
534 default:
535 break;
536 }
537
538 return offset;
539}
540
541Time
546
547Time
548JulianDate::OffsetToUtc(uint32_t daysInPosix, uint32_t ms_day, TimeSystem ts)
549{
550 // already in sync
551 if (ts == DateTime::UTC || ts == DateTime::POSIX)
552 {
553 return MilliSeconds(0);
554 }
555
556 Time tai_utc = TaiMinusUtc(daysInPosix);
557 Time offset = (ts == DateTime::TT ? TtToTai : MilliSeconds(0));
558
559 // if it is not the same day in UTC, check the leap secs for the previous day
560 if (ms_day < (offset + tai_utc).GetMilliSeconds())
561 {
562 tai_utc = TaiMinusUtc(daysInPosix - 1);
563 }
564
565 switch (ts)
566 {
567 case DateTime::UT1:
568 offset = Dut1(daysInPosix);
569 break;
570 case DateTime::TAI:
571 offset = tai_utc;
572 break;
573 case DateTime::TT:
574 offset = TtToTai + tai_utc;
575 break;
576 case DateTime::GPST:
577 offset = tai_utc - TaiToGps;
578 break;
579 default:
580 break;
581 }
582
583 // return the offset as negative
584 return MilliSeconds(-offset.GetMilliSeconds());
585}
586
587} // namespace ns3
static const std::vector< uint32_t > LeapSeconds
Definition iers-data.h:53
static const std::vector< EopParameters > EopValues
Definition iers-data.h:50
static const uint32_t BaseLeapSeconds
Definition iers-data.h:51
Class to handle Julian days and provide respective Earth Orientation Parameters (EOP).
Definition julian-date.h:79
static bool IsLeapYear(uint32_t year)
Check if it is a leap year.
JulianDate(void)
Default constructor.
double GetGmst(void) const
Retrieve the Greenwich Mean Sidereal Time.
static const Time TaiToGps
offset from TAI to GPST
Definition julian-date.h:93
void SetDate(double jd)
Set the Julian days.
uint32_t m_days
full days since epoch.
double GetDouble(TimeSystem ts=DateTime::UTC) const
GetDouble Get the Julian days.
bool operator>(const JulianDate &jd) const
operator > (compare Julian dates).
bool operator==(const JulianDate &jd) const
operator == (compare Julian dates).
JulianDate operator-(const Time &t) const
operator - (negative time adjustment).
JulianDate operator+(const Time &t) const
operator + (positive time adjustment).
Time OffsetFromUtc(void) const
Returns the offset from UTC.
TimeSystem m_time_scale
external time system.
static const uint32_t PosixYear
POSIX/Unix epoch year.
Definition julian-date.h:84
static const uint32_t DayToMs
milliseconds in a day
Definition julian-date.h:91
static const uint32_t MinYear
Minimum year supported.
Definition julian-date.h:85
Time OffsetToUtc(void) const
Returns the offset to UTC.
static Time TaiMinusUtc(uint32_t daysInPosix)
The difference between TAI and UTC time systems.
static const Time TtToTai
offset from TT to TAI
Definition julian-date.h:92
static const double PosixEpoch
1 Jan 1970, 0h
Definition julian-date.h:87
uint32_t m_ms_day
milliseconds of the day.
static const uint32_t HourToMs
milliseconds in an hour
Definition julian-date.h:90
std::string ToString(void) const
Get the string representation of the Gregorian calendar date.
DateTime GetDateTime(void) const
Get the Gregorian calendar date in current time system.
bool operator<(const JulianDate &jd) const
operator < (compare Julian dates).
double GetOmegaEarth(void) const
Retrieve Earth's angular velocity.
bool operator!=(const JulianDate &jd) const
operator != (compare Julian dates).
static Time Dut1(uint32_t daysInPosix)
Retrieve the DUT1 (UT1 - UTC) value for a given day.
DateTime::TimeSystem TimeSystem
equivalent to C++11 using TimeSystem = DateTime::TimeSystem.
Definition julian-date.h:81
std::pair< double, double > GetPolarMotion(void) const
Retrieve the polar motion cofficients measured/predicted.
DateTime GregorianDate(void) const
Convert into Gregorian calendar.
bool operator<=(const JulianDate &jd) const
operator <= (compare Julian dates).
bool operator>=(const JulianDate &jd) const
operator >= (compare Julian dates).
void operator+=(const Time &t)
operator += (positive time adjustment).
static const uint32_t J2000Epoch
1 Jan 2000, 12h
Definition julian-date.h:88
void operator-=(const Time &t)
operator -= (negative time adjustment).
static const uint32_t Posix1992
1 Jan 1992 (POSIX days)
Definition julian-date.h:89
static const uint32_t MaxYear
Maximum year supported.
Definition julian-date.h:86
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
std::ostream & operator<<(std::ostream &os, const GeoCoordinate &coordinate)
double gstime(double jdut1)
The DateTime struct.
Definition julian-date.h:46
uint32_t year
Definition julian-date.h:57
uint32_t day
Definition julian-date.h:57
uint32_t minutes
Definition julian-date.h:58
@ POSIX
Unix/POSIX Time.
Definition julian-date.h:54
@ UTC
Coordinated Universal Time [French: Temps Universel Coordonné].
Definition julian-date.h:49
@ TAI
International Atomic Time [French: Temps Atomique International].
Definition julian-date.h:51
@ TT
Terrestrial Time.
Definition julian-date.h:52
@ UT1
Universal Time.
Definition julian-date.h:50
@ GPST
Global Positioning System (GPS) Time.
Definition julian-date.h:53
uint32_t seconds
Definition julian-date.h:58
uint32_t month
Definition julian-date.h:57
uint32_t hours
Definition julian-date.h:58
uint32_t millisecs
Definition julian-date.h:58