Android:如何将 SystemClock.elapsedRealTime 转换为人类可读的 CharSeq?

Android: How to convert from SystemClock.elapsedRealTime to a human readable CharSeq?

如何从 SystemClock.elapsedRealTime() 转换为可以在文本视图中显示的人类可读的 CharSeq?

请参阅以下问题:How to format an elapsed time interval in hh:mm:ss.SSS format in Java?。使用这种方法:

private static String formatInterval(final long millis) {
    final long hr = TimeUnit.MILLISECONDS.toHours(millis);
    final long min = TimeUnit.MILLISECONDS.toMinutes(millis - TimeUnit.HOURS.toMillis(hr));
    final long sec = TimeUnit.MILLISECONDS.toSeconds(millis - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
    final long ms = TimeUnit.MILLISECONDS.toMillis(millis - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
    return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}

然后假设您有对 TextView 的引用:

long elapsedTime = SystemClock.elapsedRealTime();
textView.setText(elapsedTime);

结果是您的 TextView 将以人类可读的格式显示您的设备已启动的总时间。

tl;博士

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

避免时间格式

以一天中的时间 (HH:MM:SS.SSS) 格式显示经过的时间具有误导性和歧义性,因为它很容易被误解为一天中的时间。

ISO 8601 – 持续时间格式

ISO 8601 标准定义了各种日期时间值的合理字符串表示形式。这些值包括经过的时间。

标准格式是 PnYnMnDTnHnMnS,其中开头用 P 标记,而 T 将年-月-日部分与时-分-秒部分分开。例如:

  • PT30M = 半小时
  • PT8H30M = 八个半小时
  • P3Y6M4DT12H30M5S表示持续时间"three years, six months, four days, twelve hours, thirty minutes, and five seconds".

术语 "period" 或 "duration" 通常用作同义词。日期时间工作中的术语尚未标准化。请注意标准如何使用术语 "duration",但格式以 P 开头,如 "period"。 人生至此.

java.time

java.time classes 提供两个 classes 来表示未附加到时间轴的时间跨度:

  • Period
    年-月-日
  • Duration
    小时-分钟-秒

这两个 class 都是 parse/generate 上面讨论的标准 ISO 8601 持续时间格式。

SystemClock.elapsedRealTime() 的输出是一个 long 整数,计算经过的毫秒数。所以我们想要可能想要使用 Duration class.

long millis = SystemClock.elapsedRealTime() ;
Duration d = Duration.ofMillis( millis ) ;

让我们试试 441000 作为我们的毫秒。

Duration d = Duration.ofMillis( 441_000L ) ;

生成标准格式的字符串。对于 441_000L,我们得到 7 分 21 秒。

String output = d.toString() ;  // Generate standard ISO 8601 string.

PT7M21S

您可以解析标准字符串,以获得 Duration 对象。

Duration d = Duration.parse( "PT7M21S" ) ;

我建议教您的用户阅读标准 ISO 8601 格式,因为它可读且明确。我强烈建议 never 以时间格式 (00:07:21) 显示,因为我发现歧义会在用户中引起很多混淆。但是如果您的用户群不适合标准格式,您可以生成其他字符串。

在这个 class 的某些更高版本中,您可以调用 to…Part 方法来检索七和二十一。

int minutesPart = d.toMinutesPart() ; // The whole-minutes portion.
int secondsPart = d.toSecondsPart() ; // The whole-seconds portion.

您还可以返回总毫秒数。

long millis = d.toMillis() ;  // Not the part, but the entire span of time in terms of milliseconds.

关于java.time

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.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与您的数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

从哪里获得java.time classes?

  • Java SE 8, Java SE 9, Java SE 10,及以后
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and Java SE 7
  • Android
    • Android java.time classes.
    • 捆绑实施的更高版本
    • 对于较早的 Android (<26),ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See .

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.


乔达时间

更新: Joda-Time 项目现在处于维护模式,团队建议迁移到 java.timeclass是的。我将完整保留此部分以供历史参考。

Joda-Time 库提供了三个 class 表示时间跨度的元素,IntervalDurationPeriod。最后一个 Period 表示描述为天数、小时数等的时间跨度。它与这种特殊的 ISO 8601 格式相似。 Period class 还解析并生成 ISO 8601 格式的字符串。 Joda-Time 在 Android 中工作,作为臭名昭著的麻烦 java.util.Date/.Calendar classes.

的替代品,它已经过时并且很受欢迎。

Period class 采用 long 整数作为持续时间的毫秒计数。正是我们所需要的,因为 SystemClock.elapsedRealtime() 为我们提供了自机器启动以来的毫秒数。

long machineUptimeMillis = SystemClock.elapsedRealtime() ;
Period machineUptimePeriod = new Period( machineUptimeMillis );
String output = machineUptimePeriod.toString(); // Ex: P3DT2H15M37.123S

如果我们要跟踪某些操作需要多长时间,我们将在减法中使用一对这样的 long

long start = SystemClock.elapsedRealtime() ;
// … Perform some operation …
long stop = SystemClock.elapsedRealtime() ;
long elapsedMillis = stop - start ;
Period elapsedPeriod = new Period( elapsedMillis );

小写

为了向人类用户展示,您可能需要删除 P and/or T 并使用小写字母以获得更好的可读性。

String output = elapsedPeriod.toString().replace( "P" , "" ).replace( "T", " " ).toLowerCase() ; 

例如,3y6m4d 12h30m5s.

漂亮的印花

您可以漂亮地打印 Period 值,例如“5 年零 2 个月”。

使用内置 Locale-sensitive word-based formatter.

PeriodFormatter formatter = PeriodFormat.wordBased( Locale.CANADA_FRENCH ) ;
String output = formatter.print( elapsedPeriod ) ;

或者使用 PeriodFormatterBuilder.

创建您自己的自定义格式
 PeriodFormatter yearsAndMonths = new PeriodFormatterBuilder()
     .printZeroAlways()
     .appendYears()
     .appendSuffix(" year", " years")
     .appendSeparator(" and ")
     .printZeroRarelyLast()
     .appendMonths()
     .appendSuffix(" month", " months")
     .toFormatter() ;