blob: 64b43e32c93a3e074b3852dbd32eff43c1c0c317 [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/*
Davide Pesavento5afbb0b2018-01-01 17:24:18 -05003 * Copyright (c) 2013-2018 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
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050034// this function is declared in time-custom-clock.hpp
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080035void
36setCustomClocks(shared_ptr<CustomSteadyClock> steadyClock,
37 shared_ptr<CustomSystemClock> systemClock)
38{
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050039 g_systemClock = std::move(systemClock);
40 g_steadyClock = std::move(steadyClock);
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080041}
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
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050058system_clock::to_time_t(const system_clock::time_point& t) noexcept
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080059{
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
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050091steady_clock::duration
92steady_clock::to_wait_duration(steady_clock::duration d)
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080093{
94 if (g_steadyClock == nullptr) {
95 // optimized default version
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050096 return d;
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080097 }
98 else {
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050099 return g_steadyClock->toWaitDuration(d);
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800100 }
101}
102
103/////////////////////////////////////////////////////////////////////////////////////////////
104
105const system_clock::TimePoint&
106getUnixEpoch()
107{
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500108 static constexpr system_clock::TimePoint epoch(seconds::zero());
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800109 return epoch;
110}
111
112milliseconds
113toUnixTimestamp(const system_clock::TimePoint& point)
114{
115 return duration_cast<milliseconds>(point - getUnixEpoch());
116}
117
118system_clock::TimePoint
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500119fromUnixTimestamp(milliseconds duration)
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800120{
121 return getUnixEpoch() + duration;
122}
123
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500124static boost::posix_time::ptime
125convertToPosixTime(const system_clock::TimePoint& timePoint)
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700126{
127 namespace bpt = boost::posix_time;
Junxiao Shi855eaa52017-04-04 20:10:43 +0000128 static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700129
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500130 using BptResolution =
131#if defined(BOOST_DATE_TIME_HAS_NANOSECONDS)
132 nanoseconds;
133#elif defined(BOOST_DATE_TIME_HAS_MICROSECONDS)
134 microseconds;
Junxiao Shi855eaa52017-04-04 20:10:43 +0000135#else
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500136 milliseconds;
Junxiao Shi855eaa52017-04-04 20:10:43 +0000137#endif
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500138 constexpr auto unitsPerHour = duration_cast<BptResolution>(1_h).count();
Junxiao Shi855eaa52017-04-04 20:10:43 +0000139
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500140 auto sinceEpoch = duration_cast<BptResolution>(timePoint - getUnixEpoch()).count();
141 return epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0, sinceEpoch % unitsPerHour);
142}
Junxiao Shi855eaa52017-04-04 20:10:43 +0000143
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500144std::string
145toIsoString(const system_clock::TimePoint& timePoint)
146{
147 return boost::posix_time::to_iso_string(convertToPosixTime(timePoint));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700148}
149
Alexander Afanasyeve66040e2018-01-25 19:15:30 -0500150static system_clock::TimePoint
151convertToTimePoint(const boost::posix_time::ptime& ptime)
152{
153 namespace bpt = boost::posix_time;
154 static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
155
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500156 // .total_seconds() has an issue with large dates until Boost 1.66, see #4478.
157 // time_t overflows for large dates on 32-bit platforms (Y2038 problem).
158 auto sinceEpoch = ptime - epoch;
159 auto point = system_clock::TimePoint(seconds(sinceEpoch.ticks() / bpt::time_duration::ticks_per_second()));
160 return point + microseconds(sinceEpoch.total_microseconds() % 1000000);
Alexander Afanasyeve66040e2018-01-25 19:15:30 -0500161}
162
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700163system_clock::TimePoint
164fromIsoString(const std::string& isoString)
165{
Alexander Afanasyeve66040e2018-01-25 19:15:30 -0500166 return convertToTimePoint(boost::posix_time::from_iso_string(isoString));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700167}
168
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700169std::string
170toString(const system_clock::TimePoint& timePoint,
171 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
172 const std::locale& locale/* = std::locale("C")*/)
173{
174 namespace bpt = boost::posix_time;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700175
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500176 std::ostringstream os;
177 auto* facet = new bpt::time_facet(format.data());
178 os.imbue(std::locale(locale, facet));
179 os << convertToPosixTime(timePoint);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700180
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500181 return os.str();
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700182}
183
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700184system_clock::TimePoint
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500185fromString(const std::string& timePointStr,
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700186 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
187 const std::locale& locale/* = std::locale("C")*/)
188{
189 namespace bpt = boost::posix_time;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700190
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500191 std::istringstream is(timePointStr);
Davide Pesaventoc5ba65b2018-01-28 00:30:25 -0500192 auto* facet = new bpt::time_input_facet(format);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700193 is.imbue(std::locale(locale, facet));
194 bpt::ptime ptime;
195 is >> ptime;
196
Alexander Afanasyeve66040e2018-01-25 19:15:30 -0500197 return convertToTimePoint(ptime);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700198}
199
200} // namespace time
201} // namespace ndn
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800202
203namespace boost {
204namespace chrono {
205
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800206template<class CharT>
207std::basic_string<CharT>
208clock_string<ndn::time::system_clock, CharT>::since()
209{
210 if (ndn::time::g_systemClock == nullptr) {
211 // optimized default version
212 return clock_string<system_clock, CharT>::since();
213 }
214 else {
215 return ndn::time::g_systemClock->getSince();
216 }
217}
218
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800219template<class CharT>
220std::basic_string<CharT>
221clock_string<ndn::time::steady_clock, CharT>::since()
222{
223 if (ndn::time::g_steadyClock == nullptr) {
224 // optimized default version
225 return clock_string<ndn::time::base_steady_clock, CharT>::since();
226 }
227 else {
228 return ndn::time::g_steadyClock->getSince();
229 }
230}
231
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500232template struct clock_string<ndn::time::system_clock, char>;
233template struct clock_string<ndn::time::steady_clock, char>;
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800234
235} // namespace chrono
236} // namespace boost