From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-yw1-x112d.google.com (mail-yw1-x112d.google.com [IPv6:2607:f8b0:4864:20::112d]) by sourceware.org (Postfix) with ESMTPS id F16613858C74 for ; Mon, 7 Mar 2022 07:45:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F16613858C74 Received: by mail-yw1-x112d.google.com with SMTP id 00721157ae682-2db569555d6so153450787b3.12 for ; Sun, 06 Mar 2022 23:45:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=Cl1h4GYqwTlY1AmtxEZyiWjz6lUBTEHZI+agN2bPr74=; b=4HOm4aDP2UH6I/Y6QgaVdtBGrg3y7m6w6339COWZdHGRRHzEIO19cBCCnvVxfC6qiS LX8aI//twCLqSx5dFUSIGd4+34ktOZfY3F3tkzhH5oZULc4KOpjHtDwMkD/ep/JCIEaI geXSzo1i0z8IaDlB1boC9MmPyaOEMJU6UTHbhA2+DEKKMXnwHZWg1E2kKGn5ZTyyn0+e 2P/iG6HF99MI8lBo0joMrPeSKq7nYakuJ8y84BoRqCcWsx0/NuZ4qUaEhtLmMGRW2ZhL qlZI9Uc74h5fii82wMYOO+TbimZ4vM490h7dWRLl5uH3GQWTbhOxx/9DYIAkI46Ifz+C p2yQ== X-Gm-Message-State: AOAM530SgLwY9nWd0bCOOLZKR3N3vQURNh9OPkPcyuaBXZr/wYTpRpvm icGVr8q8Tk+eJpIuEukgpt8hgXZl53InxoaMret/uzhwZ6O8Fw== X-Google-Smtp-Source: ABdhPJxQX64/1i8F0jxuy8YIsOHUyp76UyIkMOWDIbTLdgr3Tbny2xL0SsIF42vXotHU6I6lrXK2lufPbFXGbTGQlLc= X-Received: by 2002:a81:5d02:0:b0:2d1:41bb:38b1 with SMTP id r2-20020a815d02000000b002d141bb38b1mr7690613ywb.5.1646639101157; Sun, 06 Mar 2022 23:45:01 -0800 (PST) MIME-Version: 1.0 From: Markus Rathgeb Date: Mon, 7 Mar 2022 08:44:50 +0100 Message-ID: Subject: std::get_time changed To: libstdc++@gcc.gnu.org X-Spam-Status: No, score=2.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, SCC_10_SHORT_WORD_LINES, SCC_20_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.4 X-Spam-Level: ** X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org Content-Type: text/plain; charset="UTF-8" X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Mar 2022 07:45:04 -0000 Hello, I realized a changed behavior of the function "std::get_time" with respect to tm_wday and tm_yday. In older versions tm_wday and tm_yday has not been modified. In more recent version it is modified and set to the correct value (similar to strptime). IMHO the "new" behavior is more consistent but I wonder what is "correct" or expected. Having a look at https://en.cppreference.com/w/cpp/io/manip/get_time the fields tm_wday and tm_ydas are set by only a few conversion specifiers. Can you give me some details about the changed behavior and where it is documented. == Versions used == Fedora 36 rpm -qi glibc Name : glibc Version : 2.35 Release : 3.fc36 rpm -qi gcc-c++ Name : gcc-c++ Version : 12.0.1 Release : 0.9.fc36 Ubuntu Focal apt info libc6 Package: libc6 Version: 2.31-0ubuntu9 apt info g++ Package: g++ Version: 4:9.3.0-1ubuntu2 == Code Exmaple output for Ubuntu Focal and Fedora 36 == Initialize struct tm with 0x00 Ubuntu Focal - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 0, yday: 0, isdst: 0, tm_gmtoff: 0, skipped: tm_zone Ubuntu Focal - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 0, tm_gmtoff: 0, skipped: tm_zone Fedora 36 - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 0, tm_gmtoff: 0, skipped: tm_zone Fedora 36 - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 0, tm_gmtoff: 0, skipped: tm_zone Initialize struct tm with 0x01 Ubuntu Focal - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 16843009, yday: 16843009, isdst: 16843009, tm_gmtoff: 72340172838076673, skipped: tm_zone Ubuntu Focal - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 16843009, tm_gmtoff: 72340172838076673, skipped: tm_zone Fedora 36 - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 16843009, tm_gmtoff: 72340172838076673, skipped: tm_zone Fedora 36 - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: 16843009, tm_gmtoff: 72340172838076673, skipped: tm_zone Initialize struct tm with 0xFF Ubuntu Focal - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: -1, yday: -1, isdst: -1, tm_gmtoff: -1, skipped: tm_zone Ubuntu Focal - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: -1, tm_gmtoff: -1, skipped: tm_zone Fedora 36 - std::get_time | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: -1, tm_gmtoff: -1, skipped: tm_zone Fedora 36 - strptime | sec: 58, min: 24, hour: 7, mday: 16, mon: 5, year: 121, wday: 3, yday: 166, isdst: -1, tm_gmtoff: -1, skipped: tm_zone == Code Example == #include #include #include #include #include #include #include namespace { constexpr const char *k_defaultTimeFormat = "%Y-%m-%d %H:%M:%S"; bool parseGetTime(std::tm *tm, std::string time, std::string format) { std::istringstream iss(time); iss >> std::get_time(tm, format.c_str()); return !iss.fail(); } bool parseStrptime(std::tm *tm, const char *time, const char *format) { const char *rv = strptime(time, format, tm); if (rv == nullptr) { return false; } return *rv == '\0'; } void printTm(const std::tm &tm) { std::printf("sec: %d, min: %d, hour: %d, mday: %d, mon: %d, year: %d, wday: %d, yday: %d, isdst: %d, tm_gmtoff: %ld, skipped: tm_zone\n", tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, tm.tm_isdst, tm.tm_gmtoff /*, tm.tm_zone*/); } }// namespace int main() { struct tm tm; constexpr const char *timestr = "2021-06-16 07:24:58"; for (const int r: std::list{0x00, 0x01, 0xFF}) { std::memset(&tm, r, sizeof(tm)); if (parseGetTime(&tm, timestr, k_defaultTimeFormat)) { printTm(tm); } else { std::cerr << "parsing failure: get time" << std::endl; } std::memset(&tm, r, sizeof(tm)); if (parseStrptime(&tm, timestr, k_defaultTimeFormat)) { printTm(tm); } else { std::cerr << "parsing failure: strptime" << std::endl; } } return 0; }