5

I'm looking for a way to print out milliseconds in this format using C++:

cout << hours << " Hours : " << minutes << " Minutes : " << seconds << " Seconds : " << milliseconds << " Milliseconds" << endl;

I know there are a ton of duplicate questions about this. But none of them really handle how to get the remainder in milliseconds. There are a few that do this using Java, but I want a solution in C++.

Edit:

I wanted to clarify the question. I'm looking to take a time value that I get for the time it takes a program to run and print out that time in a legible format for the user. Getting the standard hr:min:sec was straight forward. But including any remaining milliseconds was tripping me up.

Berkyjay
  • 147
  • 1
  • 1
  • 9
  • So your trouble is getting the milliseconds? Would this be a duplicate then? https://stackoverflow.com/q/19555121/2602718 – scohe001 Jun 06 '18 at 18:36
  • All of the ton of duplicates will exhibit a pattern to get from bigger to lower and lower units. Extrapolate and apply to your question. – Yunnosch Jun 06 '18 at 18:36
  • Could you link a duplicate and explain why it's not applicable? It's not clear what your special requirements are. – François Andrieux Jun 06 '18 at 18:36
  • 1
    Hint: 1000ms = 1s; 60s = 1min; 60min = 1h. The rest is math and it shouldn't matter whether you only have an example in Java (your c++ line seems valid so far) – Tom Mekken Jun 06 '18 at 18:47

7 Answers7

17
std::string format_duration( std::chrono::milliseconds ms ) {
    using namespace std::chrono;
    auto secs = duration_cast<seconds>(ms);
    ms -= duration_cast<milliseconds>(secs);
    auto mins = duration_cast<minutes>(secs);
    secs -= duration_cast<seconds>(mins);
    auto hour = duration_cast<hours>(mins);
    mins -= duration_cast<minutes>(hour);

    std::stringstream ss;
    ss << hour.count() << " Hours : " << mins.count() << " Minutes : " << secs.count() << " Seconds : " << ms.count() << " Milliseconds";
    return ss.str();
}

live example.

Extending this to days/years/etc should be easy (there isn't a predefined std::chrono duration type for days/years/etc prior to however).

But I can do better.

template<class Duration>
struct split_duration {
  Duration d;
  std::chrono::milliseconds leftover;

  split_duration( std::chrono::milliseconds ms ):
    d( std::chrono::duration_cast<Duration>(ms) ),
    leftover( ms - std::chrono::duration_cast<std::chrono::milliseconds>(d) )
  {}
};


template<class...Durations>
std::tuple<Durations...> durations( std::chrono::milliseconds ms ) {
  std::tuple<std::optional<split_duration<Durations>>...> tmp;
  ( (void)(
       (void)std::get<std::optional<split_duration<Durations>>>(tmp).emplace( ms ),
       ms = std::get<std::optional<split_duration<Durations>>>(tmp)->leftover
     ), ...
  );
  return std::make_tuple( std::get<std::optional<split_duration<Durations>>>( tmp )->d... );
}

template<class T>
struct tag_t {};
template<class T>
constexpr tag_t<T> tag = {};

inline std::string duration_name( tag_t<std::chrono::milliseconds> ) { return "ms"; }
inline std::string duration_name( tag_t<std::chrono::seconds> ) { return "Seconds"; }
inline std::string duration_name( tag_t<std::chrono::minutes> ) { return "Minutes"; }
inline std::string duration_name( tag_t<std::chrono::hours> ) { return "Hours"; }
// inline std::string duration_name( tag_t<std::chrono::days> ) { return "Days"; }
// inline std::string duration_name( tag_t<std::chrono::years> ) { return "Years"; }

template<class...Durations>
std::string format_duration( std::chrono::milliseconds ms ) {
    auto split = durations<Durations...>(ms);

    std::stringstream ss;

    (
        (void)( ss << duration_name(tag<Durations>) << ": " << std::get<Durations>(split).count() << " " ), ...
    );

    return ss.str();
}

Days/Years requires , everything else is .

You just call format_durations<Durations...>( some_ms ) and out comes a formatted string based off the Durations.... You do have to do it from most-to-least significant.

durations<Durations...> gives you a tuple breakdown of the time that has to be most-to-least; you could then reorder that before formatting if you chose.

Duplicate duration types leads to compile time errors, as std::get dies a horrible ambiguous death.

Live example.

Yakk - Adam Nevraumont
  • 250,370
  • 26
  • 305
  • 497
6

Maybe you're looking for something like this:

#include <iostream>
using namespace std;

int main() {
//Value chosen to be 1 hour, 1 minute, 1 second, and 1 millisecond
long milli = 3661001;
//3600000 milliseconds in an hour
long hr = milli / 3600000;
milli = milli - 3600000 * hr;
//60000 milliseconds in a minute
long min = milli / 60000;
milli = milli - 60000 * min;

//1000 milliseconds in a second
long sec = milli / 1000;
milli = milli - 1000 * sec;


cout << hr << " hours and " << min << " minutes and " << sec << " seconds and " << milli << " milliseconds." << endl;
}
Jsqsh
  • 110
  • 1
  • 7
6
int milliseconds = ...;

int seconds = milliseconds / 1000;
milliseconds %= 1000;

int minutes = seconds / 60;
seconds %= 60;

int hours = minutes / 60;
minutes %= 60;

cout << hours << " Hours : " << minutes << " Minutes : " << seconds << " Seconds : " << milliseconds << " Milliseconds" << endl;
Remy Lebeau
  • 505,946
  • 29
  • 409
  • 696
  • I don't think this is correct because seconds will be ALL the ms converted to seconds, not the reminding seconds in a time format such as HH:MM:SS.mmm (how many hours, minutes, seconds and milliseconds are this tick counter). – Max Kielland Aug 23 '21 at 11:39
  • @MaxKielland did you even try it? [It works just fine](https://ideone.com/8mZgHR). Perhaps you don't understand how the `%=` operator works? `milliseconds` is converted to whole `seconds` and then the remainder is saved back to `milliseconds`. Then `seconds` is converted to whole `minutes` and the remainder is saved back to `seconds`. Then `minutes` is converted to whole `hours` and the remainder is saved back to `minutes`. – Remy Lebeau Aug 23 '21 at 14:00
  • Yes I do understand modulo (%), I just missed that line (for some unknown reason). – Max Kielland Aug 25 '21 at 08:15
0

Not exactly what you're looking for, but if you're only accessing the current time, this will work:

#include <chrono>

auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch());
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ms);
ms -= seconds;

