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