1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2017, 2018 Tomasz Kamiński
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #include "tz.h"
24 #include <cassert>
25 #include <type_traits>
26 
27 //used to count number of conversion
28 int conversions = 0;
29 
30 //to/from impl
31 struct mil_clock
32 {
33   using duration = typename std::common_type<std::chrono::system_clock::duration, date::days>::type;
34   using rep = duration::rep;
35   using period = duration::period;
36   using time_point = std::chrono::time_point<mil_clock, duration>;
37 
38   static constexpr date::sys_days epoch{date::days{1000}};
39 
40   template<typename Duration>
41   static
42   std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, date::days>::type>
to_sysmil_clock43   to_sys(std::chrono::time_point<mil_clock, Duration> const& tp)
44   {
45     ++conversions;
46     return epoch + tp.time_since_epoch();
47   }
48 
49   template<typename Duration>
50   static
51   std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
from_sysmil_clock52   from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp)
53   {
54     ++conversions;
55     using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
56     return res(tp - epoch);
57   }
58 
59   template<typename Duration>
60   static
61   std::chrono::time_point<date::local_t, typename std::common_type<Duration, date::days>::type>
to_localmil_clock62   to_local(std::chrono::time_point<mil_clock, Duration> const& tp)
63   {
64      return date::clock_cast<date::local_t>(to_sys(tp));
65   }
66 
67   template<typename Duration>
68   static
69   std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
from_localmil_clock70   from_local(std::chrono::time_point<date::local_t, Duration> const& tp)
71   {
72     return from_sys(date::clock_cast<std::chrono::system_clock>(tp));
73   }
74 
75 
nowmil_clock76   static time_point now()
77   {
78     return from_sys(std::chrono::system_clock::now());
79   }
80 };
81 
82 
83 date::sys_days const mil_clock::epoch;
84 
85 // traits example
86 struct s2s_clock
87 {
88   using duration = std::chrono::system_clock::duration;
89   using rep = duration::rep;
90   using period = duration::period;
91   using time_point = std::chrono::time_point<s2s_clock, duration>;
92 
93   template<typename Duration>
94   static
95   std::chrono::time_point<std::chrono::system_clock, Duration>
to_syss2s_clock96   to_sys(std::chrono::time_point<s2s_clock, Duration> const& tp)
97   {
98     ++conversions;
99     return std::chrono::time_point<std::chrono::system_clock, Duration>(tp.time_since_epoch());
100   }
101 
102   template<typename Duration>
103   static
104   std::chrono::time_point<s2s_clock, Duration>
from_syss2s_clock105   from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp)
106   {
107     ++conversions;
108     return std::chrono::time_point<s2s_clock, Duration>(tp.time_since_epoch());
109   }
110 
nows2s_clock111   static time_point now()
112   {
113     return from_sys(std::chrono::system_clock::now());
114   }
115 };
116 
117 namespace date
118 {
119    template<>
120    struct clock_time_conversion<mil_clock, s2s_clock>
121    {
122      template<typename Duration>
123      std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
operator ()date::clock_time_conversion124      operator()(std::chrono::time_point<s2s_clock, Duration> const& tp)
125      {
126        ++conversions;
127        using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
128        return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch());
129      }
130    };
131 }
132 
133 int
main()134 main()
135 {
136     using namespace date;
137     using sys_clock = std::chrono::system_clock;
138 
139     // self
140     {
141        sys_days st(1997_y/dec/12);
142        auto mt = mil_clock::from_sys(st);
143 
144        assert(clock_cast<mil_clock>(mt) == mt);
145     }
146 
147     // mil <-> local
148     {
149        local_days lt(1997_y/dec/12);
150        auto mt = mil_clock::from_local(lt);
151 
152        assert(clock_cast<mil_clock>(lt) == mt);
153        assert(clock_cast<local_t>(mt) == lt);
154     }
155 
156     // mil <-> sys
157     {
158        sys_days st(1997_y/dec/12);
159        auto mt = mil_clock::from_sys(st);
160 
161        assert(clock_cast<mil_clock>(st) == mt);
162        assert(clock_cast<sys_clock>(mt) == st);
163     }
164 
165     // mil <-> utc
166     {
167        sys_days st(1997_y/dec/12);
168        auto mt = mil_clock::from_sys(st);
169        auto ut = utc_clock::from_sys(st);
170 
171        assert(clock_cast<mil_clock>(ut) == mt);
172        assert(clock_cast<utc_clock>(mt) == ut);
173     }
174 
175     // mil <-> tai
176     {
177        sys_days st(1997_y/dec/12);
178        auto mt = mil_clock::from_sys(st);
179        auto ut = utc_clock::from_sys(st);
180        auto tt = tai_clock::from_utc(ut);
181 
182        assert(clock_cast<tai_clock>(mt) == tt);
183        assert(clock_cast<mil_clock>(tt) == mt);
184     }
185 
186     // mil <-> gps
187     {
188        sys_days st(1997_y/dec/12);
189        auto mt = mil_clock::from_sys(st);
190        auto ut = utc_clock::from_sys(st);
191        auto gt = gps_clock::from_utc(ut);
192 
193        assert(clock_cast<gps_clock>(mt) == gt);
194        assert(clock_cast<mil_clock>(gt) == mt);
195     }
196 
197     // s2s -> mil
198     {
199        sys_days st(1997_y/dec/12);
200        auto mt = mil_clock::from_sys(st);
201        auto s2t = s2s_clock::from_sys(st);
202 
203        //direct trait conversion
204        conversions = 0;
205        assert(clock_cast<mil_clock>(s2t) == mt);
206        assert(conversions == 1);
207 
208        //uses sys_clock
209        conversions = 0;
210        assert(clock_cast<s2s_clock>(mt) == s2t);
211        assert(conversions == 2);
212     }
213 }
214