You can then add ms.count() to your cout, even if it isn't the actual remainder of the time you originally look at.

Edit: This method should be faster than using a modulus.

L. Kue
  • 463
  • 4
  • 16
0
// Online IDE - Code Editor, Compiler, Interpreter

#include <stdio.h>
#include <stdint.h>

uint32_t DAYS_IN_MILLISECONDS = 86400000;
uint32_t HOURS_IN_MILLISECONDS = 3600000;
uint16_t MINUTES_IN_MILLISECONDS = 60000;
uint16_t SECONDS_IN_MILLISECONDS = 1000;

int main()
{
    uint32_t total_milliseconds = 23*60*60000 + 100 + 1000;
    uint8_t days = total_milliseconds / DAYS_IN_MILLISECONDS;
    uint8_t hours = (total_milliseconds - days*DAYS_IN_MILLISECONDS) / HOURS_IN_MILLISECONDS;
    uint8_t minutes = (total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS) / MINUTES_IN_MILLISECONDS;
    uint8_t seconds = (total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS - minutes*MINUTES_IN_MILLISECONDS) / SECONDS_IN_MILLISECONDS;
    uint8_t milliseconds = total_milliseconds - days*DAYS_IN_MILLISECONDS - hours*HOURS_IN_MILLISECONDS - minutes*MINUTES_IN_MILLISECONDS - seconds*SECONDS_IN_MILLISECONDS;
    printf("%i:days %i:hours %i:minutes %i:seconds %i:milliseconds", days, hours, minutes, seconds, milliseconds);
    return 0;
}
DanM
  • 1,910
  • 3
  • 22
  • 37
0
#ifndef DATETIME_H_
#define DATETIME_H_

/* Useful Constants */
#define SECS_PER_MIN  (60UL)
#define SECS_PER_HOUR (3600UL)
#define SECS_PER_DAY  (SECS_PER_HOUR * 24L)
#define DAYS_PER_WEEK (7L)
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
#define SECS_PER_YEAR (SECS_PER_WEEK * 52L)
#define SECS_YR_2000  (946681200UL)

/* Useful Macros for getting elapsed time */
/** Get just seconds part of given Unix time */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
/** Get just minutes part of given Unix time */
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
/** Get just hours part of given Unix time */
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
/** Get day of week from given Unix time */
#define dayOfWeek(_time_)  (( _time_ / SECS_PER_DAY + 4)  % DAYS_PER_WEEK) // 0 = Sunday
/** Get elapsed days since 1970-01-01 from given Unix time */
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY)  // this is number of days since Jan 1 1970
/** Get quantity of seconds since midnight from given Unix time */
#define elapsedSecsToday(_time_)  (_time_ % SECS_PER_DAY)   // the number of seconds since last midnight
/** Get Unix time of midnight at start of day from given Unix time */
#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY)  // time at the start of the given day
/** Get Unix time of midnight at end of day from given just Unix time */
#define nextMidnight(_time_) ( previousMidnight(_time_)  + SECS_PER_DAY ) // time at the end of the given day
/** Get quantity of seconds since midnight at start of previous Sunday from given Unix time */
#define elapsedSecsThisWeek(_time_)  (elapsedSecsToday(_time_) +  (dayOfWeek(_time_) * SECS_PER_DAY) )



#endif /* DATETIME_H_ */

Sample Code :

unsigned long long s = 1 * 10 ;
unsigned long long m = 1 * 60 * 20;
unsigned long long h = 1 * 60 * 60 * 3;
unsigned long long d = 1 * 60 * 60 * 24 * 60;
unsigned long long M = 1 * 60 * 60 * 24 * 30 * 5;
unsigned long long y = 1 * 60 * 60 * 24 * 30 * 12 * 6;

//unsigned long long timeInSec = s + m + h + d + M + y;
unsigned long long timeInSec = s + m + h + d;

long long seconds = numberOfSeconds(timeInSec);
long long minutes = numberOfMinutes(timeInSec);
long long hours = numberOfHours(timeInSec);
long long day = dayOfWeek(timeInSec);
long long _elapsedDays = elapsedDays(timeInSec);
long long _elapsedSecsToday = elapsedSecsToday(timeInSec);
-1

Two types of output

#include <iostream>
using namespace std;

int main() {
//Value chosen to be 1 hour, 1 minute, 1 second, and 1 millisecond
long milli = 3661001;

// hours
int hr = (milli / (1000 * 60 * 60)) % 24;

// minutes
int min = (milli / (1000 * 60)) % 60;

// seconds
int sec = (milli / 1000) % 60;

// milliseconds
int mill = milli % 1000;

char msg[10];
        sprintf(
                msg,
                "%02d hours and %02d minutes and %02d seconds and %02d milliseconds.\n",
                hr,
                min,
                sec,
                mill
                );
printf(msg);

cout << hr << " hours and " << min << " minutes and " << sec << " seconds and " << mill << " milliseconds." << endl;
}
Ilya Khudyakov
  • 193
  • 2
  • 15