C++17でファイルのタイムスタンプを取得する

c++17においてstd::filesystemが追加され、boostに頼らなくてもよくなったので使ってみた。boost::filesystemはコンパイルが必要なので、標準になったのはいいものの糞仕様にはまったので、メモ。
環境はMicrosoft Visual Studio Community 2019 Version 16.7.5

  • utils.h
#pragma once

#include <chrono>
#include <filesystem>
#include <string>

// std::filesystem::file_time_typeのtime_since_epoch()を調整するバイアス。
extern const std::chrono::system_clock::time_point gEpochTimeBias;
std::string timestamp(const std::filesystem::path& path, const std::string& fmt = "%Y-%m-%d %H:%M:%S");
  • utils.cpp
#include <sstream>

#include "utils.h"

using namespace std;

// std::filesystem::file_time_typeのtime_since_epoch()が369年ずれるので、調整するバイアス。
// c++20になれば解決しているといいね。
const chrono::system_clock::time_point gEpochTimeBias = chrono::time_point_cast<chrono::system_clock::duration>(
	chrono::system_clock::now() - filesystem::file_time_type::clock::now().time_since_epoch());

string timestamp(const filesystem::path& path, const string& fmt)
{
	filesystem::file_time_type time_ftt = filesystem::last_write_time(path);
	chrono::time_point sctp = chrono::time_point_cast<chrono::system_clock::duration>(time_ftt.time_since_epoch() + gEpochTimeBias);
	const time_t time_tt = chrono::system_clock::to_time_t(sctp);

	struct tm time_tm;
	localtime_s(&time_tm, &time_tt);

	stringstream ss;
	ss << put_time(&time_tm, fmt.c_str());

	return ss.str();
}
  • main.cpp
#include <iostream>

#include "utils.h"

using namespace std;

int main()
{
	string path = "utils.h";
	string time_tm = timestamp(path);
	cout <<  time_tm << endl;
}