35

This is what I have at the moment

Seconds = (60 - timeInMilliSeconds / 1000 % 60);
Minutes = (60 - ((timeInMilliSeconds / 1000) / 60) %60);

which I feel is correct. for hours and days should it be like -

Hours = ((((timeInMilliSeconds / 1000) / 60) / 60) % 24);
Days =  ((((timeInMilliSeconds / 1000) / 60) / 60) / 24)  % 24;

and then-

TextView.SetText("Time left:" + Days + ":" + Hours + ":" + Minutes + ":" + Seconds);

but my hours and days are coming out to be incorrect

Akshat Agarwal
  • 2,837
  • 5
  • 29
  • 49
  • so why don't you utilize exist(native) date time classes?! –  Oct 29 '13 at 19:33
  • 2
    Why do `%24` on days? Are there 24 days in a month? – Peter Lawrey Oct 29 '13 at 19:45
  • @user2511414 : you are mistaking native and framework. native means written in the os native language, whatever that is (in this case C/C++), and it can belong to the framework or to any app. Classes you are referring to (such as SimpleDateFormat) belong to the framework, but whether they are native or not is not relevant. – njzk2 Oct 29 '13 at 19:50

10 Answers10

67

A simple way to calculate the time is to use something like

long seconds = timeInMilliSeconds / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
String time = days + ":" + hours % 24 + ":" + minutes % 60 + ":" + seconds % 60; 

This will work if you have more than 28 days, but not if you have a negative time.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
10

SimpleDateFormat is your friend! (I just discovered it today, it's awesome.)

SimpleDateFormat formatter = new SimpleDateFormat("dd:HH:mm:ss", Locale.UK);

Date date = new Date(timeInMilliSeconds);
String result = formatter.format(date);
Aurelien Ribon
  • 7,548
  • 3
  • 43
  • 54
  • 1
    +1 Can you explain why `, Locale.UK` is needed? I have never used it. – Peter Lawrey Oct 29 '13 at 19:46
  • 2
    EDIT: njzk2 is correct -- this WILL work for timespans less that one month. This won't work *for timespans greater than one month*. A SimpleDateFormat formats calendar dates, not elapsed time. It will interpret a millisecond offset as a date in the first month of 1970. – Charles Forsythe Oct 29 '13 at 19:50
  • 1
    @CharlesForsythe : as a matter of fact, for periods of less than a month, it would work. (just don't include years or months in your format). – njzk2 Oct 29 '13 at 19:51
  • @PeterLawrey In this instance, the Locale should have no effect. The local can have an effect if you use generic date formats where it can choose between M-D-Y (e.g. US) or D-M-Y (e.g. UK). Also, if you use a format that includes text (like month names), SimpleDateFormat will draw from a large collection of localized names and produce properly-translated text. – Charles Forsythe Oct 29 '13 at 19:56
  • @Aurélien initially I got the timeInMilliSeconds' using calenderObject.getTimeInMillis() and now if I convert it into a 'date' as you mentioned in your answer, would that somehow be incorrect? – Akshat Agarwal Oct 29 '13 at 20:09
  • 1
    @PeterLawrey Setting the locale has indeed no effect in this case since I specifically define the pattern in a locale agnostic way. However, I always include a fixed Locale in the constructor since Android Lint will complain about no Locale being set, even if that's not relevant. So basically, it's just to avoid a warning, and it has the bonus feature how being sure that the result will be the same for everyone on Earth if I include a Locale specific pattern by mistake. – Aurelien Ribon Oct 30 '13 at 07:37
  • This somehow doesn't do the right thing for me, i.e. for `timeInMilliSeconds = 0` this does not result in `00:00:00:00` as expected (also not with changing `dd` into `DD` which should IMHO be done anyway). – sschuberth May 23 '14 at 13:37
  • This does not serve the purpose of converting milliseconds to seconds, minutes, hours and days. It generated an EPOCH time whose reference is 1st Jan 1970. So if your milliseconds is 1 then the output you'll get is 1st Jan 1970. – LokiDroid Jun 11 '14 at 06:43
  • LOL i cant believe you discovered it when you said it :). This is actually THE way.... :) – Brethlosze Apr 07 '15 at 06:00
  • If the locale shouldn't matter, use `Locale.ROOT` to keep your intent clear. – Sean Van Gorder Sep 28 '15 at 15:39
  • 1
    I believe your solution does not work: Take *64800000* for example. This equates to 18 hours but by using your solution the result will be something like this: *01:18:00:00*. So as you can see, it prints out a day even though the difference is only 18 hours. – reVerse May 10 '16 at 12:51
  • 1
    This is incorrect. dd gives you day of the month of the date. It will give 1 day in durations less than a day. We want the number of days in the duration. Peter Lawrey's answer provides the correct solution. – TomV Feb 11 '21 at 17:02
