SimpleDateFormat 表示还有 2 小时

问题描述

我有这个代码,但它还有 2 个小时

  val leftTimeInMillis = 12728918
  val mTimeFormat = SimpleDateFormat("HH:mm:ss",Locale.ROOT)
  binding.textTimeLeft.text = mTimeFormat.format(leftTimeInMillis)

通常文本必须指示 03:32:08 但它是 05:32:08

解决方法

java.time.Duration 通过脱糖和 String.format()

使用现代 Java 日期和时间 API java.time 来处理您的时间工作。

我没有 Android 开发环境,但我希望以下内容能够与脱糖一起使用(请参阅下面的链接)。它适用于桌面 Java 版本 9 及更高版本。

    int leftTimeInMillis = 12_728_918;
    
    Duration timeLeft = Duration.ofMillis(leftTimeInMillis);
    String formattedTimeLeft = String.format("%02d:%02d:%02d",timeLeft.toHours(),timeLeft.toMinutesPart(),timeLeft.toSecondsPart());
    
    System.out.println(formattedTimeLeft);

输出是必需的:

03:32:08

如果出于某种原因,而不是脱糖您正在使用 ThreeTenABP,我相信 toMinutesParttoSecondsPart 方法不包括在内。然后转换需要多一点:

    Duration timeLeft = Duration.ofMillis(leftTimeInMillis);
    long hours = timeLeft.toHours();
    timeLeft = timeLeft.minusHours(hours);
    long minutes = timeLeft.toMinutes();
    timeLeft = timeLeft.minusMinutes(minutes);
    long seconds = timeLeft.getSeconds();
    String formattedTimeLeft = String.format("%02d:%02d:%02d",hours,minutes,seconds);

输出和之前一样。

替代方案:Time4A

如果您对用于日期和时间的广泛外部库感到满意,则可以选择 Time4A,Time4J 的 Android 版本。它提供了一种更优雅、更符合您自己尝试过的解决方案。我更喜欢声明一个静态格式化程序:

private static final Duration.Formatter<ClockUnit> M_TIME_FORMAT 
        = Duration.formatter(ClockUnit.class,"hh:mm:ss");

现在格式如下:

    int leftTimeInMillis = 12_728_918;
    
    Duration<ClockUnit> timeLeft = Duration.of(leftTimeInMillis,ClockUnit.MILLIS)
            .with(Duration.STD_CLOCK_PERIOD);
    String formattedTimeLeft = M_TIME_FORMAT.format(timeLeft);
    
    System.out.println(formattedTimeLeft);

03:32:08

我再次使用 Time4J 在桌面 Java 上开发了我的代码。

您的代码出了什么问题?

你的代码发生了什么?这两个小时从哪里来? SimpleDateFormat 是在 1990 年代设计的,始终用于格式化和解析时间点,而不是时间量。因此,您的数字 12 728 918 表示 UTC 时间 1970 年 1 月 1 日 Java 纪元之后几毫秒的时间点。换句话说,您正在尝试格式化 1970-01-01T03:32:08.918Z 的瞬间。由于您设备的时区设置(猜测是欧洲/雅典)在 1970 年冬天比 UTC 早 2 小时,因此用于格式化的日期和时间是 1970-01-01T05:32:08.918+02:00 [欧洲/雅典]。这就是您得到 05:32:08 的原因。

假设你在 1970 年的元旦晚上没有时间,那么你所做的就是错误的,即使你能让它工作,也会让每个阅读你代码的人感到困惑。另外如果某一天的毫秒数超过24小时,则不会打印整天,可能会造成很大的混乱。请勿将 SimpleDateFormat 用于此目的。并考虑永远不要使用 SimpleDateFormat,因为该类是出了名的麻烦且过时。

问题:java.time 不需要 Android API 级别 26 吗?

java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6

  • 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 开始)中,内置了现代 API。
  • 在非 Android Java 6 和 7 中获得 ThreeTen Backport,现代类的向后移植(ThreeTen for JSR 310;请参阅底部的链接)。
  • 在较旧的 Android 上,使用脱糖或 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。在后一种情况下,请确保使用子包从 org.threeten.bp 导入日期和时间类。

链接