blob: 84520755f7049c64c3ec2a8d84fe7b1dce507d46 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -07002/**
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>
26
27namespace ndn {
28namespace time {
29
Alexander Afanasyev85b17b82014-11-10 16:22:05 -080030static shared_ptr<CustomSystemClock> g_systemClock;
31static shared_ptr<CustomSteadyClock> g_steadyClock;
32
33// this method is defined in time-custom-clock.hpp
34void
35setCustomClocks(shared_ptr<CustomSteadyClock> steadyClock,
36 shared_ptr<CustomSystemClock> systemClock)
37{
38 g_systemClock = systemClock;
39 g_steadyClock = steadyClock;
40}
41
42/////////////////////////////////////////////////////////////////////////////////////////////
43
44system_clock::time_point
45system_clock::now() noexcept
46{
47 if (g_systemClock == nullptr) {
48 // optimized default version
49 return time_point(boost::chrono::system_clock::now().time_since_epoch());
50 }
51 else {
52 return g_systemClock->getNow();
53 }
54}
55
56std::time_t
57system_clock::to_time_t(const time_point& t) noexcept
58{
59 return duration_cast<seconds>(t.time_since_epoch()).count();
60}
61
62system_clock::time_point
63system_clock::from_time_t(std::time_t t) noexcept
64{
65 return time_point(seconds(t));
66}
67
68/////////////////////////////////////////////////////////////////////////////////////////////
69
70#ifdef __APPLE__
71 // Note that on OS X platform boost::steady_clock is not truly monotonic, so we use
72 // system_clock instead. Refer to https://svn.boost.org/trac/boost/ticket/7719)
73 typedef boost::chrono::system_clock base_steady_clock;
74#else
75 typedef boost::chrono::steady_clock base_steady_clock;
76#endif
77
78steady_clock::time_point
79steady_clock::now() noexcept
80{
81 if (g_steadyClock == nullptr) {
82 // optimized default version
83 return time_point(base_steady_clock::now().time_since_epoch());
84 }
85 else {
86 return g_steadyClock->getNow();
87 }
88}
89
90boost::posix_time::time_duration
91steady_clock::to_posix_duration(const duration& duration)
92{
93 if (g_steadyClock == nullptr) {
94 // optimized default version
95 return
96#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
97 boost::posix_time::nanoseconds(duration_cast<nanoseconds>(duration).count())
98#else
99 boost::posix_time::microseconds(duration_cast<microseconds>(duration).count())
100#endif
101 ;
102 }
103 else {
104 return g_steadyClock->toPosixDuration(duration);
105 }
106}
107
108/////////////////////////////////////////////////////////////////////////////////////////////
109
110const system_clock::TimePoint&
111getUnixEpoch()
112{
113 static system_clock::TimePoint epoch = system_clock::from_time_t(0);
114 return epoch;
115}
116
117milliseconds
118toUnixTimestamp(const system_clock::TimePoint& point)
119{
120 return duration_cast<milliseconds>(point - getUnixEpoch());
121}
122
123system_clock::TimePoint
124fromUnixTimestamp(const milliseconds& duration)
125{
126 return getUnixEpoch() + duration;
127}
128
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700129std::string
130toIsoString(const system_clock::TimePoint& timePoint)
131{
132 namespace bpt = boost::posix_time;
Junxiao Shi855eaa52017-04-04 20:10:43 +0000133 static bpt::ptime epoch(boost::gregorian::date(1970, 1, 1));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700134
Junxiao Shi855eaa52017-04-04 20:10:43 +0000135#ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
136 using BptResolutionUnit = nanoseconds;
137#else
138 using BptResolutionUnit = microseconds;
139#endif
140 constexpr auto unitsPerHour = duration_cast<BptResolutionUnit>(hours(1)).count();
141
142 auto sinceEpoch = duration_cast<BptResolutionUnit>(timePoint - getUnixEpoch()).count();
143 bpt::ptime ptime = epoch + bpt::time_duration(sinceEpoch / unitsPerHour, 0, 0,
144 sinceEpoch % unitsPerHour);
145
146 return bpt::to_iso_string(ptime);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700147}
148
149
150system_clock::TimePoint
151fromIsoString(const std::string& isoString)
152{
153 namespace bpt = boost::posix_time;
154 static bpt::ptime posixTimeEpoch = bpt::from_time_t(0);
155
156 bpt::ptime ptime = bpt::from_iso_string(isoString);
157
158 system_clock::TimePoint point =
159 system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds());
160 point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000);
161 return point;
162}
163
164
165std::string
166toString(const system_clock::TimePoint& timePoint,
167 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
168 const std::locale& locale/* = std::locale("C")*/)
169{
170 namespace bpt = boost::posix_time;
171 bpt::ptime ptime = bpt::from_time_t(system_clock::to_time_t(timePoint));
172
173 uint64_t micro = duration_cast<microseconds>(timePoint - getUnixEpoch()).count() % 1000000;
174 ptime += bpt::microseconds(micro);
175
176 bpt::time_facet* facet = new bpt::time_facet(format.c_str());
177 std::ostringstream formattedTimePoint;
178 formattedTimePoint.imbue(std::locale(locale, facet));
179 formattedTimePoint << ptime;
180
181 return formattedTimePoint.str();
182}
183
184
185system_clock::TimePoint
186fromString(const std::string& formattedTimePoint,
187 const std::string& format/* = "%Y-%m-%d %H:%M:%S"*/,
188 const std::locale& locale/* = std::locale("C")*/)
189{
190 namespace bpt = boost::posix_time;
191 static bpt::ptime posixTimeEpoch = bpt::from_time_t(0);
192
193 bpt::time_input_facet* facet = new bpt::time_input_facet(format);
194 std::istringstream is(formattedTimePoint);
195
196 is.imbue(std::locale(locale, facet));
197 bpt::ptime ptime;
198 is >> ptime;
199
200 system_clock::TimePoint point =
201 system_clock::from_time_t((ptime - posixTimeEpoch).total_seconds());
202 point += microseconds((ptime - posixTimeEpoch).total_microseconds() % 1000000);
203 return point;
204}
205
206} // namespace time
207} // namespace ndn
Alexander Afanasyev85b17b82014-11-10 16:22:05 -0800208
209namespace boost {
210namespace chrono {
211
212/////////////////////////////////////////////////////////////////////////////////////////////
213
214template<class CharT>
215std::basic_string<CharT>
216clock_string<ndn::time::system_clock, CharT>::since()
217{
218 if (ndn::time::g_systemClock == nullptr) {
219 // optimized default version
220 return clock_string<system_clock, CharT>::since();
221 }
222 else {
223 return ndn::time::g_systemClock->getSince();
224 }
225}
226
227template
228struct clock_string<ndn::time::system_clock, char>;
229
230/////////////////////////////////////////////////////////////////////////////////////////////
231
232template<class CharT>
233std::basic_string<CharT>
234clock_string<ndn::time::steady_clock, CharT>::since()
235{
236 if (ndn::time::g_steadyClock == nullptr) {
237 // optimized default version
238 return clock_string<ndn::time::base_steady_clock, CharT>::since();
239 }
240 else {
241 return ndn::time::g_steadyClock->getSince();
242 }
243}
244
245template
246struct clock_string<ndn::time::steady_clock, char>;
247
248} // namespace chrono
249} // namespace boost