6

Hi, how about this code ?

example)

               0 ms -> 0 ms
             846 ms -> 846ms
           1,000 ms -> 1s
           1,034 ms -> 1s 34ms
          60,000 ms -> 1m
          94,039 ms -> 1m 34s 39ms
       3,600,000 ms -> 1h
      61,294,039 ms -> 17h 1m 34s 39ms
      86,400,000 ms -> 1d
     406,894,039 ms -> 4d 17h 1m 34s 39ms
  31,536,000,000 ms -> 1y
  50,428,677,591 ms -> 1y 218d 15h 57m 57s 591ms

  50,428,677,591 ns -> 50s 428ms 677us 591ns
  50,428,677,591 us -> 14h 28s 677ms 591us
  50,428,677,591 ms -> 1y 218d 15h 57m 57s 591ms
  50,428,677,591 s  -> 1599y 30d 5h 59m 51s
  50,428,677,591 m  -> 95944y 354d 23h 51m
  50,428,677,591 h  -> 5756698y 129d 15h
  50,428,677,591 d  -> 138160760y 191d

/*
 * Copyright 2018 Park Jun-Hong_(fafanmama_at_naver_com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 *
 * This file is generated under this project, "open-commons-core".
 *
 * Date  : 2018. 1. 9. 오후 1:36:33
 *
 * Author: Park_Jun_Hong_(fafanmama_at_naver_com)
 * 
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 
 * @since 2018. 1. 9.
 * @author Park_Jun_Hong_(fafanmama_at_naver_com)
 */
public class TimeUtils {

    private static final TimeUnitInfo[] TIME_UNIT_INFO = new TimeUnitInfo[] { //
            new TimeUnitInfo(TimeUnit.NANOSECONDS, "ns") //
            , new TimeUnitInfo(TimeUnit.MICROSECONDS, "us") //
            , new TimeUnitInfo(TimeUnit.MILLISECONDS, "ms") //
            , new TimeUnitInfo(TimeUnit.SECONDS, "s") //
            , new TimeUnitInfo(TimeUnit.MINUTES, "m") //
            , new TimeUnitInfo(TimeUnit.HOURS, "h") //
            , new TimeUnitInfo(TimeUnit.DAYS, "d") //
    };

    private static final Map<TimeUnit, String> UNIT_STR = new HashMap<>();
    static {
        for (TimeUnitInfo tui : TIME_UNIT_INFO) {
            UNIT_STR.put(tui.unit, tui.unitStr);
        }
    }

    private static final Function<TimeUnit, TimeUnitInfo[]> FN_TIME_UNITS = unit -> {

        ArrayList<TimeUnitInfo> units = new ArrayList<>();

        for (TimeUnitInfo tui : TIME_UNIT_INFO) {
            if (tui.unit.ordinal() >= unit.ordinal()) {
                units.add(tui);
            }
        }

        return units.toArray(new TimeUnitInfo[] {});
    };

    /** discard none. */
    public static final int DC_NONE = 0x00;
    /** discard under nanoseconds */
    public static final int DC_NANO = 0x01;
    /** discard under microseconds */
    public static final int DC_MICRO = DC_NANO << 1;
    /** discard under milliseconds */
    public static final int DC_MILLI = DC_MICRO << 1;
    /** discard under seconds */
    public static final int DC_SECOND = DC_MILLI << 1;
    /** discard under minutes */
    public static final int DC_MINUTE = DC_SECOND << 1;
    /** discard under hours */
    public static final int DC_HOUR = DC_MINUTE << 1;
    /** discard under days */
    public static final int DC_DAY = DC_HOUR << 1;

    // prevent to create an instance.
    private TimeUtils() {
    }

    public static void main(String[] args) {

        long[] times = new long[] { 0, 846, 1000, 1034, 60000, 94039, 3600000, 61294039, 86400000, 406894039, 31536000000L, 50428677591L };
        for (long time : times) {
            System.out.println(String.format("%20s %-2s -> %s", String.format("%,d", time), "ms", toFormattedString(time, TimeUnit.MILLISECONDS)));
        }

        System.out.println("=================================");

        long time = 50428677591L;
        for (TimeUnitInfo tui : TIME_UNIT_INFO) {
            System.out.println(String.format("%20s %-2s -> %s", String.format("%,d", time), tui.unitStr, toFormattedString(time, tui.unit)));
        }
    }

    private static long mod(long time, TimeUnit unit) {
        switch (unit) {
            case NANOSECONDS: // to nanosecond
            case MILLISECONDS: // to microsecond
            case MICROSECONDS: // to millsecond
                return time % 1000;
            case SECONDS: // to second
                return time % 60;
            case MINUTES: // to minute
                return time % 60;
            case HOURS: // to hour
                return time % 24;
            case DAYS: // to day
                return time % 365;
            default:
                throw new IllegalArgumentException(unit.toString());
        }
    }

    /**
     * 
     * <br>
     * 
     * <pre>
     * [개정이력]
     *      날짜      | 작성자   |   내용
     * ------------------------------------------
     * 2018. 1. 9.      박준홍         최초 작성
     * </pre>
     *
     * @param timeBuf
     * @param time
     * @param unit
     *
     * @author Park_Jun_Hong_(fafanmama_at_naver_com)
     * @since 2018. 1. 9.
     */
    private static void prependTimeAndUnit(StringBuffer timeBuf, long time, String unit) {
        if (time < 1) {
            return;
        }

        if (timeBuf.length() > 0) {
            timeBuf.insert(0, " ");
        }

        timeBuf.insert(0, unit);
        timeBuf.insert(0, time);
    }

    /**
     * Provide the Millisecond time value in {year}y {day}d {hour}h {minute}m {second}s {millisecond}ms {nanoseconds}ns.
     * <br>
     * Omitted if there is no value for that unit.
     * 
     * @param time
     *            time value.
     * @param timeUnit
     *            a unit of input time value.
     * @return
     *
     * @since 2018. 1. 9.
     */
    public static String toFormattedString(long time, TimeUnit timeUnit) {

        // if zero ...
        if (time < 1) {
            return "0 " + UNIT_STR.get(timeUnit);
        }

        StringBuffer timeBuf = new StringBuffer();

        long mod = 0L;
        long up = time;

        for (TimeUnitInfo unit : FN_TIME_UNITS.apply(timeUnit)) {
            mod = mod(up, unit.unit);
            prependTimeAndUnit(timeBuf, mod, unit.unitStr);

            up = up(up, unit.unit);

            if (up < 1) {
                return timeBuf.toString();
            }
        }

        prependTimeAndUnit(timeBuf, up, "y");

        return timeBuf.toString();
    }

