VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gdatetime.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gdatetime.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gdatetime.h"
23 #include "gstr.h"
24 #include "gassert.h"
25 #include <sstream>
26 #include <iomanip>
27 
28 namespace
29 {
30  const std::time_t minute = 60 ;
31  const std::time_t hour = 60 * minute ;
32  const std::time_t day = 24 * hour ;
33 }
34 
35 G::EpochTime::EpochTime( std::time_t s_ , unsigned long us_ ) :
36  s(s_) ,
37  us(static_cast<unsigned int>(us_))
38 {
39  if( us_ >= 1000000UL )
40  {
41  s += static_cast<std::time_t>( us_ / 1000000UL ) ;
42  us = static_cast<unsigned int>( us_ % 1000000UL ) ;
43  }
44 }
45 
46 G::EpochTime G::operator+( G::EpochTime lhs , G::EpochTime rhs )
47 {
48  lhs.s += rhs.s ;
49  lhs.us += rhs.us ;
50  if( lhs.us > 1000000UL )
51  {
52  lhs.s++ ;
53  lhs.us -= 1000000UL ;
54  }
55  return lhs ;
56 }
57 
58 G::EpochTime G::operator-( G::EpochTime big , G::EpochTime small_ )
59 {
60  big.s -= small_.s ;
61  if( small_.us > big.us )
62  {
63  big.s-- ;
64  big.us += 1000000U ;
65  }
66  big.us -= small_.us ;
67  return big ;
68 }
69 
70 void G::EpochTime::streamOut( std::ostream & stream ) const
71 {
72  std::streamsize w = stream.width() ;
73  char c = stream.fill() ;
74  stream
75  << s << "."
76  << std::setw(6) << std::setfill('0')
77  << us
78  << std::setw(w) << std::setfill(c) ;
79 }
80 
81 // ==
82 
83 G::EpochTime G::DateTime::epochTime( const BrokenDownTime & bdt_in )
84 {
85  // get a rough starting point -- mktime() works with localtime,
86  // including daylight saving, but there is no UTC equivalent --
87  // timegm(3) is deprecated in favour of nasty fiddling with the
88  // TZ environment variable
89  //
90  BrokenDownTime bdt( bdt_in ) ;
91  const bool leap_second = bdt.tm_sec == 60 ;
92  if( leap_second ) bdt.tm_sec = 59 ;
93  EpochTime tlocal( std::mktime(&bdt) , 0U ) ; // localtime
94 
95  // optimisation
96  static std::time_t diff = 0 ;
97  static bool diff_set = false ;
98  if( diff_set )
99  {
100  EpochTime t( tlocal.s + diff ) ;
101  if( equivalent( t , bdt_in ) )
102  return leap_second ? (t+1) : t ;
103  diff_set = false ; // optimisation failure eg. change of dst
104  }
105 
106  // iterate over all possible timezones
107  //
108  const std::time_t dt = minute * 30 ;
109  const std::time_t day_and_a_bit = day + dt ;
110  EpochTime t( tlocal.s - day_and_a_bit ) ;
111  const EpochTime end( tlocal.s + day_and_a_bit ) ;
112  for( diff = -day_and_a_bit ; t <= end ; t.s += dt , diff += dt )
113  {
114  if( equivalent( t , bdt_in ) )
115  {
116  diff_set = true ;
117  return leap_second ? (t+1) : t ;
118  }
119  }
120  throw Error() ;
121 }
122 
123 G::DateTime::BrokenDownTime G::DateTime::utc( EpochTime epoch_time )
124 {
125  static BrokenDownTime zero ;
126  BrokenDownTime result = zero ;
127  G::DateTime::gmtime_imp( &epoch_time.s , &result ) ;
128  return result ;
129 }
130 
131 G::DateTime::BrokenDownTime G::DateTime::local( EpochTime epoch_time )
132 {
133  static BrokenDownTime zero ;
134  BrokenDownTime bdt_local = zero ;
135  G::DateTime::localtime_imp( &epoch_time.s , &bdt_local ) ;
136  return bdt_local ;
137 }
138 
139 G::DateTime::Offset G::DateTime::offset( EpochTime utc )
140 {
141  BrokenDownTime bdt_local = local(utc) ;
142 
143  EpochTime local = epochTime(bdt_local) ;
144  bool ahead = local.s >= utc.s ; // ie. east-of
145  EpochTime n( ahead ? (local.s-utc.s) : (utc.s-local.s) ) ;
146  return Offset( ahead , static_cast<unsigned int>(n.s) ) ;
147 }
148 
149 std::string G::DateTime::offsetString( int tz )
150 {
151  std::ostringstream ss ;
152  ss << ( tz < 0 ? "-" : "+" ) ;
153  if( tz < 0 ) tz = -tz ;
154  ss << (tz/10) << (tz%10) << "00" ;
155  return ss.str() ;
156 }
157 
158 std::string G::DateTime::offsetString( Offset offset )
159 {
160  unsigned int hh = offset.second / 3600U ;
161  unsigned int mm = (offset.second / 60U) % 60 ;
162 
163  std::ostringstream ss ;
164  char sign = (offset.first || (hh==0&&mm==0)) ? '+' : '-' ;
165  ss << sign << (hh/10U) << (hh%10U) << (mm/10) << (mm%10) ;
166  return ss.str() ;
167 }
168 
169 bool G::DateTime::equivalent( EpochTime t , const BrokenDownTime & bdt_in )
170 {
171  BrokenDownTime bdt_test = utc(t) ;
172  return equivalent( bdt_test , bdt_in ) ;
173 }
174 
175 bool G::DateTime::equivalent( const BrokenDownTime & bdt1 , const BrokenDownTime & bdt2 )
176 {
177  return
178  bdt1.tm_mday == bdt2.tm_mday &&
179  bdt1.tm_hour == bdt2.tm_hour &&
180  bdt1.tm_min == bdt2.tm_min ;
181 }
182 
183 /// \file gdatetime.cpp
static BrokenDownTime utc(EpochTime epoch_time)
Converts from epoch time to UTC broken-down-time.
Definition: gdatetime.cpp:123
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
static Offset offset(EpochTime epoch_time)
Returns the offset between UTC and localtime as at 'epoch_time'.
Definition: gdatetime.cpp:139
static BrokenDownTime local(EpochTime epoch_time)
Converts from epoch time to local broken-down-time.
Definition: gdatetime.cpp:131
void streamOut(std::ostream &) const
Used by operator<<.
Definition: gdatetime.cpp:70
static std::string offsetString(Offset offset)
Converts the given utc/localtime offset into a five-character "+/-hhmm" string.
Definition: gdatetime.cpp:158
EpochTime(std::time_t)
Constructor.
Definition: gdatetime.h:124
static EpochTime epochTime(const BrokenDownTime &broken_down_time)
Converts from UTC broken-down-time to epoch time.
Definition: gdatetime.cpp:83