- 
                Notifications
    You must be signed in to change notification settings 
- Fork 720
Open
Description
Summary
Parsing 12‑hour times with AM/PM directly into date::sys_time ignores %p: PM inputs produce the same UTC result as AM. The C++ locale facet appears correct (std::get_time handles AM/PM). Using %r instead of %I:%M:%S %p works, so this looks specific to %I…%p in date::parse/from_stream for sys_time when combined with %z/%Ez.
Minimal repro (fails with %I:%M:%S %p)
main.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <chrono>
#include <locale>
#include <date/date.h>
template <typename Dur>
void test(const std::string& s, const std::string& fmt) {
    std::istringstream in{s};
    in.imbue(std::locale("en_US.utf8")); // AM/PM facet
    date::sys_time<Dur> tp{};
    in >> date::parse(fmt.c_str(), tp);
    if (!in) {
        std::cerr << "Parse failed. fmt='" << fmt << "' input='" << s << "'\n";
        return;
    }
    std::cout << s << "  ->  " << date::format("%FT%TZ", tp) << '\n';
}
int main() {
    using seconds = std::chrono::seconds;
    test<seconds>("Sep 16, 2025 10:29:51 PM -0300",
                  "%b %d, %Y %I:%M:%S %p %z");
    test<seconds>("Sep 16, 2025 10:29:51 PM -03:00",
                  "%b %d, %Y %I:%M:%S %p %Ez");
    test<seconds>("Sep 16, 2025 10:29:51 AM -0300",
                  "%b %d, %Y %I:%M:%S %p %z");
}Actual output (incorrect)
Sep 16, 2025 10:29:51 PM -0300  ->  2025-09-16T13:29:51Z
Sep 16, 2025 10:29:51 PM -03:00  ->  2025-09-16T13:29:51Z
Sep 16, 2025 10:29:51 AM -0300  ->  2025-09-16T13:29:51Z
Expected output
Sep 16, 2025 10:29:51 PM -0300  ->  2025-09-17T01:29:51Z
Sep 16, 2025 10:29:51 PM -03:00  ->  2025-09-17T01:29:51Z
Sep 16, 2025 10:29:51 AM -0300  ->  2025-09-16T13:29:51Z
Control repro (works with %r)
main_r.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <chrono>
#include <locale>
#include <date/date.h>
template <typename Dur>
void test(const std::string& s, const std::string& fmt) {
    std::istringstream in{s};
    in.imbue(std::locale("en_US.utf8"));
    date::sys_time<Dur> tp{};
    in >> date::parse(fmt.c_str(), tp);
    if (!in) {
        std::cerr << "Parse failed. fmt='" << fmt << "' input='" << s << "'\n";
        return;
    }
    std::cout << s << "  ->  " << date::format("%FT%TZ", tp) << '\n';
}
int main() {
    using seconds = std::chrono::seconds;
    test<seconds>("Sep 16, 2025 10:29:51 PM -0300",
                  "%b %d, %Y %r %z");
    test<seconds>("Sep 16, 2025 10:29:51 PM -03:00",
                  "%b %d, %Y %r %Ez");
    test<seconds>("Sep 16, 2025 10:29:51 AM -0300",
                  "%b %d, %Y %r %z");
}Actual output (correct)
Sep 16, 2025 10:29:51 PM -0300  ->  2025-09-17T01:29:51Z
Sep 16, 2025 10:29:51 PM -03:00  ->  2025-09-17T01:29:51Z
Sep 16, 2025 10:29:51 AM -0300  ->  2025-09-16T13:29:51Z
Facet sanity check (std lib handles %p correctly)
diag.cpp
#include <locale>
#include <iomanip>
#include <sstream>
#include <ctime>
#include <iostream>
int main() {
    std::locale loc("en_US.utf8");
    // %p formats correctly
    std::ostringstream os; os.imbue(loc);
    std::tm tm{}; tm.tm_hour = 13;
    os << std::put_time(&tm, "%p");
    std::cout << "put_time(%p) for 13:00 -> '" << os.str() << "' (expect 'PM')\n";
    // get_time parses AM/PM correctly
    auto parse = [&](const char* s){
        std::tm t{}; std::istringstream is(s); is.imbue(loc);
        is >> std::get_time(&t, "%I:%M:%S %p");
        std::cout << "get_time('" << s << "') -> tm_hour=" << t.tm_hour << "\n";
    };
    parse("10:29:51 AM"); // -> 10
    parse("10:29:51 PM"); // -> 22
    parse("12:00:00 AM"); // -> 0
    parse("12:00:00 PM"); // -> 12
}Observed
put_time(%p) for 13:00 -> 'PM' (expect 'PM')
get_time('10:29:51 AM') -> tm_hour=10
get_time('10:29:51 PM') -> tm_hour=22
get_time('12:00:00 AM') -> tm_hour=0
get_time('12:00:00 PM') -> tm_hour=12
Environment
Compiler: GCC 13.3.0
$ gcc --version
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
libc: glibc 2.39
$ ldd --version
ldd (Ubuntu GLIBC 2.39-0ubuntu8.5) 2.39
Locales available (excerpt):
$ locale -a
C
C.utf8
…
en_US.utf8
…
- en_US.utf8loads successfully and is used in the tests above.
- dateversion tested: v3.0.4 (also reproducible with v3.0.1).
Notes / Workarounds
- Using %r(12‑hour time with AM/PM) instead of%I:%M:%S %pworks correctly.
- Alternatively, normalize AM/PM to 24‑hour in the input and parse with %H:%M:%S %z/%Ez.
Ask
Is %p being dropped when parsing sys_time with %I…%p along with %z/%Ez? Any fix or guidance would be appreciated.
Metadata
Metadata
Assignees
Labels
No labels