关于将时间戳字符串转换为 "HH:MM:SS.microseconds" 格式的建议
Advice on converting timestamp string in "HH:MM:SS.microseconds" format
我得到了一个字符串格式的时间戳列表(假设我们有一个现成的 std::vector<std::string>
)std::vector<std::string> = {"12:27:37.740002", "19:37:17.314002", "20:00:07.140902",...}
。没有日期,没有时区。将这些字符串解析为某种 C++ 类型(std::chrono::time_point
?)以便稍后能够执行一些比较和排序的更好方法是什么。
例如:比较从 "20:00:07.140902"
解析的值和从 "20:00:07.000000"
解析的值。
C++17 可以,但我不能使用任何第三方库(Boost、Date 等)。
保持微秒精度至关重要。
您可以完全使用 C++ 标准库功能构建此功能。
要解析字符串,请使用 std::regex。
对于时间相关的数据类型,使用 std::chrono
示例:
#include <stdexcept>
#include <regex>
#include <chrono>
#include <iostream>
auto parse_to_timepoint(const std::string& input)
{
// setup a regular expression to parse the input string
// https://regex101.com/
// each part between () is a group and will end up in the match
// [0-2] will match any character from 0 to 2 etc..
// [0-9]{6} will match exactly 6 digits
static const std::regex rx{ "([0-2][0-9]):([0-5][0-9]):([0-5][0-9])\.([0-9]{6})" };
std::smatch match;
if (!std::regex_search(input, match, rx))
{
throw std::invalid_argument("input string is not a valid time string");
}
// convert each matched group to the corresponding value
// note match[0] is the complete matched string by the regular expression
// we only need the groups which start at index 1
const auto& hours = std::stoul(match[1]);
const auto& minutes = std::stoul(match[2]);
const auto& seconds = std::stoul(match[3]);
const auto& microseconds = std::stoul(match[4]);
// build up a duration
std::chrono::high_resolution_clock::duration duration{};
duration += std::chrono::hours(hours);
duration += std::chrono::minutes(minutes);
duration += std::chrono::seconds(seconds);
duration += std::chrono::microseconds(microseconds);
// then return a time_point (note this will not help you with correctly handling day boundaries)
// since there is no date in the input string
return std::chrono::high_resolution_clock::time_point{ duration };
}
int main()
{
std::string input1{ "20:00:07.140902" };
std::string input2{ "20:00:07.000000" };
auto tp1 = parse_to_timepoint(input1);
auto tp2 = parse_to_timepoint(input2);
std::cout << "start time = " << ((tp1 < tp2) ? input1 : input2) << "\n";
std::cout << "end time = " << ((tp1 >= tp2) ? input1 : input2) << "\n";
return 0;
}
我不明白为什么这不起作用。使用std::chrono::from_stream
将字符串解析成一个时间点,然后比较两个时间点即可。
但是,我现在一直在使用 Visual Studio 2022 17.0.2(社区版)进行尝试,但无法将字符串解析为 tp
。
Ted Lyngmo 在 中谈到了用亚秒解析秒时的错误(已在 VS2022 17.0.3 中修复)。我不得不说,尽管他的解决方案在我的 VS2022 中对我不起作用。
无论如何,你可能想试一试。
#include <chrono>
#include <iomanip> // boolalpha
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
auto parse_string_to_tp(const std::string& str)
{
std::istringstream iss{ str };
std::chrono::sys_time<std::chrono::microseconds> tp{};
std::chrono::from_stream(iss, "%H:%M:%S", tp); // or simply "%T"
return tp;
}
int main()
{
const std::string str1{ "12:27:37.740002" };
const std::string str2{ "13:00:00.500000" };
auto tp1{ parse_string_to_tp(str1) };
auto tp2{ parse_string_to_tp(str2) };
std::cout << "tp1 < tp2: " << std::boolalpha << (tp1 < tp2) << "\n";
std::cout << "tp2 < tp1: " << std::boolalpha << (tp2 < tp1) << "\n";
}
编辑:如果您只使用持续时间而不是时间点,它会起作用:
#include <chrono>
#include <iomanip> // boolalpha
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
auto parse_string_to_duration(const std::string& str)
{
std::istringstream iss{ str };
std::chrono::microseconds d{};
std::chrono::from_stream(iss, "%T", d);
return d;
}
int main()
{
const std::string str1{ "12:27:37.740002" };
const std::string str2{ "23:39:48.500000" };
auto d1{ parse_string_to_duration(str1) };
auto d2{ parse_string_to_duration(str2) };
std::cout << "d1 < d2: " << std::boolalpha << (d1 < d2) << "\n";
std::cout << "d2 < d1: " << std::boolalpha << (d2 < d1) << "\n";
}
我得到了一个字符串格式的时间戳列表(假设我们有一个现成的 std::vector<std::string>
)std::vector<std::string> = {"12:27:37.740002", "19:37:17.314002", "20:00:07.140902",...}
。没有日期,没有时区。将这些字符串解析为某种 C++ 类型(std::chrono::time_point
?)以便稍后能够执行一些比较和排序的更好方法是什么。
例如:比较从 "20:00:07.140902"
解析的值和从 "20:00:07.000000"
解析的值。
C++17 可以,但我不能使用任何第三方库(Boost、Date 等)。 保持微秒精度至关重要。
您可以完全使用 C++ 标准库功能构建此功能。 要解析字符串,请使用 std::regex。 对于时间相关的数据类型,使用 std::chrono
示例:
#include <stdexcept>
#include <regex>
#include <chrono>
#include <iostream>
auto parse_to_timepoint(const std::string& input)
{
// setup a regular expression to parse the input string
// https://regex101.com/
// each part between () is a group and will end up in the match
// [0-2] will match any character from 0 to 2 etc..
// [0-9]{6} will match exactly 6 digits
static const std::regex rx{ "([0-2][0-9]):([0-5][0-9]):([0-5][0-9])\.([0-9]{6})" };
std::smatch match;
if (!std::regex_search(input, match, rx))
{
throw std::invalid_argument("input string is not a valid time string");
}
// convert each matched group to the corresponding value
// note match[0] is the complete matched string by the regular expression
// we only need the groups which start at index 1
const auto& hours = std::stoul(match[1]);
const auto& minutes = std::stoul(match[2]);
const auto& seconds = std::stoul(match[3]);
const auto& microseconds = std::stoul(match[4]);
// build up a duration
std::chrono::high_resolution_clock::duration duration{};
duration += std::chrono::hours(hours);
duration += std::chrono::minutes(minutes);
duration += std::chrono::seconds(seconds);
duration += std::chrono::microseconds(microseconds);
// then return a time_point (note this will not help you with correctly handling day boundaries)
// since there is no date in the input string
return std::chrono::high_resolution_clock::time_point{ duration };
}
int main()
{
std::string input1{ "20:00:07.140902" };
std::string input2{ "20:00:07.000000" };
auto tp1 = parse_to_timepoint(input1);
auto tp2 = parse_to_timepoint(input2);
std::cout << "start time = " << ((tp1 < tp2) ? input1 : input2) << "\n";
std::cout << "end time = " << ((tp1 >= tp2) ? input1 : input2) << "\n";
return 0;
}
我不明白为什么这不起作用。使用std::chrono::from_stream
将字符串解析成一个时间点,然后比较两个时间点即可。
但是,我现在一直在使用 Visual Studio 2022 17.0.2(社区版)进行尝试,但无法将字符串解析为 tp
。
Ted Lyngmo 在
无论如何,你可能想试一试。
#include <chrono>
#include <iomanip> // boolalpha
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
auto parse_string_to_tp(const std::string& str)
{
std::istringstream iss{ str };
std::chrono::sys_time<std::chrono::microseconds> tp{};
std::chrono::from_stream(iss, "%H:%M:%S", tp); // or simply "%T"
return tp;
}
int main()
{
const std::string str1{ "12:27:37.740002" };
const std::string str2{ "13:00:00.500000" };
auto tp1{ parse_string_to_tp(str1) };
auto tp2{ parse_string_to_tp(str2) };
std::cout << "tp1 < tp2: " << std::boolalpha << (tp1 < tp2) << "\n";
std::cout << "tp2 < tp1: " << std::boolalpha << (tp2 < tp1) << "\n";
}
编辑:如果您只使用持续时间而不是时间点,它会起作用:
#include <chrono>
#include <iomanip> // boolalpha
#include <iostream> // cout
#include <sstream> // istringstream
#include <string>
auto parse_string_to_duration(const std::string& str)
{
std::istringstream iss{ str };
std::chrono::microseconds d{};
std::chrono::from_stream(iss, "%T", d);
return d;
}
int main()
{
const std::string str1{ "12:27:37.740002" };
const std::string str2{ "23:39:48.500000" };
auto d1{ parse_string_to_duration(str1) };
auto d2{ parse_string_to_duration(str2) };
std::cout << "d1 < d2: " << std::boolalpha << (d1 < d2) << "\n";
std::cout << "d2 < d1: " << std::boolalpha << (d2 < d1) << "\n";
}