// file : build/timestamp.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include #include // stat #include // stat #include // stat #include // localtime, gmtime, strftime #include #include using namespace std; namespace build { // Figuring out whether we have the nanoseconds in some form. // template constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) { return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris). } template constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) { return s->st_mtimespec.tv_nsec; // MacOS X. } template constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) { return s->st_mtime_n; // AIX 5.2 and later. } template constexpr int nsec (...) {return 0;} timestamp path_mtime (const path& p) { struct stat s; if (stat (p.string ().c_str (), &s) != 0) { if (errno == ENOENT || errno == ENOTDIR) return timestamp_nonexistent; else throw system_error (errno, system_category ()); } return system_clock::from_time_t (s.st_mtime) + chrono::duration_cast ( chrono::nanoseconds (nsec (&s))); } ostream& operator<< (ostream& os, const timestamp& ts) { // @@ replace with put_time() // time_t t (system_clock::to_time_t (ts)); if (t == 0) return os << ""; std::tm tm; if (localtime_r (&t, &tm) == nullptr) throw system_error (errno, system_category ()); // If year is greater than 9999, we will overflow. // char buf[20]; // YYYY-MM-DD HH:MM:SS\0 if (strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S", &tm) == 0) return os << ""; os << buf; using namespace chrono; timestamp sec (system_clock::from_time_t (t)); nanoseconds ns (duration_cast (ts - sec)); if (ns != nanoseconds::zero ()) { os << '.'; os.width (9); os.fill ('0'); os << ns.count (); } return os; } ostream& operator<< (ostream& os, const duration& d) { // @@ replace with put_time() // timestamp ts; // Epoch. ts += d; time_t t (system_clock::to_time_t (ts)); const char* fmt (nullptr); const char* unt ("nanoseconds"); if (t >= 365 * 12 * 24 * 60 * 60) { fmt = "%Y-%m-%d %H:%M:%S"; unt = "years"; } else if (t >= 12 * 24 * 60* 60) { fmt = "%m-%d %H:%M:%S"; unt = "months"; } else if (t >= 24 * 60* 60) { fmt = "%d %H:%M:%S"; unt = "days"; } else if (t >= 60 * 60) { fmt = "%H:%M:%S"; unt = "hours"; } else if (t >= 60) { fmt = "%M:%S"; unt = "minutes"; } else if (t >= 1) { fmt = "%S"; unt = "seconds"; } if (fmt != nullptr) { std::tm tm; if (gmtime_r (&t, &tm) == nullptr) throw system_error (errno, system_category ()); char buf[20]; // YYYY-MM-DD HH:MM:SS\0 if (strftime (buf, sizeof (buf), fmt, &tm) == 0) return os << ""; os << buf; } using namespace chrono; timestamp sec (system_clock::from_time_t (t)); nanoseconds ns (duration_cast (ts - sec)); if (ns != nanoseconds::zero ()) { if (fmt != nullptr) { os << '.'; os.width (9); os.fill ('0'); } os << ns.count () << ' ' << unt; } else if (fmt == 0) os << '0'; return os; } }