blob: 6f669cb6836d53dc2eabb515176cd563a39edfd3 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa84f4642017-08-23 16:14:51 -04002/*
Junxiao Shi855eaa52017-04-04 20:10:43 +00003 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070020 */
21
22#include "time.hpp"
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080023#include "time-custom-clock.hpp"
24
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070025#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040026#include <sstream>
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027
28namespace ndn {
29namespace time {
30
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080031static shared_ptr<CustomSystemClock> g_systemClock;
32static shared_ptr<CustomSteadyClock> g_steadyClock;
33
34// this method is defined in time-custom-clock.hpp
35void
36setCustomClocks(shared_ptr<CustomSteadyClock> steadyClock,
37 shared_ptr<CustomSystemClock> systemClock)
38{
39 g_systemClock = systemClock;
40 g_steadyClock = steadyClock;
41}
42
43/////////////////////////////////////////////////////////////////////////////////////////////
44
45system_clock::time_point
46system_clock::now() noexcept
47{
48 if (g_systemClock == nullptr) {
49 // optimized default version
50 return time_point(boost::chrono::system_clock::now().time_since_epoch());
51 }
52 else {
53 return g_systemClock->getNow();
54 }
55}
56
57std::time_t
58system_clock::to_time_t(const time_point& t) noexcept
59{
60 return duration_cast<seconds>(t.time_since_epoch()).count();
61}
62
63system_clock::time_point
64system_clock::from_time_t(std::time_t t) noexcept
65{
66 return time_point(seconds(t));
67}
68
69/////////////////////////////////////////////////////////////////////////////////////////////
70
71#ifdef __APPLE__
72 // Note that on OS X platform boost::steady_clock is not truly monotonic, so we use
73 // system_clock instead. Refer to https://svn.boost.org/trac/boost/ticket/7719)
74 typedef boost::chrono::system_clock base_steady_clock;
75#else
76 typedef boost::chrono::steady_clock base_steady_clock;
77#endif
78
79steady_clock::time_point
80steady_clock::now() noexcept
81{
82 if (g_steadyClock == nullptr) {
83 // optimized default version
84 return time_point(base_steady_clock::now().time_since_epoch());
85 }
86 else {
87 return g_steadyClock->getNow();
88 }
89}
90
91boost::posix_time::time_duration
92steady_clock::to_posix_duration(const duration& duration)
93{
94 if (g_steadyClock == nullptr) {
95 // optimized default version
96 return
97#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
98 boost::posix_time::nanoseconds(duration_cast<nanoseconds>(duration).count())
99#else
100 boost::posix_time::microseconds(duration_cast<microseconds>(duration).count())
101#endif
102 ;
103 }
104 else {
105 return g_steadyClock->toPosixDuration(duration);
106 }
107}
108
109/////////////////////////////////////////////////////////////////////////////////////////////
110
111const system_clock::TimePoint&
112getUnixEpoch()
113{
114 static system_clock::TimePoint epoch = system_clock::from_time_t(0);
115 return epoch;
116}
117
118milliseconds
119toUnixTimestamp(const system_clock::TimePoint& point)
120{
121 return duration_cast<milliseconds>(point - getUnixEpoch());
122}
123
124system_clock::TimePoint
125fromUnixTimestamp(const milliseconds& duration)
126{
127 return getUnixEpoch() + duration;
128}
129
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700130std::string
131toIsoString(const system_clock::TimePoint& timePoint)
132{
133 namespace bpt = boost::posix_time;
Junxiao Shi855eaa52017-04-04 20:10:43 +0000134 static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700135
Junxiao Shi855eaa52017-04-04 20:10:43 +0000136#ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
137 using BptResolutionUnit = nanoseconds;
138#else
139 using BptResolutionUnit = microseconds;
140#endif
141 constexpr auto unitsPerHour = duration_cast<BptResolutionUnit>(hours(1)).count();
142
143 auto sinceEpoch = duration_cast<BptResolutionUnit>(timePoint - getUnixEpoch()).count();
144 bpt::ptime ptime = epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0,
145 sinceEpoch % unitsPerHour);
146
147 return bpt::to_iso_string(ptime);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700148}
149
150
151system_clock::TimePoint
152fromIsoString(const std::string& isoString)
153{
154 namespace bpt = boost::posix_time;
155 static bpt::ptime posixTimeEpoch = bpt::from_time_t(0);
156
157 bpt::ptime ptime = bpt::from_iso_string(isoString);
158
159 system_clock::TimePoint point =
160 system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds());
161 point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000);
162 return point;
163}
164
165
166std::string
167toString(const system_clock::TimePoint& timePoint,
168 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
169 const std::locale& locale/* = std::locale("C")*/)
170{
171 namespace bpt = boost::posix_time;
172 bpt::ptime ptime = bpt::from_time_t(system_clock::to_time_t(timePoint));
173
174 uint64_t micro = duration_cast<microseconds>(timePoint - getUnixEpoch()).count() % 1000000;
175 ptime += bpt::microseconds(micro);
176
177 bpt::time_facet* facet = new bpt::time_facet(format.c_str());
178 std::ostringstream formattedTimePoint;
179 formattedTimePoint.imbue(std::locale(locale, facet));
180 formattedTimePoint << ptime;
181
182 return formattedTimePoint.str();
183}
184
185
186system_clock::TimePoint
187fromString(const std::string& formattedTimePoint,
188 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
189 const std::locale& locale/* = std::locale("C")*/)
190{
191 namespace bpt = boost::posix_time;
192 static bpt::ptime posixTimeEpoch = bpt::from_time_t(0);
193
194 bpt::time_input_facet* facet = new bpt::time_input_facet(format);
195 std::istringstream is(formattedTimePoint);
196
197 is.imbue(std::locale(locale, facet));
198 bpt::ptime ptime;
199 is >> ptime;
200
201 system_clock::TimePoint point =
202 system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds());
203 point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000);
204 return point;
205}
206
207} // namespace time
208} // namespace ndn
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800209
210namespace boost {
211namespace chrono {
212
213/////////////////////////////////////////////////////////////////////////////////////////////
214
215template<class CharT>
216std::basic_string<CharT>
217clock_string<ndn::time::system_clock, CharT>::since()
218{
219 if (ndn::time::g_systemClock == nullptr) {
220 // optimized default version
221 return clock_string<system_clock, CharT>::since();
222 }
223 else {
224 return ndn::time::g_systemClock->getSince();
225 }
226}
227
228template
229struct clock_string<ndn::time::system_clock, char>;
230
231/////////////////////////////////////////////////////////////////////////////////////////////
232
233template<class CharT>
234std::basic_string<CharT>
235clock_string<ndn::time::steady_clock, CharT>::since()
236{
237 if (ndn::time::g_steadyClock == nullptr) {
238 // optimized default version
239 return clock_string<ndn::time::base_steady_clock, CharT>::since();
240 }
241 else {
242 return ndn::time::g_steadyClock->getSince();
243 }
244}
245
246template
247struct clock_string<ndn::time::steady_clock, char>;
248
249} // namespace chrono
250} // namespace boost