Pioneer
DateTime.h
Go to the documentation of this file.
1 #ifndef DATETIME_H
2 #define DATETIME_H
3 
4 #include <string>
5 
6 namespace Time {
7 
8  // We separate lengths of time (TimeDelta) from points in time (DateTime),
9  // because they have different operations defined on them
10  //
11  // The TimeDelta constructor takes a TimeUnit parameter, so you specify
12  // a length of time with, e.g., Time::TimeDelta(42, Time::Day)
13  //
14  // TimeUnit is an enum (rather than a set of const TimeDelta values) because
15  // that ensures the compiler will treat the values as compile time constants
16  // instead of objects that must be defined in a translation unit and initialised.
17  //
18  // The base units are (currently) microseconds, which is chosen
19  // because it's plenty high enough resolution for most uses, and it's
20  // easily understandable, and it gives good range when stored in
21  // signed 64-bit integers (approx. +/- 292277 years)
22  //
23  // The base units can be trivially changed by modifying the TimeUnit enum.
24  //
25  // DateTime is mostly about dealing with the Gregorian calendar.
26  //
27  // These types have a fairly unsophisticated understanding of the calendar
28  // and the passage of time. For example, leap seconds are not supported at all.
29  // But... I'm pretty sure we don't need leap seconds for Pioneer.
30 
31  enum TimeUnit : int64_t {
32  Microsecond = 1ll,
34  Second = 1000ll * Millisecond,
35  Minute = 60ll * Second,
36  Hour = 60ll * Minute,
37  Day = 24ll * Hour,
38  Week = 7ll * Day
39  };
40 
41  class TimeDelta;
42  class DateTime;
43 
44  class TimeDelta {
45  public:
47  m_delta(0) {}
48  explicit TimeDelta(int64_t t, TimeUnit unit = Second) :
49  m_delta(t * unit) {}
50 
51  int64_t GetTotalWeeks() const { return (m_delta / Week); }
52  int64_t GetTotalDays() const { return (m_delta / Day); }
53  int64_t GetTotalHours() const { return (m_delta / Hour); }
54  int64_t GetTotalMinutes() const { return (m_delta / Minute); }
55  int64_t GetTotalSeconds() const { return (m_delta / Second); }
56  int64_t GetTotalMilliseconds() const { return (m_delta / Millisecond); }
57  int64_t GetTotalMicroseconds() const { return (m_delta / Microsecond); }
58 
60  {
61  m_delta += x.m_delta;
62  return *this;
63  }
65  {
66  m_delta -= x.m_delta;
67  return *this;
68  }
69 
70  friend TimeDelta operator+(const TimeDelta &a, const TimeDelta &b) { return TimeDelta(a.m_delta + b.m_delta, TimeUnit(1)); }
71  friend TimeDelta operator-(const TimeDelta &a, const TimeDelta &b) { return TimeDelta(a.m_delta - b.m_delta, TimeUnit(1)); }
72  friend TimeDelta operator*(int64_t x, const TimeDelta &t) { return TimeDelta(x * t.m_delta, TimeUnit(1)); }
73  friend TimeDelta operator/(const TimeDelta &t, int64_t x) { return TimeDelta(t.m_delta / x, TimeUnit(1)); }
74  friend int64_t operator/(const TimeDelta &a, const TimeDelta &b) { return (a.m_delta / b.m_delta); }
75 
76  friend DateTime operator+(const DateTime &a, const TimeDelta &b);
77  friend DateTime operator-(const DateTime &a, const TimeDelta &b);
78 
79  private:
80  friend class DateTime;
81  int64_t m_delta;
82  };
83 
84  class DateTime {
85  public:
87  m_timestamp(-int64_t(24 * 60 * 60) * int64_t(400 * 365 + 97) * int64_t(Second)) {}
88  // month = 1 to 12
89  // day = 1 to N where N is the number of days in the specified month and year
90  DateTime(int year, int month, int day, int hour = 0, int minute = 0, int second = 0, int microsecond = 0);
91  DateTime(double gameTime);
92 
93  void GetDateParts(int *year, int *month, int *day) const;
94  void GetTimeParts(int *hour, int *minute, int *second, int *microsecond = nullptr) const;
95 
96  double ToGameTime() const;
97  std::string ToDateString() const;
98  std::string ToTimeString() const;
99  std::string ToDateTimeString() const { return ToStringISO8601(); }
100  std::string ToStringISO8601() const;
101 
102  friend TimeDelta operator-(const DateTime &a, const DateTime &b)
103  {
104  return TimeDelta(a.m_timestamp - b.m_timestamp, TimeUnit(1));
105  }
106  friend DateTime operator+(const DateTime &a, const TimeDelta &b)
107  {
108  return DateTime(a.m_timestamp + b.m_delta);
109  }
110  friend DateTime operator-(const DateTime &a, const TimeDelta &b)
111  {
112  return DateTime(a.m_timestamp - b.m_delta);
113  }
114  friend DateTime operator+(const TimeDelta &a, const DateTime &b) { return (b + a); }
115 
117  {
118  m_timestamp += x.m_delta;
119  return *this;
120  }
122  {
123  m_timestamp -= x.m_delta;
124  return *this;
125  }
126 
127  friend bool operator<(const DateTime &a, const DateTime &b) { return (a.m_timestamp < b.m_timestamp); }
128  friend bool operator<=(const DateTime &a, const DateTime &b) { return (a.m_timestamp <= b.m_timestamp); }
129  friend bool operator==(const DateTime &a, const DateTime &b) { return (a.m_timestamp == b.m_timestamp); }
130  friend bool operator!=(const DateTime &a, const DateTime &b) { return (a.m_timestamp != b.m_timestamp); }
131  friend bool operator>(const DateTime &a, const DateTime &b) { return (a.m_timestamp > b.m_timestamp); }
132  friend bool operator>=(const DateTime &a, const DateTime &b) { return (a.m_timestamp >= b.m_timestamp); }
133 
134  int64_t GetTimestamp() const { return m_timestamp; }
135 
136  private:
137  explicit DateTime(int64_t tstamp) :
138  m_timestamp(tstamp) {}
139 
140  // The timestamp is the number of microseconds since the epoch (2001-01-01T00:00:00Z)
141  //
142  // This epoch (the start of the year 2001) is chosen because it makes counting
143  // leap years easier (see DateTime constructor from date components)
144  //
145  // However, these are *not* SI microseconds, they are mean solar microseconds.
146  // SI microseconds are defined in terms of the behaviour of the caesium atom.
147  // Mean solar microseconds are defined in terms of the rotation of the Earth.
148  // This means that there are always precisely 86400 * 10^6 mean solar microseconds in each day.
149  // Since every day contains precisely the same number of mean solar microseconds, it is practical
150  // to compute the number of mean solar microseconds between any two dates (specified
151  // according to the Gregorian calendar) or to compute a date from a timestamp.
152  //
153  // If we used SI microseconds, we would need to know all past and future leap seconds to be able to correctly
154  // convert between the timestamp value and a year-month-day-hour-minute-second-microsecond tuple.
155  // Apart from making the calculations a pain in the ass, that is actually impossible for dates in the future,
156  // because leap seconds are not predictable (they're introduced as necessary based on astronomical observations)
157  //
158  // (Incidentally, this is the way all integer timestamps work, at least all the ones I've ever seen)
159  int64_t m_timestamp; // (units: microseconds; 0 means 2001-01-01T00:00:00Z)
160  };
161 
162 } // namespace Time
163 
164 #endif
Definition: DateTime.h:84
friend bool operator==(const DateTime &a, const DateTime &b)
Definition: DateTime.h:129
std::string ToTimeString() const
Definition: DateTime.cpp:194
friend DateTime operator+(const TimeDelta &a, const DateTime &b)
Definition: DateTime.h:114
friend bool operator!=(const DateTime &a, const DateTime &b)
Definition: DateTime.h:130
friend DateTime operator+(const DateTime &a, const TimeDelta &b)
Definition: DateTime.h:106
friend DateTime operator-(const DateTime &a, const TimeDelta &b)
Definition: DateTime.h:110
std::string ToStringISO8601() const
Definition: DateTime.cpp:203
DateTime & operator+=(const TimeDelta &x)
Definition: DateTime.h:116
friend bool operator>=(const DateTime &a, const DateTime &b)
Definition: DateTime.h:132
int64_t GetTimestamp() const
Definition: DateTime.h:134
DateTime()
Definition: DateTime.h:86
std::string ToDateTimeString() const
Definition: DateTime.h:99
DateTime & operator-=(const TimeDelta &x)
Definition: DateTime.h:121
void GetDateParts(int *year, int *month, int *day) const
Definition: DateTime.cpp:96
friend bool operator<(const DateTime &a, const DateTime &b)
Definition: DateTime.h:127
void GetTimeParts(int *hour, int *minute, int *second, int *microsecond=nullptr) const
Definition: DateTime.cpp:149
double ToGameTime() const
Definition: DateTime.cpp:174
friend bool operator<=(const DateTime &a, const DateTime &b)
Definition: DateTime.h:128
friend TimeDelta operator-(const DateTime &a, const DateTime &b)
Definition: DateTime.h:102
friend bool operator>(const DateTime &a, const DateTime &b)
Definition: DateTime.h:131
std::string ToDateString() const
Definition: DateTime.cpp:185
Definition: DateTime.h:44
TimeDelta & operator-=(const TimeDelta &x)
Definition: DateTime.h:64
friend TimeDelta operator-(const TimeDelta &a, const TimeDelta &b)
Definition: DateTime.h:71
int64_t GetTotalDays() const
Definition: DateTime.h:52
int64_t GetTotalWeeks() const
Definition: DateTime.h:51
int64_t GetTotalHours() const
Definition: DateTime.h:53
int64_t GetTotalMicroseconds() const
Definition: DateTime.h:57
TimeDelta & operator+=(const TimeDelta &x)
Definition: DateTime.h:59
friend DateTime operator+(const DateTime &a, const TimeDelta &b)
friend DateTime operator-(const DateTime &a, const TimeDelta &b)
friend TimeDelta operator+(const TimeDelta &a, const TimeDelta &b)
Definition: DateTime.h:70
friend TimeDelta operator*(int64_t x, const TimeDelta &t)
Definition: DateTime.h:72
friend int64_t operator/(const TimeDelta &a, const TimeDelta &b)
Definition: DateTime.h:74
TimeDelta(int64_t t, TimeUnit unit=Second)
Definition: DateTime.h:48
friend TimeDelta operator/(const TimeDelta &t, int64_t x)
Definition: DateTime.h:73
int64_t GetTotalSeconds() const
Definition: DateTime.h:55
TimeDelta()
Definition: DateTime.h:46
int64_t GetTotalMinutes() const
Definition: DateTime.h:54
int64_t GetTotalMilliseconds() const
Definition: DateTime.h:56
Definition: DateTime.h:6
TimeUnit
Definition: DateTime.h:31
@ Second
Definition: DateTime.h:34
@ Millisecond
Definition: DateTime.h:33
@ Minute
Definition: DateTime.h:35
@ Microsecond
Definition: DateTime.h:32
@ Hour
Definition: DateTime.h:36
@ Week
Definition: DateTime.h:38
@ Day
Definition: DateTime.h:37