Created
August 1, 2018 21:40
-
-
Save HowardHinnant/3c560d747dea6c91b4081da331f640cb to your computer and use it in GitHub Desktop.
Example implementation of filesystem::file_clock which covers the range and precision of ext4 (https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "date/tz.h" | |
#include <ostream> | |
#include <istream> | |
namespace filesystem | |
{ | |
struct file_clock | |
{ | |
using duration = std::chrono::nanoseconds; | |
using rep = duration::rep; | |
using period = duration::period; | |
using time_point = std::chrono::time_point<file_clock>; | |
static constexpr bool is_steady = false; | |
static time_point now(); | |
template<typename Duration> | |
static | |
std::chrono::time_point<std::chrono::system_clock, Duration> | |
to_sys(const std::chrono::time_point<file_clock, Duration>& t) noexcept; | |
template<typename Duration> | |
static | |
std::chrono::time_point<file_clock, Duration> | |
from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>& t) noexcept; | |
template<typename Duration> | |
static | |
std::chrono::time_point<date::local_t, Duration> | |
to_local(const std::chrono::time_point<file_clock, Duration>& t) noexcept; | |
template<typename Duration> | |
static | |
std::chrono::time_point<file_clock, Duration> | |
from_local(const std::chrono::time_point<date::local_t, Duration>& t) noexcept; | |
// private helpers | |
static | |
timespec | |
to_timespec(const time_point& t) noexcept; | |
static | |
time_point | |
from_timespec(const timespec& t) noexcept; | |
}; | |
template <class Duration> | |
using file_time = std::chrono::time_point<file_clock, Duration>; | |
using file_time_type = file_clock::time_point; | |
template <class Duration> | |
inline | |
std::chrono::time_point<std::chrono::system_clock, Duration> | |
file_clock::to_sys(const std::chrono::time_point<file_clock, Duration>& t) noexcept | |
{ | |
using namespace date; | |
return sys_time<Duration>{t.time_since_epoch()} + | |
(sys_days{2174_y/1/1} - sys_days{1970_y/1/1}); | |
} | |
template <class Duration> | |
inline | |
std::chrono::time_point<file_clock, Duration> | |
file_clock::from_sys(const std::chrono::time_point<std::chrono::system_clock, Duration>& t) noexcept | |
{ | |
using namespace date; | |
return file_time<Duration>{t.time_since_epoch()} - | |
(sys_days{2174_y/1/1} - sys_days{1970_y/1/1}); | |
} | |
template <class Duration> | |
inline | |
std::chrono::time_point<date::local_t, Duration> | |
file_clock::to_local(const std::chrono::time_point<file_clock, Duration>& t) noexcept | |
{ | |
using namespace date; | |
return local_time<Duration>{to_sys(t).time_since_epoch()}; | |
} | |
template <class Duration> | |
inline | |
std::chrono::time_point<file_clock, Duration> | |
file_clock::from_local(const std::chrono::time_point<date::local_t, Duration>& t) noexcept | |
{ | |
using namespace date; | |
return file_time<Duration>{from_sys(sys_time<Duration>{t.time_since_epoch()})}; | |
} | |
file_clock::time_point | |
file_clock::now() | |
{ | |
return from_sys(std::chrono::system_clock::now()); | |
} | |
template <class CharT, class Traits, class Duration> | |
std::basic_ostream<CharT, Traits>& | |
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, | |
const file_time<Duration>& t) | |
{ | |
using namespace std::chrono; | |
const std::string abbrev("UTC"); | |
constepxr std::chrono::seconds offset{0}; | |
using D128 = duration<__int128, typename Duration::period>; | |
return date::to_stream(os, fmt, file_clock::to_local(time_point_cast<D128>(t)), | |
&abbrev, &offset); | |
} | |
template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>> | |
std::basic_istream<CharT, Traits>& | |
from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, | |
file_time<Duration>& tp, | |
std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr, | |
std::chrono::minutes* offset = nullptr) | |
{ | |
using namespace date; | |
using namespace std::chrono; | |
using D128 = duration<__int128, typename Duration::period>; | |
local_time<D128> lp; | |
from_stream(is, fmt, lp, abbrev, offset); | |
if (!is.fail()) | |
tp = file_clock::from_local(lp); | |
return is; | |
} | |
template <class CharT, class Traits, class Duration> | |
std::basic_ostream<CharT, Traits>& | |
operator<<(std::basic_ostream<CharT, Traits>& os, const file_time<Duration>& t) | |
{ | |
const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; | |
return to_stream(os, fmt, t); | |
} | |
inline | |
timespec | |
file_clock::to_timespec(const time_point& t) noexcept | |
{ | |
using namespace date; | |
using namespace std::chrono; | |
auto tp = to_sys(time_point_cast<std::chrono::duration<__int128, std::nano>>(t)); | |
auto s = floor<seconds>(tp); | |
timespec ts; | |
ts.tv_sec = static_cast<decltype(ts.tv_sec)>(s.time_since_epoch().count()); | |
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((tp - s).count()); | |
return ts; | |
} | |
inline | |
file_clock::time_point | |
file_clock::from_timespec(const timespec& t) noexcept | |
{ | |
using namespace date; | |
using namespace std::chrono; | |
auto d = std::chrono::duration<__int128>{t.tv_sec} + nanoseconds{t.tv_nsec}; | |
return time_point_cast<duration>(from_sys(sys_time<decltype(d)>{d})); | |
} | |
} // namespace filesystem | |
#include <iostream> | |
#include <sstream> | |
int | |
main() | |
{ | |
using namespace std; | |
std::cout << filesystem::file_clock::time_point::min() << '\n'; | |
std::cout << filesystem::file_clock::now() << '\n'; | |
std::cout << filesystem::file_clock::time_point::max() << '\n'; | |
std::istringstream in{"2466-04-11 23:47:16.854775807"}; | |
filesystem::file_clock::time_point tp; | |
in >> date::parse("%F %T", tp); | |
cout << tp << '\n'; | |
in.clear(); | |
in.str("1881-09-22 00:12:43.145224192"); | |
in >> date::parse("%F %T", tp); | |
cout << tp << '\n'; | |
timespec ts = {15661036036, 854775807}; // or {-2785708037, 145224192} | |
tp = filesystem::file_clock::from_timespec(ts); | |
cout << tp << '\n'; | |
ts = filesystem::file_clock::to_timespec(tp); | |
cout << "{" << ts.tv_sec << ", " << ts.tv_nsec << "}\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example output: