_LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(file_time_type const& tm) { auto secs = duration_cast<seconds>(tm.time_since_epoch()); auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs); if (nsecs.count() < 0) { secs = secs + seconds(1); nsecs = nsecs + seconds(1); } using TLim = numeric_limits<time_t>; if (secs.count() >= 0) return secs.count() <= TLim::max(); return secs.count() >= TLim::min(); }
static bool CompareTime(file_time_type t1, file_time_type t2) { auto min_secs = duration_cast<Sec>(file_time_type::min().time_since_epoch()); bool IsMin = t1.time_since_epoch() < min_secs || t2.time_since_epoch() < min_secs; if (SupportsNanosecondRoundTrip && (!IsMin || SupportsMinRoundTrip)) return t1 == t2; if (IsMin) { return duration_cast<Sec>(t1.time_since_epoch()) == duration_cast<Sec>(t2.time_since_epoch()); } file_time_type::duration dur; if (t1 > t2) dur = t1 - t2; else dur = t2 - t1; if (WorkaroundStatTruncatesToSeconds) return duration_cast<Sec>(dur).count() == 0; return duration_cast<MicroSec>(dur).count() == 0; }
// Check if a time point is representable on a given filesystem. Check that: // (A) 'tp' is representable as a time_t // (B) 'tp' is non-negative or the filesystem supports negative times. // (C) 'tp' is not 'file_time_type::max()' or the filesystem supports the max // value. // (D) 'tp' is not 'file_time_type::min()' or the filesystem supports the min // value. inline bool TimeIsRepresentableByFilesystem(file_time_type tp) { TimeSpec ts = {}; if (!ConvertToTimeSpec(ts, tp)) return false; else if (tp.time_since_epoch().count() < 0 && !SupportsNegativeTimes) return false; else if (tp == file_time_type::max() && !SupportsMaxTime) return false; else if (tp == file_time_type::min() && !SupportsMinTime) return false; return true; }
bool ConvertToTimeSpec(TimeSpec& ts, file_time_type ft) { using SecFieldT = decltype(TimeSpec::tv_sec); using NSecFieldT = decltype(TimeSpec::tv_nsec); using SecLim = std::numeric_limits<SecFieldT>; using NSecLim = std::numeric_limits<NSecFieldT>; auto secs = duration_cast<Sec>(ft.time_since_epoch()); auto nsecs = duration_cast<NanoSec>(ft.time_since_epoch() - secs); if (nsecs.count() < 0) { if (Sec::min().count() > SecLim::min()) { secs += Sec(1); nsecs -= Sec(1); } else { nsecs = NanoSec(0); } } if (SecLim::max() < secs.count() || SecLim::min() > secs.count()) return false; if (NSecLim::max() < nsecs.count() || NSecLim::min() > nsecs.count()) return false; ts.tv_sec = secs.count(); ts.tv_nsec = nsecs.count(); return true; }
bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) { using namespace chrono; auto dur = tp.time_since_epoch(); auto sec_dur = duration_cast<seconds>(dur); auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur); // The tv_nsec and tv_usec fields must not be negative so adjust accordingly if (subsec_dur.count() < 0) { if (sec_dur.count() > min_seconds) { sec_dur -= seconds(1); subsec_dur += seconds(1); } else { subsec_dur = SubSecDurT::zero(); } } return checked_set(sec_out, sec_dur.count()) && checked_set(subsec_out, subsec_dur.count()); }
inline bool TimeIsRepresentableAsTimeT(file_time_type tp) { using namespace std::chrono; using Lim = std::numeric_limits<std::time_t>; auto sec = duration_cast<seconds>(tp.time_since_epoch()).count(); return (sec >= Lim::min() && sec <= Lim::max()); }