[英]How to consitently roundtrip with std::put_time std::get_time when the time string uses a "PM" field?
編輯:將 tmb.tm_isdst 初始化為 0
我在解析帶有“AM”/“PM”字段的日期時遇到問題。 通常,無論我使用的轉換說明符組合如何,它似乎都會忽略此字段。 有時它似乎隨機解析時間。
我正在解析的示例日期是
08/22/2020 10:16:57 PM
我正在使用"en_US.utf-8"
語言環境和以下轉換說明符字符串:
"%x %I:%M:%S %p" //ignores AM/PM
"%x %X" // hour gets a random number and minutes/seconds equal 0
"%x %r" // hour gets a random number and minutes/seconds equal 0
我試過 x86-64 GCC 5 到 10 和 x86-64 clang 3.4.1 到 10。
這是無法進行往返的示例代碼( 帶有 godbot 的實時代碼):
#include <sstream>
#include <locale>
#include <iomanip>
int main(){
std::time_t t = 1598134617;
std::tm tm = *std::localtime(&t);
std::stringstream ss;
ss.imbue(std::locale("en_US.utf-8"));
ss << std::put_time(&tm, "%x %I:%M:%S %p");
std::cout << ss.str() << std::endl;
std::tm tmb;
ss >> std::get_time(&tmb,"%x %I:%M:%S %p");
tmb.tm_isdst = 0;
std::cout << "years since 1900:\t" << tmb.tm_year << std::endl;
std::cout << "month:\t\t\t" << tmb.tm_mon << std::endl;
std::cout << "day:\t\t\t" << tmb.tm_mday << std::endl;
std::cout << "hour:\t\t\t" << tmb.tm_hour << std::endl;
std::cout << "mins:\t\t\t" << tmb.tm_min << std::endl;
std::cout << "secs:\t\t\t" << tmb.tm_sec << std::endl;
std::cout << "dst:\t\t\t" << tmb.tm_isdst << std::endl;
std::cout << "timestamp:\t\t" << (mktime(&tmb));
}
此代碼輸出錯誤的時間戳,因此由於未解析“PM”字段而導致往返失敗。
時間戳應該是1598134617; 打印 1598091417:
08/22/2020 10:16:57 PM
years since 1900: 120
month: 7
day: 22
hour: 10
mins: 16
secs: 57
dst: 0
timestamp: 1598091417
關於如何在 c++ 中一致地解析“AM”/“PM”字段有什么想法嗎?
使用 clang 時,將其添加到命令行: -stdlib=libc++
。 這使用std::get_time
和std::put_time
函數的 llvm 實現。
您已經犯下了未初始化std::tm tmb
的tm_isdst
成員的主要(和流行!)錯誤。 我不知道它在你的例子中的價值是什么,但是當我測試你的代碼時,它給了我一些看似隨機的預期值偏移,即使時間是上午。 添加tmb.tm_isdst = -1;
tmb
聲明后解決了問題。 這是因為mktime()
依賴於這個值,但std::get_time()
(和strptime()
)沒有設置它。
設置tm_isdst = -1
表示“我希望系統在提供的時間決定 DST 是否生效。” 只要時間沒有歧義(例如,在“回退”夏令時轉換期間),這種自動模式就可以完美運行。
請求當地立法者放棄 DST,請求編譯器編寫者警告使用部分初始化的struct tm
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.