How do you convert from SystemClock.elapsedRealTime()
to a human readable CharSeq that can be displayed in textview?
Duration.ofMillis( // Represent a span of time on scale of hours-minutes-seconds, unattached to the timeline.
SystemClock.elapsedRealTime() // 441_000L as an example.
)
.toString() // Generate a String in standard ISO 8601 format.
PT7M21S
Displaying elapsed time in the format of time-of-day (HH:MM:SS.SSS) is misleading and ambiguous as it can easily be misinterpreted as time-of-day.
The ISO 8601 standard defines sensible string representations of various date-time values. These values include elapsed time.
The standard format is PnYnMnDTnHnMnS
where the beginning is marked with a P
while a T
separates the years-month-days portion from the hours-minutes-seconds portion. For example:
PT30M
= a half hourPT8H30M
= eight and a half hoursP3Y6M4DT12H30M5S
represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".Often the terms "period" or "duration" are used as synonyms. The terminology in date-time work has not yet been standardized. Note how the standard uses the term "duration", yet the format begins with a P
as in "period". C’est la vie.
The java.time classes offer two classes to represent a span of time unattached to the timeline:
Period
Duration
Both of these classes parse/generate the standard ISO 8601 duration format discussed above.
Your output from SystemClock.elapsedRealTime()
is a long
integer number counting milliseconds elapsed. So we want likely want to use the Duration
class.
long millis = SystemClock.elapsedRealTime() ;
Duration d = Duration.ofMillis( millis ) ;
Let’s try 441000 as our millis.
Duration d = Duration.ofMillis( 441_000L ) ;
Generate the standard formatted string. For 441_000L
, we get seven minutes and 21 seconds.
String output = d.toString() ; // Generate standard ISO 8601 string.
PT7M21S
You can parse the standard strings, to get a Duration
object.
Duration d = Duration.parse( "PT7M21S" ) ;
I suggest teaching your users to read the standard ISO 8601 format, as it is readable and unambiguous. I strongly recommend never displaying as a time-of-day format (00:07:21
) as I have seen that ambiguity cause much confusion among users. But if your user-base is not amenable to the standard format, you can generate other strings.
In some later versions of this class, you can call the to…Part
methods to retrieve the seven and the twenty-one.
int minutesPart = d.toMinutesPart() ; // The whole-minutes portion.
int secondsPart = d.toSecondsPart() ; // The whole-seconds portion.
You can also get back to a grand total of milliseconds.
long millis = d.toMillis() ; // Not the part, but the entire span of time in terms of milliseconds.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
UPDATE: The Joda-Time project is now in maintenance-mode, with the team advising migration to java.time classes. I am leaving this section intact for history.
The Joda-Time library offers three classes to represent a span of time, Interval
, Duration
, and Period
. That last one, Period
, means a span of time described as a count of days, hours, and such. It parallels this particular ISO 8601 format. The Period
class also parses and generates strings in the ISO 8601 format. Joda-Time works in Android, is well-worn and quite popular as a replacement for the notoriously troublesome java.util.Date/.Calendar classes.
The Period
class takes a long
integer as a count of milliseconds in duration. Just what we need, as SystemClock.elapsedRealtime()
gives us a count in milliseconds since the machine booted.
long machineUptimeMillis = SystemClock.elapsedRealtime() ;
Period machineUptimePeriod = new Period( machineUptimeMillis );
String output = machineUptimePeriod.toString(); // Ex: P3DT2H15M37.123S
If we are tracking how long some operation takes, we’ll be using a pair of such long
s in subtraction.
long start = SystemClock.elapsedRealtime() ;
// … Perform some operation …
long stop = SystemClock.elapsedRealtime() ;
long elapsedMillis = stop - start ;
Period elapsedPeriod = new Period( elapsedMillis );
For presentation to human users, you may want to strip out the P
and/or T
and use lowercase letters for better readability.
String output = elapsedPeriod.toString().replace( "P" , "" ).replace( "T", " " ).toLowerCase() ;
For example, 3y6m4d 12h30m5s
.
You can pretty-print Period
values such as "5 years and 2 months".
Use the built-in Locale-sensitive word-based formatter.
PeriodFormatter formatter = PeriodFormat.wordBased( Locale.CANADA_FRENCH ) ;
String output = formatter.print( elapsedPeriod ) ;
Or create your own custom format with a PeriodFormatterBuilder
.
PeriodFormatter yearsAndMonths = new PeriodFormatterBuilder()
.printZeroAlways()
.appendYears()
.appendSuffix(" year", " years")
.appendSeparator(" and ")
.printZeroRarelyLast()
.appendMonths()
.appendSuffix(" month", " months")
.toFormatter() ;