【问题标题】:Different behavior of PeriodFormatter on different devices (JodaTime)PeriodFormatter 在不同设备上的不同行为(JodaTime)
【发布时间】:2017-06-26 03:25:37
【问题描述】:

我正在使用 JodaTime 为 android 应用程序实现倒数计时器。 根据设备的不同,输出是不同的。

       DateTime openingDateTime = new DateTime(2018, DateTimeConstants.JUNE, 14, 21, 0, 0, DateTimeZone.forID("Europe/Moscow"));
        DateTime nowDateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"));
        long difference = openingDateTime.getMillis() - nowDateTime.getMillis();
(...)
onTick(difference);

(...)

    PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
            .printZeroAlways()
            .appendDays().appendSuffix(" day", " days")
            .appendSeparator(" ")
            .appendHours()
            .appendSeparator(":")
            .appendMinutes()
            .appendSeparator(":")
            .appendSeconds()
            .toFormatter();
(...)    

        @Override
        public void onTick(long millisUntilFinished) {
            Duration duration = new Duration(millisUntilFinished);
            Period period = duration.toPeriod(PeriodType.dayTime());
            tvCounter.setText(periodFormatter.print(period));
        }

单机输出正确:491 days 4:39:18 另一方面是错误的:0 天 11788:49:11。 我做错了什么?

【问题讨论】:

  • 也许您的设备上有不同版本的 Joda-Time。无论如何,我只能重现您的第二个(错误)示例,javadoc 说:“只会使用句点类型中的精确字段。最多是小时、分钟、秒和毫秒”
  • 为什么不简单地使用Period p = new Period(nowDateTime, openingDateTime, PeriodType.dayTime()); 而不是这种有损的毫秒转换?
  • @MenoHochschild Joda-Time 的版本是相同的。我不知道为什么,但 Joda 必须使用与我的解决方案相关的某种信息的内部 android 实现。
  • @MenoHochschild 你说得对,在这种情况下我必须忘记默认的 long millisUntilFinished 参数(它来自 CountDownTimer android SDK 解决方案)并使用简单的 Period(DateTime, DateTime, PerdiodType)
  • @MenoHochschild 你说得对,更改默认区域会影响输出。

标签: android jodatime duration period periodformatter


【解决方案1】:

感谢您的 cmets,我现在可以重现您的问题。只需将以下静态初始化程序添加到您的测试类(首先)以模拟您观察预期输出的设备:

static {
    TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
}

根据规范(另见accepted answer on this SO-post),转换duration.toPeriod(periodType) 应该只使用所谓的精确持续时间字段,即小时、分钟、秒和毫秒,而不是天。

我对Joda-Time(v2.9.6)源码的分析:

内部类org.joda.time.chrono.BasicChronology 包含以下常量:

private static final DurationField cDaysField = new PreciseDurationField(DurationFieldType.days(), 86400000L);

所以我们看到这里这个持续时间字段被标记为“精确”,但是:子类 ZonedChronology 包装了它并覆盖了方法 isPrecise() 的行为:

public boolean isPrecise() { 
  return iTimeField ? iField.isPrecise() : iField.isPrecise() && this.iZone.isFixed(); 
} 

这显示了 days()-duration-field 的精度属性的额外区域依赖性,即对于 UTC 等固定区域是精确的,否则不精确。

我不知道分析和观察到的行为是功能还是错误。比方说,期望duration.toPeriod(...) 创建的Period-objects 与区域无关是很危险的。如果系统区域是固定的,那么not documented there 有一个精确的天数组件。

不幸的是,对默认时区的隐式依赖通过其年表设计被深度编码到 Joda-Time 中。 作为解决方法,您可以使用

Period p = new Period(nowDateTime, openingDateTime, PeriodType.dayTime());

【讨论】:

    猜你喜欢
    • 2016-06-06
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多