36 static constexpr const char * good_format =
"%ntYyCGgmUWVjdwuHIMSDFRT" ;
37 static constexpr unsigned int million = 1000000U ;
39 template <
typename Tp> TimeInterval interval( Tp start , Tp end )
41 using namespace std::chrono ;
44 auto d = end - start ;
46 auto s = (duration_cast<seconds>(d)).count() ; G_ASSERT( s >= 0 ) ;
47 typename std::make_unsigned<
decltype(s)>::type su = s ;
48 if(
sizeof(su) >
sizeof(TimeInterval::s_type) &&
49 su > std::numeric_limits<TimeInterval::s_type>::max() )
52 auto us = (duration_cast<microseconds>(d) % seconds(1)).count() ; G_ASSERT( us >= 0 ) ;
53 typename std::make_unsigned<
decltype(us)>::type usu = us ;
54 G_ASSERT( us <= std::numeric_limits<TimeInterval::us_type>::max() ) ;
56 return TimeInterval(
static_cast<TimeInterval::s_type
>(su) ,
static_cast<TimeInterval::us_type
>(usu) ) ;
58 bool operator<(
const std::tm & a ,
const std::tm & b )
noexcept
60 if( a.tm_year < b.tm_year )
return true ;
61 if( a.tm_year > b.tm_year )
return false ;
62 if( a.tm_mon < b.tm_mon )
return true ;
63 if( a.tm_mon > b.tm_mon )
return false ;
64 if( a.tm_mday < b.tm_mday )
return true ;
65 if( a.tm_mday > b.tm_mday )
return false ;
66 if( a.tm_hour < b.tm_hour )
return true ;
67 if( a.tm_hour > b.tm_hour )
return false ;
68 if( a.tm_min < b.tm_min )
return true ;
69 if( a.tm_min > b.tm_min )
return false ;
70 return a.tm_sec < b.tm_sec ;
72 bool sameMinute(
const std::tm & a ,
const std::tm & b )
noexcept
75 a.tm_year == b.tm_year &&
76 a.tm_mon == b.tm_mon &&
77 a.tm_mday == b.tm_mday &&
78 a.tm_hour == b.tm_hour &&
79 a.tm_min == b.tm_min ;
81 bool sameSecond(
const std::tm & a ,
const std::tm & b )
noexcept
83 return sameMinute( a , b ) && a.tm_sec == b.tm_sec ;
85 void localtime_( std::tm & tm_out , std::time_t t_in )
87 if( localtime_r( &t_in , &tm_out ) ==
nullptr )
88 throw DateTime::Error() ;
89 tm_out.tm_isdst = -1 ;
91 void gmtime_( std::tm & tm_out , std::time_t t_in )
93 if( gmtime_r( &t_in , &tm_out ) ==
nullptr )
94 throw DateTime::Error() ;
95 tm_out.tm_isdst = -1 ;
97 std::time_t mktime_( std::tm & tm )
100 std::time_t t = std::mktime( &tm ) ;
101 if( t == std::time_t(-1) )
102 throw DateTime::Error() ;
105 std::time_t mktimelocal(
const std::tm & local_tm_in )
107 struct std::tm tm = local_tm_in ;
108 return mktime_( tm ) ;
110 std::time_t mktimeutc(
const std::tm & utc_tm_in , std::time_t begin , std::time_t end )
114 std::time_t count = end - begin ;
115 std::time_t t = begin ;
119 std::time_t step = count / 2 ;
157 m_tm.tm_year = y - 1900 ;
158 m_tm.tm_mon = mon - 1 ;
171 return DateTimeImp::mktimelocal( m_tm ) ;
177 std::time_t t0 = DateTimeImp::mktimelocal( m_tm ) ;
183 DateTimeImp::gmtime_( tm , t0+memo.
value() ) ;
184 if( DateTimeImp::sameSecond(tm,m_tm) )
185 return t0 + memo.
value() ;
188 std::time_t dt = 25 * 3600 + 10 ;
189 std::time_t begin = std::max(dt,t0) - dt ;
190 std::time_t end = t0 + dt ;
191 std::time_t t = DateTimeImp::mktimeutc( m_tm , begin , end ) ;
192 if( t == begin || t == end )
193 throw DateTime::Error(
"timezone error" ) ;
209 DateTimeImp::localtime_( bdt.
m_tm , t.
s() ) ;
216 DateTimeImp::gmtime_( bdt.
m_tm , t.
s() ) ;
222 return { year , month , day , 12 , 0 , 0 } ;
228 return { year , month , day , 0 , 0 , 0 } ;
234 for(
const char * p = std::strchr(fmt,
'%') ; p && p[1] ; p = std::strchr(p+1,
'%') )
236 if( std::strchr(DateTimeImp::good_format,p[1]) == nullptr )
237 throw DateTime::Error(
"bad format string" ) ;
240 std::tm tm_copy = m_tm ;
241 DateTimeImp::mktime_( tm_copy ) ;
243 return std::strftime( out , out_size , fmt , &tm_copy ) > 0U ;
248 if( !
format( out.data() , out.size() , fmt ) )
249 throw DateTime::Error() ;
255 return str(
"%F %T" ) ;
261 std::size_t n = std::strlen( fmt ) + 1U ;
262 for(
const char * p = std::strchr(fmt,
'%') ; p && p[1] ; p = std::strchr(p+1,
'%') )
265 std::vector<char> buffer( n ) ;
267 buffer.at(buffer.size()-1U) =
'\0' ;
268 return { buffer.data() } ;
273 return m_tm.tm_hour ;
288 return m_tm.tm_year + 1900 ;
293 return m_tm.tm_mon + 1 ;
298 return m_tm.tm_mday ;
303 std::tm tm_copy = m_tm ;
304 DateTimeImp::mktime_( tm_copy ) ;
305 return tm_copy.tm_wday ;
311 return DateTimeImp::sameMinute( m_tm , other.m_tm ) ;
324 m_tp = std::chrono::system_clock::from_time_t(t) ;
325 m_tp += std::chrono::microseconds( us ) ;
330 return SystemTime( std::chrono::system_clock::now() ) ;
340 return DateTimeImp::interval( m_tp , end.m_tp ) ;
346 m_tp += std::chrono::microseconds( us ) ;
353 return s() == t.s() ;
369 using namespace std::chrono ;
370 return static_cast<unsigned int>((duration_cast<milliseconds>(m_tp.time_since_epoch()) % seconds(1)).count()) ;
376 using namespace std::chrono ;
377 return static_cast<unsigned int>((duration_cast<microseconds>(m_tp.time_since_epoch()) % seconds(1)).count()) ;
382 using namespace std::chrono ;
383 G_ASSERT( duration_cast<seconds>(m_tp.time_since_epoch()).count() == system_clock::to_time_t(m_tp) ) ;
384 return system_clock::to_time_t( m_tp ) ;
390 duration_type zero{0} ;
391 G_ASSERT(
SystemTime(time_point_type(zero)).s() == 0 ) ;
399 return m_tp == time_point_type( duration_type(0) ) ;
405 return m_tp < other.m_tp ;
411 return m_tp <= other.m_tp ;
417 return m_tp == other.m_tp ;
422 return !( *
this == other ) ;
428 return m_tp > other.m_tp ;
435 return m_tp >= other.m_tp ;
450 using namespace std::chrono ;
451 m_tp += seconds(i.
s()) ;
452 m_tp += microseconds(i.
us()) ;
457 int w =
static_cast<int>( stream.width() ) ;
458 char c = stream.fill() ;
461 << std::setw(6) << std::setfill(
'0')
463 << std::setw(w) << std::setfill(c) ;
466std::ostream & G::operator<<( std::ostream & stream ,
const SystemTime & t )
474G::TimerTime::TimerTime( time_point_type tp ) :
481 time_point_type tp = std::chrono::steady_clock::now() ;
482 if( tp == time_point_type() ) tp += duration_type(1) ;
488 return TimerTime( time_point_type( duration_type(0) ) ) ;
493 return m_tp == time_point_type( duration_type(0) ) ;
499 using namespace std::chrono ;
500 return TimerTime( time_point_type( seconds(s) + microseconds(us) ) ) ;
504unsigned long G::TimerTime::s()
const
506 using namespace std::chrono ;
507 return static_cast<unsigned long>( duration_cast<seconds>(m_tp.time_since_epoch()).count() ) ;
510unsigned long G::TimerTime::us()
const
512 using namespace std::chrono ;
513 return static_cast<unsigned long>( (duration_cast<microseconds>(m_tp.time_since_epoch()) % seconds(1)).count() ) ;
517std::string G::TimerTime::str()
const
519 std::ostringstream ss ;
520 ss << s() <<
'.' << std::setw(6) << std::setfill(
'0') << us() ;
534 using namespace std::chrono ;
535 m_tp += seconds(i.
s()) ;
536 m_tp += microseconds(i.
us()) ;
548 return DateTimeImp::interval( m_tp , end.m_tp ) ;
554 using namespace std::chrono ;
556 duration_cast<seconds>(m_tp.time_since_epoch()) ==
557 duration_cast<seconds>(t.m_tp.time_since_epoch()) ;
563 return m_tp <= other.m_tp ;
568 return m_tp == other.m_tp ;
574 return m_tp != other.m_tp ;
581 return m_tp > other.m_tp ;
588 return m_tp >= other.m_tp ;
623void G::TimeInterval::normalise()
625 using namespace G::DateTimeImp ;
626 if( m_us >= million )
630 if( m_us >= million )
632 increase( m_s , m_us / million ) ;
633 m_us = m_us % million ;
640 using namespace G::DateTimeImp ;
641 return TimeInterval( std::numeric_limits<s_type>::max() , million-1U ) ;
661 return m_s == other.m_s && m_us == other.m_us ;
667 return !( *
this == other ) ;
673 return m_s < other.m_s || ( m_s == other.m_s && m_us < other.m_us ) ;
679 return *
this == other || *
this < other ;
685 return m_s > other.m_s || ( m_s == other.m_s && m_us > other.m_us ) ;
691 return *
this == other || *
this > other ;
713void G::TimeInterval::increase(
unsigned int & s ,
unsigned int ds )
717 const bool overflow = s < old ;
719 throw DateTime::Error(
"overflow" ) ;
724 using namespace G::DateTimeImp ;
726 if( m_us >= million )
731 increase( m_s , i.m_s ) ;
734void G::TimeInterval::decrease(
unsigned int & s ,
unsigned int ds )
737 throw DateTime::Error(
"underflow" ) ;
743 using namespace G::DateTimeImp ;
750 decrease( m_s , i.m_s ) ;
755 int w =
static_cast<int>( stream.width() ) ;
756 char c = stream.fill() ;
759 << std::setw(6) << std::setfill(
'0')
761 << std::setw(w) << std::setfill(c) ;
764std::ostream & G::operator<<( std::ostream & stream ,
const TimeInterval & ti )
776 bool ahead = t_in < t_zone ;
777 TimeInterval i = ahead ? (t_zone-t_in) : (t_in-t_zone) ;
778 return Offset{ ahead , i.
s() } ;
784 std::ostringstream ss ;
785 ss << ( tz < 0 ?
"-" :
"+" ) ;
786 if( tz < 0 ) tz = -tz ;
787 ss << (tz/10) << (tz%10) <<
"00" ;
794 unsigned int hh = (offset.second+30U) / 3600U ;
795 unsigned int mm = ((offset.second+30U) / 60U) % 60 ;
797 std::ostringstream ss ;
798 char sign = (offset.first || (hh==0&&mm==0)) ?
'+' :
'-' ;
799 ss << sign << (hh/10U) << (hh%10U) << (mm/10) << (mm%10) ;
An encapsulation of 'struct std::tm'.
int wday() const
Returns week day where sunday=0 and saturday=6.
int day() const
Returns the 1..31 month-day value.
static BrokenDownTime null()
Factory function for an unusable object with bogus component values.
std::time_t epochTimeFromLocal() const
Uses std::mktime() to convert this locale-dependent local broken-down time into epoch time.
std::string str() const
Returns str() using a "%F %T" format.
BrokenDownTime(const struct std::tm &)
Constructor.
int sec() const
Returns the 0..59 or 0..60 seconds value.
static BrokenDownTime utc(SystemTime)
Factory function for the utc broken-down time of the given epoch time.
static BrokenDownTime midday(int year, int month, int day)
Factory function for midday on the given date.
static BrokenDownTime midnight(int year, int month, int day)
Factory function for midnight starting the given date.
int month() const
Returns the 1..12 month value.
static BrokenDownTime local(SystemTime)
Factory function for the locale-dependent local broken-down time of the given epoch time.
int hour() const
Returns the 0..23 hour value.
int year() const
Returns the four-digit year value.
bool format(char *out, std::size_t out_size, const char *fmt) const
Puts the formatted date, including a terminating null character, into the given output buffer.
bool sameMinute(const BrokenDownTime &) const noexcept
Returns true if this and the other broken-down times are the same, at minute resolution with no round...
std::time_t epochTimeFromUtc() const
Converts this utc broken-down time into epoch time.
int min() const
Returns the 0..59 minute value.
static Offset offset(SystemTime)
Returns the offset in seconds between UTC and localtime as at the given system time.
static std::string offsetString(Offset offset)
Converts the given utc/localtime offset into a five-character "+/-hhmm" string.
Represents a unix-epoch time with microsecond resolution.
TimeInterval operator-(const SystemTime &start) const
Returns the given start time's interval() compared to this end time.
static SystemTime now()
Factory function for the current time.
std::time_t s() const noexcept
Returns the number of seconds since the start of the epoch.
SystemTime operator+(TimeInterval) const
Returns this time with given interval added.
unsigned int ms() const
Returns the millisecond fraction.
unsigned int us() const
Returns the microsecond fraction.
bool operator!=(const SystemTime &) const
Comparison operator.
BrokenDownTime local() const
Returns the locale-dependent local broken-down time.
bool operator>(const SystemTime &) const
Comparison operator.
void streamOut(std::ostream &) const
Streams out the time comprised of the s() value, a decimal point, and then the six-digit us() value.
TimeInterval interval(const SystemTime &end) const
Returns the interval between this time and the given end time.
bool sameSecond(const SystemTime &other) const noexcept
Returns true if this time and the other time are the same, at second resolution.
bool operator<=(const SystemTime &) const
Comparison operator.
bool isZero() const
Returns true if zero().
bool operator>=(const SystemTime &) const
Comparison operator.
static SystemTime zero()
Factory function for the start of the epoch.
SystemTime(std::time_t, unsigned long us=0UL) noexcept
Constructor.
BrokenDownTime utc() const
Returns the utc broken-down time.
void operator+=(TimeInterval)
Adds the given interval. Throws on overflow.
bool operator<(const SystemTime &) const
Comparison operator.
bool operator==(const SystemTime &) const
Comparison operator.
An interval between two G::SystemTime values or two G::TimerTime values.
TimeInterval(unsigned int s, unsigned int us=0U)
Constructor.
TimeInterval operator+(const TimeInterval &) const
Returns the combined interval. Throws on overflow.
static TimeInterval zero()
Factory function for the zero interval.
void operator-=(TimeInterval)
Subtracts the given interval. Throws on underflow.
bool operator==(const TimeInterval &) const
Comparison operator.
static TimeInterval limit()
Factory function for the maximum valid interval.
unsigned int s() const
Returns the number of seconds.
unsigned int us() const
Returns the fractional microseconds part.
void operator+=(TimeInterval)
Adds the given interval. Throws on overflow.
bool operator>(const TimeInterval &) const
Comparison operator.
TimeInterval operator-(const TimeInterval &) const
Returns the interval difference. Throws on underflow.
bool operator<(const TimeInterval &) const
Comparison operator.
bool operator!=(const TimeInterval &) const
Comparison operator.
void streamOut(std::ostream &) const
Streams out the interval.
bool operator>=(const TimeInterval &) const
Comparison operator.
bool operator<=(const TimeInterval &) const
Comparison operator.
A monotonically increasing subsecond-resolution timestamp, notionally unrelated to time_t.
bool isZero() const noexcept
Returns true if zero().
static TimerTime now()
Factory function for the current steady-clock time.
TimerTime operator+(const TimeInterval &) const
Returns this time with given interval added.
bool operator>(const TimerTime &) const
Comparison operator.
TimeInterval interval(const TimerTime &end) const
Returns the interval between this time and the given end time.
bool operator==(const TimerTime &) const
Comparison operator.
bool operator!=(const TimerTime &) const
Comparison operator.
TimeInterval operator-(const TimerTime &start) const
Returns the given start time's interval() compared to this end time.
bool sameSecond(const TimerTime &other) const
Returns true if this time and the other time are the same, at second resolution.
void operator+=(TimeInterval)
Adds an interval.
static TimerTime zero()
Factory function for the start of the epoch, guaranteed to be less than any now().
bool operator<=(const TimerTime &) const
Comparison operator.
bool operator>=(const TimerTime &) const
Comparison operator.
A class template like a simplified c++17 std::optional.
const T & value() const
Returns the value.
bool has_value() const noexcept
Returns true if a defined value.