Skip to content

<chrono>: format() %y mishandles negative year values #4248

Open
@StephanTLavavej

Description

@StephanTLavavej

Found by libcxx/test/std/time/time.syn/formatter.year.pass.cpp in the upcoming libc++ test update.

For %C, I believe MSVC's STL is correct, so I filed llvm/llvm-project#74727.

For %y, I believe MSVC's STL is bogus.

D:\GitHub\STL\out\x64>type meow.cpp
#include <cassert>
#include <chrono>
#include <format>
#include <print>
#include <string>
#include <string_view>
using namespace std;

void check(const string_view actual, const string_view correct) {
    if (actual == correct) {
        println("Got {}, pass.", actual);
    } else {
        println("Got {}, expected {}, FAIL!", actual, correct);
    }
}

int main() {
    // libcxx/test/std/time/time.syn/formatter.year.pass.cpp

    // %Y works:
    assert(format("%Y={:%Y}", -9999y) == "%Y=-9999");
    assert(format("%Y={:%Y}", -999y) == "%Y=-0999");
    assert(format("%Y={:%Y}", -99y) == "%Y=-0099");
    assert(format("%Y={:%Y}", -9y) == "%Y=-0009");

    // N4964 [tab:time.format.spec]: "%C The year divided by 100 using floored division.
    // If the result is a single decimal digit, it is prefixed with 0."
    // LLVM-74727 [libc++] Should formatting year{-99} with %C produce "-1" or "-01"?
    check(format("{:%%Y=%Y %%C=%C}", -9999y), "%Y=-9999 %C=-100");
    check(format("{:%%Y=%Y %%C=%C}", -999y), "%Y=-0999 %C=-10");
    check(format("{:%%Y=%Y %%C=%C}", -99y), "%Y=-0099 %C=-1");
    check(format("{:%%Y=%Y %%C=%C}", -9y), "%Y=-0009 %C=-1");

    println("-----");

    // [tab:time.format.spec]: "%y The last two decimal digits of the year.
    // If the result is a single digit it is prefixed by 0."
    check(format("{:%%Y=%Y %%y=%y}", -9999y), "%Y=-9999 %y=99");
    check(format("{:%%Y=%Y %%y=%y}", -999y), "%Y=-0999 %y=99");
    check(format("{:%%Y=%Y %%y=%y}", -99y), "%Y=-0099 %y=99");
    check(format("{:%%Y=%Y %%y=%y}", -9y), "%Y=-0009 %y=09");
}
D:\GitHub\STL\out\x64>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp && meow
meow.cpp
Got %Y=-9999 %C=-100, pass.
Got %Y=-0999 %C=-10, pass.
Got %Y=-0099 %C=-01, expected %Y=-0099 %C=-1, FAIL!
Got %Y=-0009 %C=-01, expected %Y=-0009 %C=-1, FAIL!
-----
Got %Y=-9999 %y=01, expected %Y=-9999 %y=99, FAIL!
Got %Y=-0999 %y=01, expected %Y=-0999 %y=99, FAIL!
Got %Y=-0099 %y=01, expected %Y=-0099 %y=99, FAIL!
Got %Y=-0009 %y=91, expected %Y=-0009 %y=09, FAIL!

Metadata

Metadata

Assignees

No one assigned

    Labels

    blocked on LWGWaiting for WG21 to tell us what to dobugSomething isn't workingchronoC++20 chronoformatC++20/23 format

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions