diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index 9ccb211c5abbb2..62e5a0ca89f582 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -80,7 +80,9 @@ API Changes - Removed the nonstandard methods ``std::chrono::file_clock::to_time_t`` and ``std::chrono::file_clock::from_time_t``; neither libstdc++ nor MSVC STL - had such methods. + had such methods. Instead, in C++20, you can use ``std::chrono::file_clock::from_sys`` + and ``std::chrono::file_clock::to_sys``, which are specified in the Standard. + If you are not using C++20, you should move to it. - The declarations of functions ``declare_reachable``, ``undeclare_reachable``, ``declare_no_pointers``, ``undeclare_no_pointers``, and ``get_pointer_safety`` have been removed not only from C++2b but diff --git a/libcxx/include/chrono b/libcxx/include/chrono index ec510a99b5831a..f703d6cf0dc3f1 100644 --- a/libcxx/include/chrono +++ b/libcxx/include/chrono @@ -276,7 +276,23 @@ template using sys_seconds = sys_time; // C++20 using sys_days = sys_time; // C++20 -class file_clock; // C++20 +class file_clock // C++20 +{ +public: + typedef see-below rep; + typedef nano period; + typedef chrono::duration duration; + typedef chrono::time_point time_point; + static constexpr bool is_steady = false; + + static time_point now() noexcept; + + template + static sys_time to_sys(const file_time&); + + template + static file_time from_sys(const sys_time&); +}; template using file_time = time_point; // C++20 @@ -2798,6 +2814,20 @@ struct _FilesystemClock { static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false; _LIBCPP_AVAILABILITY_FILESYSTEM _LIBCPP_FUNC_VIS static time_point now() noexcept; + +#if _LIBCPP_STD_VER > 17 + template + _LIBCPP_HIDE_FROM_ABI + static chrono::sys_time<_Duration> to_sys(const chrono::file_time<_Duration>& __t) { + return chrono::sys_time<_Duration>(__t.time_since_epoch()); + } + + template + _LIBCPP_HIDE_FROM_ABI + static chrono::file_time<_Duration> from_sys(const chrono::sys_time<_Duration>& __t) { + return chrono::file_time<_Duration>(__t.time_since_epoch()); + } +#endif // _LIBCPP_STD_VER > 17 }; _LIBCPP_END_NAMESPACE_FILESYSTEM #endif // !_LIBCPP_CXX03_LANG diff --git a/libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp b/libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp new file mode 100644 index 00000000000000..d8fecd93d731cc --- /dev/null +++ b/libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-filesystem-library + +// Filesystem is supported on Apple platforms starting with macosx10.15. +// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14}} + +// TODO(ldionne): This test fails on Ubuntu Focal on our CI nodes (and only there), in 32 bit mode. +// UNSUPPORTED: linux && 32bits-on-64bits + +// +// +// file_clock +// +// template +// static sys_time to_sys(const file_time&); +// +// template +// static file_time from_sys(const sys_time&); + +#include +#include + +int main(int, char**) { + // Test round-trip through the system clock, starting from file_clock::now() + { + std::chrono::file_clock::time_point const ft = std::chrono::file_clock::now(); + auto st = std::chrono::file_clock::to_sys(ft); + assert(ft == std::chrono::file_clock::from_sys(st)); + } + + // Test round-trip through the system clock, starting from system_clock::now() + { + std::chrono::system_clock::time_point const st = std::chrono::system_clock::now(); + auto ft = std::chrono::file_clock::from_sys(st); + assert(st == std::chrono::file_clock::to_sys(ft)); + } + + // Make sure the value we get is in the ballpark of something reasonable + { + std::chrono::file_clock::time_point const file_now = std::chrono::file_clock::now(); + std::chrono::system_clock::time_point const sys_now = std::chrono::system_clock::now(); + { + auto diff = sys_now - std::chrono::file_clock::to_sys(file_now); + assert(std::chrono::milliseconds(-500) < diff && diff < std::chrono::milliseconds(500)); + } + { + auto diff = std::chrono::file_clock::from_sys(sys_now) - file_now; + assert(std::chrono::milliseconds(-500) < diff && diff < std::chrono::milliseconds(500)); + } + } + + // Make sure to_sys and from_sys are consistent with each other + { + std::chrono::file_clock::time_point const ft = std::chrono::file_clock::now(); + std::chrono::system_clock::time_point const st = std::chrono::system_clock::now(); + auto sys_diff = std::chrono::file_clock::to_sys(ft) - st; + auto file_diff = ft - std::chrono::file_clock::from_sys(st); + assert(sys_diff == file_diff); + } + + return 0; +}