    private static long up(long time, TimeUnit unit) {
        switch (unit) {
            case NANOSECONDS: // to microsecond & above
            case MILLISECONDS: // to millsecond & above
            case MICROSECONDS: // to second & above
                return time / 1000;
            case SECONDS: // to minute & above
                return time / 60;
            case MINUTES: // to hour & above
                return time / 60;
            case HOURS: // to day & above
                return time / 24;
            case DAYS: // to year & above
                return time / 365;
            default:
                throw new IllegalArgumentException(unit.toString());
        }
    }

    private static class TimeUnitInfo {
        private final TimeUnit unit;
        private final String unitStr;

        public TimeUnitInfo(TimeUnit unit, String unitStr) {
            this.unit = unit;
            this.unitStr = unitStr;
        }
    }

}
Park Jun-Hong
  • 103
  • 1
  • 6
  • Very nice! I like that it omits units with no values. HOWEVER, I have an enhancement request! Pad hours, minutes, seconds to 2 characters, and millis to 3 chars. Makes a huge difference for reports. Maybe should be optional flag. Also to consider if also to pad days to 3 characters. [Man, you got me thinking..] Make year optional, or have another method without years, even if >365 days. Also make the OMIT feature (which I love) optional, useful for columnar reports where all the rows HAVE to absolutely be aligned. Thanks. – nat101 Jul 29 '18 at 19:15
  • Thanks for your comment. I think that optional flags are good. So I will apply your opinion. Additional a nanoseconds as a input value. See later.~^^~ – Park Jun-Hong Sep 28 '18 at 04:34
  • Looking forward. Thanks. – nat101 Nov 06 '18 at 06:50
3

To format elapsed/remaining times in android, use android.text.format.DateUtils, in particular, getRelativeTimeSpanString and formatElapsedTime.

njzk2
  • 38,969
  • 7
  • 69
  • 107
  • can you explain a bit what do each of those do? – Akshat Agarwal Oct 29 '13 at 20:28
  • the documentation is quite complete, and i don't see what i could add that wouldn't already be in any tutorial about this class. – njzk2 Oct 30 '13 at 14:20
  • This will either add an "in" prefix or "ago" suffix, and it does not display all of days, hours, minutes, seconds, but only one of them depending on the flags. – sschuberth May 23 '14 at 12:58
1

You can also use the joda-time API (http://joda.org/joda-time/)

"The class DateTimeFormat provides a single method forPattern(String) that supports formatting by pattern. These "pattern-based" formatters provide a similar approach to that of SimpleDateFormat."

LocalDate date = LocalDate.now();
DateTimeFormatter fmt = DateTimeFormat.forPattern("d MMMM, yyyy");
String str = date.toString(fmt);
1

Here is a simple JS function

function simplifiedMilliseconds(milliseconds) {

  const totalSeconds = parseInt(Math.floor(milliseconds / 1000));
  const totalMinutes = parseInt(Math.floor(totalSeconds / 60));
  const totalHours = parseInt(Math.floor(totalMinutes / 60));
  const days = parseInt(Math.floor(totalHours / 24));

  const seconds = parseInt(totalSeconds % 60);
  const minutes = parseInt(totalMinutes % 60);
  const hours = parseInt(totalHours % 24);

  let time = '1s';
  if (days > 0) {
    time = `${days}d:${hours}h:${minutes}m:${seconds}s`;
  } else if (hours > 0) {
    time = `${hours}h:${minutes}m:${seconds}s`;
  } else if (minutes > 0) {
    time = `${minutes}m:${seconds}s`;
  } else if (seconds > 0) {
    time = `${seconds}s`;
  }
  return time;
}
Jay Dadhaniya
  • 171
  • 4
  • 15
1

java.time

I recommend you use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.

import java.time.Duration;

public class Main {
    public static void main(String[] args) {
        // Given milliseconds e.g. milliseconds from the epoch
        long millis = System.currentTimeMillis();

        Duration duration = Duration.ofMillis(millis);

        // Duration in default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%d:%02d:%02d:%02d", duration.toDays(), duration.toHours() % 24,
                duration.toMinutes() % 60, duration.toSeconds() % 60);
        System.out.println("Duration (days:hours:min:seconds): " + formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%d:%02d:%02d:%02d", duration.toDaysPart(), duration.toHoursPart(),
                duration.toMinutesPart(), duration.toSecondsPart());
        System.out.println("Duration (days:hours:min:seconds): " + formattedElapsedTime);
        // ##############################################################################
    }
}

