7

After running this program
(compiled with MSVC compiler 19.50.35723 with option /std:c++23preview)

#include <print>
#include <chrono>
#include <string>
int main() {
    using namespace std::chrono;
    system_clock::time_point tp1;
    system_clock::time_point tp2;

    std::string y1 = "01.01.2024";
    std::string y2 = "01.01.2025";
    
    std::istringstream is1{ y1.data() };
    is1 >> parse("%d.%m.%Y", tp1);
    std::istringstream is2{ y2.data() };
    is2 >> parse("%d.%m.%Y", tp2);

    std::println("{}", tp1);
    std::println("{}", tp2);

    auto duration = duration_cast<years>(tp2 - tp1);
    std::println("duration: {} year(s)", duration);

    return 0;
}

I got the following result:

2024-01-01 00:00:00.0000000
2025-01-01 00:00:00.0000000
duration: 1[31556952]s year(s)

I was expecting a duration of exactly 1 year without fractional seconds, can someone help me out here?

7
  • 1
    The result is 1 (as it has been rounded down) - the [31556952]s is the unit. Use duration.count() if you don't want that printed. Commented yesterday
  • Format strings are documented here, but it seams it doesn't work for year specific parts like %Y: godbolt.org/z/jfsxYeaqj It works for %T. Commented yesterday
  • 1
    I've missed that table is split and year specifiers are in "invalid part": The following specifiers are recognized, but will cause std::format_error to be thrown: Commented yesterday
  • 2
    Yes, that's expected. From beginning of 2025 to beginning of 2026 is less than 31556952 seconds; rounding down gives 0. You perhaps want to convert to floating-point year duration? Commented yesterday
  • 1
    Your question performs chronological arithmetic, but also hints that you may desire calendrical arithmetic. In <chrono> you can do either. Chronological arithmetic operates on fixed units of time. Calendrical arithmetic follows the irregularity of calendars. See this SO Q/A for more details: stackoverflow.com/q/43010362/576911. This concentrates on months arithmetic but the same analogous behavior is also true for years. Commented yesterday

4 Answers 4

12

It seems from comments that you want to get a floating-point number of years. std::chrono::years is an integer number of years. To get a floating-point value, we need a custom duration:

    using float_years = duration<float, years::period>;
    auto duration = float_years{tp2 - tp1};
    std::println("duration: {:%Q} year(s)", duration);

That yields

duration: 1.0020739 year(s)

Not exactly one year, because a leap year is about ¾ day longer than an average year (and non-leap years are about ¼ day shorter):

years is equal to 365.2425 days (the average length of a Gregorian year). months is equal to 30.436875 days (exactly 1/12 of years).
-- cppreference

Sign up to request clarification or add additional context in comments.

Comments

9

I was expecting a duration of exactly 1 year without fractional seconds,

While {:%Q} could work, it is extracting the internal count() from a duration, which is dangerous and usually unnecessary with std::chrono types. If a code change alters the duration's period, you will start getting incorrect values.

The following will give you a year count regardless of the internal representation of your duration.

The code is also smaller and arguably clearer.

    auto duration = tp2 - tp1;
    std::println("duration: {} year(s)", duration / years{1});

The lesson: dividing two durations gives you a correct count without needing to know (or duration_cast) either duration's representation.

See it work.

2 Comments

Interestingly, there's a difference between how these format floating point durations: godbolt.org/z/nWfq1PG5v
@Caleth yes — matching the behavior of C++ internal types, if either operand of a division is floating point, the result will be floating point. You can certainly leverage that to get the behavior that you want.
7

You can use the %Q conversion specifier.

std::println("duration: {:%Q} year(s)", duration);

As the comments point out, [31556952]s is the units suffix for std::chrono::years.

Comments

1

duration_cast returns a duration object rather than a raw numeric value. The number shown in brackets represents the number of seconds in one year. The quick solution for your case is to call the count() member function of the duration class. For reference: https://en.cppreference.com/w/cpp/chrono/duration/count.html

duration: 1[31556952]s year(s)
// Source - https://stackoverflow.com/q/79879480
// Posted by Angle.Bracket, modified by community. See post 'Timeline' for change history
// Retrieved 2026-01-31, License - CC BY-SA 4.0

#include <print>
#include <chrono>
#include <string>
int main() {
    using namespace std::chrono;
    system_clock::time_point tp1;
    system_clock::time_point tp2;

    std::string y1 = "01.01.2024";
    std::string y2 = "01.01.2025";
    
    std::istringstream is1{ y1.data() };
    is1 >> parse("%d.%m.%Y", tp1);
    std::istringstream is2{ y2.data() };
    is2 >> parse("%d.%m.%Y", tp2);

    std::println("{}", tp1); // 2024-01-01 00:00:00.000000000 
    std::println("{}", tp2); // 2025-01-01 00:00:00.000000000 

    auto duration = duration_cast<years>(tp2 - tp1).count(); // NOTE: Modified here
    std::println("duration: {} year(s)", duration); // duration: 1 year(s) 

    return 0;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.