1/*
2 * Copyright 2017-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * Conversions between std::chrono types and POSIX time types.
19 *
20 * These conversions will fail with a ConversionError if an overflow would
21 * occur performing the conversion. (e.g., if the input value cannot fit in
22 * the destination type). However they allow loss of precision (e.g.,
23 * converting nanoseconds to a struct timeval which only has microsecond
24 * granularity, or a struct timespec to std::chrono::minutes).
25 */
26
27#pragma once
28
29#include <chrono>
30#include <type_traits>
31
32#include <folly/Conv.h>
33#include <folly/Expected.h>
34#include <folly/portability/SysTime.h>
35#include <folly/portability/SysTypes.h>
36
37namespace folly {
38namespace detail {
39
40template <typename T>
41struct is_duration : std::false_type {};
42template <typename Rep, typename Period>
43struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
44template <typename T>
45struct is_time_point : std::false_type {};
46template <typename Clock, typename Duration>
47struct is_time_point<std::chrono::time_point<Clock, Duration>>
48 : std::true_type {};
49template <typename T>
50struct is_std_chrono_type {
51 static constexpr bool value =
52 is_duration<T>::value || is_time_point<T>::value;
53};
54template <typename T>
55struct is_posix_time_type {
56 static constexpr bool value = std::is_same<T, struct timespec>::value ||
57 std::is_same<T, struct timeval>::value;
58};
59template <typename Tgt, typename Src>
60struct is_chrono_conversion {
61 static constexpr bool value =
62 ((is_std_chrono_type<Tgt>::value && is_posix_time_type<Src>::value) ||
63 (is_posix_time_type<Tgt>::value && is_std_chrono_type<Src>::value));
64};
65
66/**
67 * This converts a number in some input type to time_t while ensuring that it
68 * fits in the range of numbers representable by time_t.
69 *
70 * This is similar to the normal folly::tryTo() behavior when converting
71 * arthmetic types to an integer type, except that it does not complain about
72 * floating point conversions losing precision.
73 */
74template <typename Src>
75Expected<time_t, ConversionCode> chronoRangeCheck(Src value) {
76 if (value > std::numeric_limits<time_t>::max()) {
77 return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
78 }
79 if (std::is_signed<Src>::value) {
80 if (value < std::numeric_limits<time_t>::lowest()) {
81 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
82 }
83 }
84
85 return static_cast<time_t>(value);
86}
87
88/**
89 * Convert a std::chrono::duration with second granularity to a pair of
90 * (seconds, subseconds)
91 *
92 * The SubsecondRatio template parameter specifies what type of subseconds to
93 * return. This must have a numerator of 1.
94 */
95template <typename SubsecondRatio, typename Rep>
96static Expected<std::pair<time_t, long>, ConversionCode> durationToPosixTime(
97 const std::chrono::duration<Rep, std::ratio<1, 1>>& duration) {
98 static_assert(
99 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
100
101 auto sec = chronoRangeCheck(duration.count());
102 if (sec.hasError()) {
103 return makeUnexpected(sec.error());
104 }
105
106 time_t secValue = sec.value();
107 long subsec = 0L;
108 if (std::is_floating_point<Rep>::value) {
109 auto fraction = (duration.count() - secValue);
110 subsec = static_cast<long>(fraction * SubsecondRatio::den);
111 if (duration.count() < 0 && fraction < 0) {
112 if (secValue == std::numeric_limits<time_t>::lowest()) {
113 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
114 }
115 secValue -= 1;
116 subsec += SubsecondRatio::den;
117 }
118 }
119 return std::pair<time_t, long>{secValue, subsec};
120}
121
122/**
123 * Convert a std::chrono::duration with subsecond granularity to a pair of
124 * (seconds, subseconds)
125 */
126template <typename SubsecondRatio, typename Rep, std::intmax_t Denominator>
127static Expected<std::pair<time_t, long>, ConversionCode> durationToPosixTime(
128 const std::chrono::duration<Rep, std::ratio<1, Denominator>>& duration) {
129 static_assert(Denominator != 1, "special case expecting den != 1");
130 static_assert(
131 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
132
133 auto sec = chronoRangeCheck(duration.count() / Denominator);
134 if (sec.hasError()) {
135 return makeUnexpected(sec.error());
136 }
137 auto secTimeT = sec.value();
138
139 auto remainder = duration.count() - (secTimeT * Denominator);
140 auto subsec = (remainder * SubsecondRatio::den) / Denominator;
141 if (UNLIKELY(duration.count() < 0) && remainder != 0) {
142 if (secTimeT == std::numeric_limits<time_t>::lowest()) {
143 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
144 }
145 secTimeT -= 1;
146 subsec += SubsecondRatio::den;
147 }
148
149 return std::pair<time_t, long>{secTimeT, subsec};
150}
151
152/**
153 * Convert a std::chrono::duration with coarser-than-second granularity to a
154 * pair of (seconds, subseconds)
155 */
156template <typename SubsecondRatio, typename Rep, std::intmax_t Numerator>
157static Expected<std::pair<time_t, long>, ConversionCode> durationToPosixTime(
158 const std::chrono::duration<Rep, std::ratio<Numerator, 1>>& duration) {
159 static_assert(Numerator != 1, "special case expecting num!=1");
160 static_assert(
161 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
162
163 constexpr auto maxValue = std::numeric_limits<time_t>::max() / Numerator;
164 constexpr auto minValue = std::numeric_limits<time_t>::lowest() / Numerator;
165 if (duration.count() > maxValue) {
166 return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
167 }
168 if (duration.count() < minValue) {
169 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
170 }
171
172 // Note that we can't use chronoRangeCheck() here since we have to check
173 // if (duration.count() * Numerator) would overflow (which we do above).
174 auto secOriginalRep = (duration.count() * Numerator);
175 auto sec = static_cast<time_t>(secOriginalRep);
176
177 long subsec = 0L;
178 if (std::is_floating_point<Rep>::value) {
179 auto fraction = secOriginalRep - sec;
180 subsec = static_cast<long>(fraction * SubsecondRatio::den);
181 if (duration.count() < 0 && fraction < 0) {
182 if (sec == std::numeric_limits<time_t>::lowest()) {
183 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
184 }
185 sec -= 1;
186 subsec += SubsecondRatio::den;
187 }
188 }
189 return std::pair<time_t, long>{sec, subsec};
190}
191
192/*
193 * Helper classes for picking an intermediate duration type to use
194 * when doing conversions to/from durations where neither the numerator nor
195 * denominator are 1.
196 */
197template <typename T, bool IsFloatingPoint, bool IsSigned>
198struct IntermediateTimeRep {};
199template <typename T, bool IsSigned>
200struct IntermediateTimeRep<T, true, IsSigned> {
201 using type = T;
202};
203template <typename T>
204struct IntermediateTimeRep<T, false, true> {
205 using type = intmax_t;
206};
207template <typename T>
208struct IntermediateTimeRep<T, false, false> {
209 using type = uintmax_t;
210};
211// For IntermediateDuration we always use 1 as the numerator, and the original
212// Period denominator. This ensures that we do not lose precision when
213// performing the conversion.
214template <typename Rep, typename Period>
215using IntermediateDuration = std::chrono::duration<
216 typename IntermediateTimeRep<
217 Rep,
218 std::is_floating_point<Rep>::value,
219 std::is_signed<Rep>::value>::type,
220 std::ratio<1, Period::den>>;
221
222/**
223 * Convert a std::chrono::duration to a pair of (seconds, subseconds)
224 *
225 * This overload is only used for unusual durations where neither the numerator
226 * nor denominator are 1.
227 */
228template <typename SubsecondRatio, typename Rep, typename Period>
229Expected<std::pair<time_t, long>, ConversionCode> durationToPosixTime(
230 const std::chrono::duration<Rep, Period>& duration) {
231 static_assert(Period::num != 1, "should use special-case code when num==1");
232 static_assert(Period::den != 1, "should use special-case code when den==1");
233 static_assert(
234 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
235
236 // Perform this conversion by first converting to a duration where the
237 // numerator is 1, then convert to the output type.
238 using IntermediateType = IntermediateDuration<Rep, Period>;
239 using IntermediateRep = typename IntermediateType::rep;
240
241 // Check to see if we would have overflow converting to the intermediate
242 // type.
243 constexpr auto maxInput =
244 std::numeric_limits<IntermediateRep>::max() / Period::num;
245 if (duration.count() > maxInput) {
246 return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
247 }
248 constexpr auto minInput =
249 std::numeric_limits<IntermediateRep>::min() / Period::num;
250 if (duration.count() < minInput) {
251 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
252 }
253 auto intermediate =
254 IntermediateType{static_cast<IntermediateRep>(duration.count()) *
255 static_cast<IntermediateRep>(Period::num)};
256
257 return durationToPosixTime<SubsecondRatio>(intermediate);
258}
259
260/**
261 * Check for overflow when converting to a duration type that is second
262 * granularity or finer (e.g., nanoseconds, milliseconds, seconds)
263 *
264 * This assumes the input is normalized, with subseconds >= 0 and subseconds
265 * less than 1 second.
266 */
267template <bool IsFloatingPoint>
268struct CheckOverflowToDuration {
269 template <
270 typename Tgt,
271 typename SubsecondRatio,
272 typename Seconds,
273 typename Subseconds>
274 static ConversionCode check(Seconds seconds, Subseconds subseconds) {
275 static_assert(
276 Tgt::period::num == 1,
277 "this implementation should only be used for subsecond granularity "
278 "duration types");
279 static_assert(
280 !std::is_floating_point<typename Tgt::rep>::value, "incorrect usage");
281 static_assert(
282 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
283
284 if (LIKELY(seconds >= 0)) {
285 constexpr auto maxCount = std::numeric_limits<typename Tgt::rep>::max();
286 constexpr auto maxSeconds = maxCount / Tgt::period::den;
287
288 auto unsignedSeconds = to_unsigned(seconds);
289 if (LIKELY(unsignedSeconds < maxSeconds)) {
290 return ConversionCode::SUCCESS;
291 }
292
293 if (UNLIKELY(unsignedSeconds == maxSeconds)) {
294 constexpr auto maxRemainder =
295 maxCount - (maxSeconds * Tgt::period::den);
296 constexpr auto maxSubseconds =
297 (maxRemainder * SubsecondRatio::den) / Tgt::period::den;
298 if (subseconds <= 0) {
299 return ConversionCode::SUCCESS;
300 }
301 if (to_unsigned(subseconds) <= maxSubseconds) {
302 return ConversionCode::SUCCESS;
303 }
304 }
305 return ConversionCode::POSITIVE_OVERFLOW;
306 } else if (std::is_unsigned<typename Tgt::rep>::value) {
307 return ConversionCode::NEGATIVE_OVERFLOW;
308 } else {
309 constexpr auto minCount =
310 to_signed(std::numeric_limits<typename Tgt::rep>::lowest());
311 constexpr auto minSeconds = (minCount / Tgt::period::den);
312 if (LIKELY(seconds >= minSeconds)) {
313 return ConversionCode::SUCCESS;
314 }
315
316 if (UNLIKELY(seconds == minSeconds - 1)) {
317 constexpr auto maxRemainder =
318 minCount - (minSeconds * Tgt::period::den) + Tgt::period::den;
319 constexpr auto maxSubseconds =
320 (maxRemainder * SubsecondRatio::den) / Tgt::period::den;
321 if (subseconds <= 0) {
322 return ConversionCode::NEGATIVE_OVERFLOW;
323 }
324 if (subseconds >= maxSubseconds) {
325 return ConversionCode::SUCCESS;
326 }
327 }
328 return ConversionCode::NEGATIVE_OVERFLOW;
329 }
330 }
331};
332
333template <>
334struct CheckOverflowToDuration<true> {
335 template <
336 typename Tgt,
337 typename SubsecondRatio,
338 typename Seconds,
339 typename Subseconds>
340 static ConversionCode check(
341 Seconds /* seconds */,
342 Subseconds /* subseconds */) {
343 static_assert(
344 std::is_floating_point<typename Tgt::rep>::value, "incorrect usage");
345 static_assert(
346 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
347
348 // We expect floating point types to have much a wider representable range
349 // than integer types, so we don't bother actually checking the input
350 // integer value here.
351 static_assert(
352 std::numeric_limits<typename Tgt::rep>::max() >=
353 std::numeric_limits<Seconds>::max(),
354 "unusually limited floating point type");
355 static_assert(
356 std::numeric_limits<typename Tgt::rep>::lowest() <=
357 std::numeric_limits<Seconds>::lowest(),
358 "unusually limited floating point type");
359
360 return ConversionCode::SUCCESS;
361 }
362};
363
364/**
365 * Convert a timeval or a timespec to a std::chrono::duration with second
366 * granularity.
367 *
368 * The SubsecondRatio template parameter specifies what type of subseconds to
369 * return. This must have a numerator of 1.
370 *
371 * The input must be in normalized form: the subseconds field must be greater
372 * than or equal to 0, and less than SubsecondRatio::den (i.e., less than 1
373 * second).
374 */
375template <
376 typename SubsecondRatio,
377 typename Seconds,
378 typename Subseconds,
379 typename Rep>
380auto posixTimeToDuration(
381 Seconds seconds,
382 Subseconds subseconds,
383 std::chrono::duration<Rep, std::ratio<1, 1>> dummy)
384 -> Expected<decltype(dummy), ConversionCode> {
385 using Tgt = decltype(dummy);
386 static_assert(Tgt::period::num == 1, "special case expecting num==1");
387 static_assert(Tgt::period::den == 1, "special case expecting den==1");
388 static_assert(
389 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
390
391 auto outputSeconds = tryTo<typename Tgt::rep>(seconds);
392 if (outputSeconds.hasError()) {
393 return makeUnexpected(outputSeconds.error());
394 }
395
396 if (std::is_floating_point<typename Tgt::rep>::value) {
397 return Tgt{typename Tgt::rep(seconds) +
398 (typename Tgt::rep(subseconds) / SubsecondRatio::den)};
399 }
400
401 // If the value is negative, we have to round up a non-zero subseconds value
402 if (UNLIKELY(outputSeconds.value() < 0) && subseconds > 0) {
403 if (UNLIKELY(
404 outputSeconds.value() ==
405 std::numeric_limits<typename Tgt::rep>::lowest())) {
406 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
407 }
408 return Tgt{outputSeconds.value() + 1};
409 }
410
411 return Tgt{outputSeconds.value()};
412}
413
414/**
415 * Convert a timeval or a timespec to a std::chrono::duration with subsecond
416 * granularity
417 */
418template <
419 typename SubsecondRatio,
420 typename Seconds,
421 typename Subseconds,
422 typename Rep,
423 std::intmax_t Denominator>
424auto posixTimeToDuration(
425 Seconds seconds,
426 Subseconds subseconds,
427 std::chrono::duration<Rep, std::ratio<1, Denominator>> dummy)
428 -> Expected<decltype(dummy), ConversionCode> {
429 using Tgt = decltype(dummy);
430 static_assert(Tgt::period::num == 1, "special case expecting num==1");
431 static_assert(Tgt::period::den != 1, "special case expecting den!=1");
432 static_assert(
433 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
434
435 auto errorCode = detail::CheckOverflowToDuration<
436 std::is_floating_point<typename Tgt::rep>::value>::
437 template check<Tgt, SubsecondRatio>(seconds, subseconds);
438 if (errorCode != ConversionCode::SUCCESS) {
439 return makeUnexpected(errorCode);
440 }
441
442 if (LIKELY(seconds >= 0)) {
443 return std::chrono::duration_cast<Tgt>(
444 std::chrono::duration<typename Tgt::rep>{seconds}) +
445 std::chrono::duration_cast<Tgt>(
446 std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
447 subseconds});
448 } else {
449 // For negative numbers we have to round subseconds up towards zero, even
450 // though it is a positive value, since the overall value is negative.
451 return std::chrono::duration_cast<Tgt>(
452 std::chrono::duration<typename Tgt::rep>{seconds + 1}) -
453 std::chrono::duration_cast<Tgt>(
454 std::chrono::duration<typename Tgt::rep, SubsecondRatio>{
455 SubsecondRatio::den - subseconds});
456 }
457}
458
459/**
460 * Convert a timeval or a timespec to a std::chrono::duration with
461 * granularity coarser than 1 second.
462 */
463template <
464 typename SubsecondRatio,
465 typename Seconds,
466 typename Subseconds,
467 typename Rep,
468 std::intmax_t Numerator>
469auto posixTimeToDuration(
470 Seconds seconds,
471 Subseconds subseconds,
472 std::chrono::duration<Rep, std::ratio<Numerator, 1>> dummy)
473 -> Expected<decltype(dummy), ConversionCode> {
474 using Tgt = decltype(dummy);
475 static_assert(Tgt::period::num != 1, "special case expecting num!=1");
476 static_assert(Tgt::period::den == 1, "special case expecting den==1");
477 static_assert(
478 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
479
480 if (UNLIKELY(seconds < 0) && subseconds > 0) {
481 // Increment seconds by one to handle truncation of negative numbers
482 // properly.
483 if (UNLIKELY(seconds == std::numeric_limits<Seconds>::lowest())) {
484 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
485 }
486 seconds += 1;
487 }
488
489 if (std::is_floating_point<typename Tgt::rep>::value) {
490 // Convert to the floating point type before performing the division
491 return Tgt{static_cast<typename Tgt::rep>(seconds) / Tgt::period::num};
492 } else {
493 // Perform the division as an integer, and check that the result fits in
494 // the output integer type
495 auto outputValue = (seconds / Tgt::period::num);
496 auto expectedOuput = tryTo<typename Tgt::rep>(outputValue);
497 if (expectedOuput.hasError()) {
498 return makeUnexpected(expectedOuput.error());
499 }
500
501 return Tgt{expectedOuput.value()};
502 }
503}
504
505/**
506 * Convert a timeval or timespec to a std::chrono::duration
507 *
508 * This overload is only used for unusual durations where neither the numerator
509 * nor denominator are 1.
510 */
511template <
512 typename SubsecondRatio,
513 typename Seconds,
514 typename Subseconds,
515 typename Rep,
516 std::intmax_t Denominator,
517 std::intmax_t Numerator>
518auto posixTimeToDuration(
519 Seconds seconds,
520 Subseconds subseconds,
521 std::chrono::duration<Rep, std::ratio<Numerator, Denominator>> dummy)
522 -> Expected<decltype(dummy), ConversionCode> {
523 using Tgt = decltype(dummy);
524 static_assert(
525 Tgt::period::num != 1, "should use special-case code when num==1");
526 static_assert(
527 Tgt::period::den != 1, "should use special-case code when den==1");
528 static_assert(
529 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
530
531 // Cast through an intermediate type with subsecond granularity.
532 // Note that this could fail due to overflow during the initial conversion
533 // even if the result is representable in the output POSIX-style types.
534 //
535 // Note that for integer type conversions going through this intermediate
536 // type can result in slight imprecision due to truncating the intermediate
537 // calculation to an integer.
538 using IntermediateType =
539 IntermediateDuration<typename Tgt::rep, typename Tgt::period>;
540 auto intermediate = posixTimeToDuration<SubsecondRatio>(
541 seconds, subseconds, IntermediateType{});
542 if (intermediate.hasError()) {
543 return makeUnexpected(intermediate.error());
544 }
545 // Now convert back to the target duration. Use tryTo() to confirm that the
546 // result fits in the target representation type.
547 return tryTo<typename Tgt::rep>(
548 intermediate.value().count() / Tgt::period::num)
549 .then([](typename Tgt::rep tgt) { return Tgt{tgt}; });
550}
551
552template <
553 typename Tgt,
554 typename SubsecondRatio,
555 typename Seconds,
556 typename Subseconds>
557Expected<Tgt, ConversionCode> tryPosixTimeToDuration(
558 Seconds seconds,
559 Subseconds subseconds) {
560 static_assert(
561 SubsecondRatio::num == 1, "subsecond numerator should always be 1");
562
563 // Normalize the input if required
564 if (UNLIKELY(subseconds < 0)) {
565 const auto overflowSeconds = (subseconds / SubsecondRatio::den);
566 const auto remainder = (subseconds % SubsecondRatio::den);
567 if (std::numeric_limits<Seconds>::lowest() + 1 - overflowSeconds >
568 seconds) {
569 return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
570 }
571 seconds = seconds - 1 + overflowSeconds;
572 subseconds = remainder + SubsecondRatio::den;
573 } else if (UNLIKELY(subseconds >= SubsecondRatio::den)) {
574 const auto overflowSeconds = (subseconds / SubsecondRatio::den);
575 const auto remainder = (subseconds % SubsecondRatio::den);
576 if (std::numeric_limits<Seconds>::max() - overflowSeconds < seconds) {
577 return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
578 }
579 seconds += overflowSeconds;
580 subseconds = remainder;
581 }
582
583 return posixTimeToDuration<SubsecondRatio>(seconds, subseconds, Tgt{});
584}
585
586} // namespace detail
587
588/**
589 * struct timespec to std::chrono::duration
590 */
591template <typename Tgt>
592typename std::enable_if<
593 detail::is_duration<Tgt>::value,
594 Expected<Tgt, ConversionCode>>::type
595tryTo(const struct timespec& ts) {
596 return detail::tryPosixTimeToDuration<Tgt, std::nano>(ts.tv_sec, ts.tv_nsec);
597}
598
599/**
600 * struct timeval to std::chrono::duration
601 */
602template <typename Tgt>
603typename std::enable_if<
604 detail::is_duration<Tgt>::value,
605 Expected<Tgt, ConversionCode>>::type
606tryTo(const struct timeval& tv) {
607 return detail::tryPosixTimeToDuration<Tgt, std::micro>(tv.tv_sec, tv.tv_usec);
608}
609
610/**
611 * timespec or timeval to std::chrono::time_point
612 */
613template <typename Tgt, typename Src>
614typename std::enable_if<
615 detail::is_time_point<Tgt>::value && detail::is_posix_time_type<Src>::value,
616 Expected<Tgt, ConversionCode>>::type
617tryTo(const Src& value) {
618 return tryTo<typename Tgt::duration>(value).then(
619 [](typename Tgt::duration result) { return Tgt(result); });
620}
621
622/**
623 * std::chrono::duration to struct timespec
624 */
625template <typename Tgt, typename Rep, typename Period>
626typename std::enable_if<
627 std::is_same<Tgt, struct timespec>::value,
628 Expected<Tgt, ConversionCode>>::type
629tryTo(const std::chrono::duration<Rep, Period>& duration) {
630 auto result = detail::durationToPosixTime<std::nano>(duration);
631 if (result.hasError()) {
632 return makeUnexpected(result.error());
633 }
634
635 struct timespec ts;
636 ts.tv_sec = result.value().first;
637 ts.tv_nsec = result.value().second;
638 return ts;
639}
640
641/**
642 * std::chrono::duration to struct timeval
643 */
644template <typename Tgt, typename Rep, typename Period>
645typename std::enable_if<
646 std::is_same<Tgt, struct timeval>::value,
647 Expected<Tgt, ConversionCode>>::type
648tryTo(const std::chrono::duration<Rep, Period>& duration) {
649 auto result = detail::durationToPosixTime<std::micro>(duration);
650 if (result.hasError()) {
651 return makeUnexpected(result.error());
652 }
653
654 struct timeval tv;
655 tv.tv_sec = result.value().first;
656 tv.tv_usec = result.value().second;
657 return tv;
658}
659
660/**
661 * std::chrono::time_point to timespec or timeval
662 */
663template <typename Tgt, typename Clock, typename Duration>
664typename std::enable_if<
665 detail::is_posix_time_type<Tgt>::value,
666 Expected<Tgt, ConversionCode>>::type
667tryTo(const std::chrono::time_point<Clock, Duration>& timePoint) {
668 return tryTo<Tgt>(timePoint.time_since_epoch());
669}
670
671/**
672 * For all chrono conversions, to() wraps tryTo()
673 */
674template <typename Tgt, typename Src>
675typename std::enable_if<detail::is_chrono_conversion<Tgt, Src>::value, Tgt>::
676 type
677 to(const Src& value) {
678 return tryTo<Tgt>(value).thenOrThrow(
679 [](Tgt res) { return res; },
680 [&](ConversionCode e) { return makeConversionError(e, StringPiece{}); });
681}
682
683} // namespace folly
684