Output:

PT448255H41M9.125S
Duration (days:hours:min:seconds): 18677:07:41:09
Duration (days:hours:min:seconds): 18677:07:41:09

Note: For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
0

to solve your question try the following java class (with immutable instances)

package adrjx.utils.time;

public class VRDecodedTimePeriodMillis
{
    // instance data

    private int theMillisecs = 0;
    private int theSeconds = 0;
    private int theMinutes = 0;
    private int theHours = 0;
    private int theDays = 0;

    // init

    public VRDecodedTimePeriodMillis (long aTimePeriodMillis)
    {
        long aSeconds = aTimePeriodMillis / 1000;
        long aMinutes = aSeconds / 60;
        long aHours = aMinutes / 60;
        long aDays = aHours / 24;

        this.theMillisecs = (int)(aTimePeriodMillis % 1000);
        this.theSeconds = (int)(aSeconds % 60);
        this.theMinutes = (int)(aMinutes % 60);
        this.theHours = (int)(aHours % 24);
        this.theDays = (int)(aDays);

        // done
    }

    // accessors

    public int getMillisecs() { return this.theMillisecs; }
    public int getSeconds() { return this.theSeconds; }
    public int getMinutes() { return this.theMinutes; }
    public int getHours() { return this.theHours; }
    public int getDays() { return this.theDays; }

}

that's all folks ...

0

java.util.concurrent.TimeUnit to the rescue:

    long remainingMillis = 1076232425L; // Your value comes here.

    long days = TimeUnit.MILLISECONDS.toDays(remainingMillis);
    long daysMillis = TimeUnit.DAYS.toMillis(days);

    long hours = TimeUnit.MILLISECONDS.toHours(remainingMillis - daysMillis);
    long hoursMillis = TimeUnit.HOURS.toMillis(hours);

    long minutes = TimeUnit.MILLISECONDS.toMinutes(remainingMillis - daysMillis - hoursMillis);
    long minutesMillis = TimeUnit.MINUTES.toMillis(minutes);

    long seconds = TimeUnit.MILLISECONDS.toSeconds(remainingMillis - daysMillis - hoursMillis - minutesMillis);

    String resultString = days + " day(s) " + hours + " hour(s) " + minutes + " minute(s) " + seconds + " second(s)";
sasieightynine
  • 434
  • 1
  • 5
  • 16
0

Kotlin way

    fun getTripDuration(durationStr: String): String {

    val totalSeconds = durationStr.toDouble()
    val totalMinutes = floor(totalSeconds / 60)
    val totalHours = floor(totalMinutes / 60)
    val days = floor(totalHours / 24).toLong()
    val minutes = (totalMinutes % 60).toLong()
    val hours = (totalHours % 24).toLong()

    Timber.d("$days Days $hours Hours $minutes Minutes")
    var durationInWords = ""

    if (days > 1L) {
        durationInWords = durationInWords.plus("$days days ")
    } else if (days == 1L) {
        durationInWords = durationInWords.plus("$days day ")
    }

    if (hours > 1L) {
        durationInWords = durationInWords.plus("$hours hours ")
    } else if (hours == 1L) {
        durationInWords = durationInWords.plus("$hours hour ")
    }

    if (minutes > 1L) {
        durationInWords = durationInWords.plus("$minutes mins")
    } else if (minutes == 1L) {
        durationInWords = durationInWords.plus("$minutes min")
    }

    if (durationInWords.isEmpty()) {
        durationInWords = durationInWords.plus("$minutes min")
    }

    return durationInWords
}
Akash Dubey
  • 1,508
  • 17
  • 34