Search code examples
javastringformatter

String.format, long and DateTime conversion


If the question is a duplicate, I apologise, I didn't find anything via Google.

To my problem:

I have the following test:

public void testSecondsToMinutes() {
    long zero = 0;
    long thirty_seconds = 30;
    long one_minute = 60;
    long thirty_minutes_fiftynine_seonds = 1859;
    long two_hours_ten_miutes_fourty_seconds = 7840;

    String format1 = "00:00:00";
    String format2 = "00:00:30";
    String format3 = "00:01:00";
    String format4 = "00:30:59";
    String format5 = "02:10:40";

    assertEquals(format1,Entrypoint.secondsToMinutes(zero));
    assertEquals(format2,Entrypoint.secondsToMinutes(thirty_seconds));
    assertEquals(format3,Entrypoint.secondsToMinutes(one_minute));
    assertEquals(format4,Entrypoint.secondsToMinutes(thirty_minutes_fiftynine_seonds));
    assertEquals(format5,Entrypoint.secondsToMinutes(two_hours_ten_miutes_fourty_seconds)); 
}

and the following function:

public static String secondsToMinutes(long seconds)
{
    return String.format("%TH:%TM:%TS", seconds, seconds, seconds);
}

the Java documentation for the Formatter states the following:

The following conversion characters are used for formatting common date/time compositions.
This conversion may be applied to long, Long, Calendar, and Date.
[...]
'R' '\u0052'    Time formatted for the 24-hour clock as "%tH:%tM"
'T' '\u0054'    Time formatted for the 24-hour clock as "%tH:%tM:%tS".

However, I am getting the following ComparisionFailure:

expected 00:00:00 but was 01:00:00

I must be missing something obvious here...


Solution

  • When you pass a long to String.format, it’s interpreted as milliseconds from the epoch, which is an entirely different entity than your intended seconds from midnight.

    Your problem is solved easiest by directly encoding your intention:

    public static String secondsToTwentyFourHourString(long seconds) {
        return String.format("%1$TH:%1$TM:%1$TS", LocalTime.ofSecondOfDay(seconds));
    }
    

    This way, you specify an operation which is not dependent on time zones.

    The same logic also works with DateTimeFormatter:

    public static String secondsToTwentyFourHourString(long seconds) {
        return LocalTime.ofSecondOfDay(seconds)
            .format(DateTimeFormatter.ofPattern("HH:mm:ss"));
    }