Search code examples
datetimeminecraftbukkitmilliseconds

How do I convert milliseconds to days, hour, minutes


I tried to do this:

        long Plptime = player.getStatistic(Statistic.PLAY_ONE_TICK)*50L; //from ticks to ms(1 tick (20 each sec) by 50 gives aprox the ms)

        SimpleDateFormat formatter = new SimpleDateFormat("dd 'days,' HH 
        'hours and' mm 'minutes'", Locale.getDefault());

        Date date = new Date(Plptime);
        String result1 = formatter.format(date);

But when it messages the String to the player (minecraft by the way), the hours and days start on 1 while the min start on 0, for example right when someone just joins his playtime will be 01days 01 hours 00 min. Any solutions? Thanks


Solution

  • Java 9 or later

    Let’s first declare a couple of helpful constants.

    private static final int TICKS_PER_SECOND = 20;
    public static final Duration ONE_TICK = Duration.ofSeconds(1).dividedBy(TICKS_PER_SECOND);
    

    Now do:

        int ticks = player.getStatistic(Statistic.PLAY_ONE_TICK);
        Duration plpTime = ONE_TICK.multipliedBy(ticks);
        String result1 = String.format(Locale.ENGLISH, "%02d days %02d hours and %02d minutes",
                plpTime.toDays(), plpTime.toHoursPart(), plpTime.toMinutesPart());
    
        System.out.println(result1);
    

    This prints a string like

    00 days 17 hours and 08 minutes

    Possibly the number of ticks per second (20) is already declared as a constant somewhere in Bukkit, I don’t know. If it is, take that one rather declaring your own.

    Java 6, 7 or 8

    The toXxxPart methods I used were introduced in Java 9. Without them we need to calculate the individual parts like this:

        long days = plpTime.toDays();
        plpTime = plpTime.minusDays(days);
        long hours = plpTime.toHours();
        plpTime = plpTime.minusHours(hours);
        long minutes = plpTime.toMinutes();
        String result1 = String.format(Locale.ENGLISH, "%02d days %02d hours and %02d minutes",
                days, hours, minutes);
    

    The result is the same as above.

    Question: How can that work in Java 6 or 7?

    The Duration class that I am using is part of java.time, the modern Java date and time API

    • In Java 8 and later and on newer Android devices (from API level 26, I’m told) java.time comes built-in.
    • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
    • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

    What went wrong in your code?

    Why the hours seem to start at 1 (not 0): It’s your time zone. When you create a Date from your milliseconds, you get the point in time that many milliseconds after the epoch defined as 00:00 UTC on Jan 1, 1970 (which conceptually is quite misleading when the question was when a player joined). If your time zone was 1 hour ahead of UTC in the winter of 1970 (like Central European time, for example), it was already 1 o’clock at the epoch, so the hours count from there.

    And since it was January 1, the day is given as 1, of course. Curiously, if you had been in a time zone west of GMT (America/Los_Angeles to give just one example), the date would still have been December 31, 1969 in the first hours after the epoch, so the newly joined player might appear to have been there for 31 days, 16 hours and 00 minutes, for example.

    Links