简体   繁体   English

ZonedDateTime 到早期 Android 中 Java 8 之前的日期

[英]ZonedDateTime to Date before Java 8 in early Android

I am trying to replace the ZonedDateTime.toInstant method because it is only available since API 26 for Android.我正在尝试替换ZonedDateTime.toInstant方法,因为它仅在适用于 Android 的 API 26 之后可用。
But my app is supposed to support API 19.但我的应用程序应该支持 API 19。
I want to convert the ZonedDateTime to a Date so i can do something like this:我想将 ZonedDateTime 转换为日期,以便我可以执行以下操作:

final Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
final long millis = calendar.getTimeInMillis();

What i want to achieve is the following:我想要实现的是以下内容:
I want to calculate the difference between the current date and another date in Seconds, Minutes, Hours, ... the highest possible unit wins, so i would get eg 5 days ago as result.我想计算当前日期和另一个日期之间的差异,以秒、分钟、小时为单位,......最高可能的单位获胜,所以我会得到例如5 days ago的结果。

tl;dr tl;博士

For Android before 26, use the ThreeTen-ABP library.对于 26之前的 Android,使用ThreeTen-ABP库。

Avoid legacy date-time classes避免遗留的日期时间类

The old date-time classes such as Calendar and Date are terrible , really, awful wretched classes.旧的日期时间类,例如CalendarDate可怕的,真的,可怕的可悲的类。 They are laden with bad design decisions and hacks, built by people who did not understand date-time handling.它们充满了糟糕的设计决策和黑客,由不了解日期时间处理的人构建。 Avoid them.避开它们。 They were entirely supplanted by the java.time classes with the adoption of JSR 310 for a reason – actually, many reasons.随着 JSR 310 的采用,它们完全被java.time类所取代——实际上,有很多原因。

Avoid these legacy classes.避免这些遗留类。 Use only java.time classes.仅使用java.time类。

ThreeTen-Backport library ThreeTen-Backport

For Java 6 and Java 7, most of the java.time functionality is back-ported in the ThreeTen-Backport project.对于 Java 6 和 Java 7,大部分java.time功能都在ThreeTen-Backport项目中向后移植。

ThreeTen-ABP三十-ABP

That back-port is further adapted to earlier Android (<26) in the ThreeTen-ABP project.ThreeTen-ABP项目中,该后向移植进一步适用于早期的 Android (<26)。

I urge you to add this library to your project so you can avoid ever using the tragic legacy classes.我敦促您将此库添加到您的项目中,这样您就可以避免使用悲剧性的遗留类。

Conversion转换

Where you need to interface with old code not yet updated to java.time , convert back-and-forth between legacy and modern.如果您需要与尚未更新为java.time 的旧代码进行交互,请在旧代码和现代代码之间来回转换。

In Java 8 and later, convert by calling the new to… and from… methods found on the old classes.在 Java 8 及更高版本中,通过调用在旧类中找到的新的to…from…方法进行转换。

In the back-port, convert using the to… conversion methods found on the org.threeten.bp.DateTimeUtils class.在后向端口中,使用org.threeten.bp.DateTimeUtils类中的to…转换方法to…转换。

Elapsed time已用时间

Your Question talks about calculating elapsed time.您的问题涉及计算经过时间。

To count years, months, and days, use Period .要计算年、月和日,请使用Period

To count days (24-hour chunks of time unrelated to the calendar), hours, minutes, seconds, and fractional second, use Duration .要计算天数(与日历无关的 24 小时时间块)、小时、分钟、秒和小数秒,请使用Duration

Search Stack Overflow for more info.搜索堆栈溢出以获取更多信息。 These classes have been covered many time already.这些类已经介绍了很多次。


About java.time关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于 Java 8 及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

To learn more, see the Oracle Tutorial .要了解更多信息,请参阅Oracle 教程 And search Stack Overflow for many examples and explanations.并在 Stack Overflow 上搜索许多示例和解释。 Specification is JSR 310 .规范是JSR 310

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.现在处于维护模式Joda-Time项目建议迁移到java.time类。

You may exchange java.time objects directly with your database.您可以直接与您的数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later.使用符合JDBC 4.2或更高版本的JDBC 驱动程序 No need for strings, no need for java.sql.* classes.不需要字符串,不需要java.sql.*类。

Where to obtain the java.time classes?从哪里获得 java.time 类?

在此处输入图片说明

You can enable "Support for newer Java language APIs" simply by this gradle configuration:您可以通过以下 gradle 配置简单地启用“支持更新的 Java 语言 API”:

<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->

android {
  defaultConfig {
    //Only required when setting minSdkVersion to 20 or lower
    multiDexEnabled true
  }

  compileOptions {
    // Flag to enable support for the new language APIs
    coreLibraryDesugaringEnabled true
    // Sets Java compatibility to Java 8
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

dependencies {
  // Dependency with the implementation code for the APIs
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'
}

Source: https://medium.com/androiddevelopers/support-for-newer-java-language-apis-bca79fc8ef65来源: https : //medium.com/androiddevelopers/support-for-newer-java-language-apis-bca79fc8ef65

There's already a good answer by Basil Bourque. Basil Bourque 已经有一个很好的答案。 After your comments I thought I could be just a little more specific:在您发表评论后,我想我可以更具体一点:

public static String diff(String thenStr) {
    Instant now = Instant.now();
    Instant then = Instant.parse(thenStr);
    ChronoUnit[] units = ChronoUnit.values();
    // try longest units first, they are in the far end of the array
    for (int i = units.length - 1; i >= 0; i--) {
        if (then.isSupported(units[i])) {
            long diffInCurrentUnit = units[i].between(then, now);
            if (diffInCurrentUnit != 0) {
                return "" + diffInCurrentUnit + ' ' + units[i].toString().toLowerCase();
            }
        }
    }
    return "0";
}

Let's try it out:让我们试试看:

    System.out.println(diff("2019-02-23T16:50:21Z"));
    System.out.println(diff("2019-02-23T20:15:21Z"));

Output when running just now:刚才运行时的输出:

 3 hours 36 seconds

Imports I used:我使用的进口:

import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;
import org.threeten.bp.temporal.UnsupportedTemporalTypeException;

Instant doesn't support coarser units than days (at 24 hours). Instant不支持比天(24 小时)更粗的单位。 If you need to be able to return weeks, months or years, just use OffsetDateTime instead of Instant .如果您需要能够返回数周、数月或数年,只需使用OffsetDateTime而不是Instant

Question: Can I use java.time on my Android API level?问题:我可以在我的 Android API 级别上使用 java.time 吗?

Yes, java.time works nicely on older and newer Android devices.是的,java.time 在较旧和较新的 Android 设备上都能很好地工作。 It just requires at least Java 6 .它只需要至少Java 6

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.在 Java 8 及更高版本和更新的 Android 设备(从 API 级别 26)中,现代 API 是内置的。 In this case import from java.time with subpackages.在这种情况下,从带有子包的java.time导入。
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).在 Java 6 和 7 中获得 ThreeTen Backport,现代类的 backport(ThreeTen for JSR 310;请参阅底部的链接)。
  • On (older) Android use the Android edition of ThreeTen Backport.在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。 It's called ThreeTenABP.它被称为 ThreeTenABP。 And make sure you import the date and time classes from org.threeten.bp with subpackages.并确保使用子包从org.threeten.bp导入日期和时间类。

A stream?一条流?

EDIT: @Basil Bourque asked in a comment:编辑: @Basil Bourque 在评论中问道:

I wonder if this could be crunched down into a stream, perhaps a one-liner?我想知道这是否可以压缩成一条小溪,也许是一条单线?

It can, but I don't think it will be an advantage in this case:它可以,但我认为在这种情况下这不会是一个优势:

    return IntStream.range(0, units.length)
            .map(i -> units.length - i - 1)
            .mapToObj(i -> units[i])
            .filter(then::isSupported)
            .filter(unit -> unit.between(then, now) != 0)
            .map(unit -> "" + unit.between(then, now) + ' ' + unit.toString().toLowerCase())
            .findFirst()
            .orElse("0");

I find the code for taking the array elements backward, .map(i -> units.length - i - 1) , a bit hard to read.我发现向后获取数组元素的代码.map(i -> units.length - i - 1)有点难以阅读。 We need to calculate the difference twice, first for filtering and then for assembling the string result.我们需要计算两次差值,首先是过滤,然后是组合字符串结果。 But it works, and you may go with it if you like.但它有效,如果您愿意,可以使用它。

The double calculation can be avoided with an inner stream pipeline, again harder to read, though:使用内部流管道可以避免双重计算,但同​​样难以阅读:

            .flatMap(unit -> LongStream.of(unit.between(then, now))
                    .filter(diff -> diff != 0)
                    .mapToObj(diff -> "" + diff + ' ' + unit.toString().toLowerCase()))

Links链接

Solution (ThreeTen-Backport Library):解决方案(ThreeTen-Backport 库):
It's working perfectly, i already tried it out on an KitKat emulator.它工作得很好,我已经在 KitKat 模拟器上试过了。

private static final ChronoUnit[] chronoUnits = {ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS, ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS};
private static final Map<ChronoUnit, Integer> chronoUnitPluralIdMap = new HashMap<ChronoUnit, Integer>() {{
    put(ChronoUnit.YEARS, R.plurals.chrono_unit_years_ago);
    put(ChronoUnit.MONTHS, R.plurals.chrono_unit_months_ago);
    put(ChronoUnit.DAYS, R.plurals.chrono_unit_days_ago);
    put(ChronoUnit.HOURS, R.plurals.chrono_unit_hours_ago);
    put(ChronoUnit.MINUTES, R.plurals.chrono_unit_minutes_ago);
    put(ChronoUnit.SECONDS, R.plurals.chrono_unit_seconds_ago);
}};

public static String getTimeStringUntilNowFromUTC(Context context, String utcDate) {
    Instant now = Instant.now(Clock.systemUTC());
    Instant then = Instant.parse(utcDate);
    for (ChronoUnit chronoUnit : chronoUnits) {
        if (then.isSupported(chronoUnit)) {
            long units = chronoUnit.between(then, now);
            if (units > 0) {
                //noinspection ConstantConditions
                return context.getResources().getQuantityString(chronoUnitPluralIdMap.get(chronoUnit), (int)units, (int)units);
            }
        }
    }
    return "-";
}

public static String getTimeBetweenTwoDates(Context context, String date1, String date2) {
    Instant date1Instant = Instant.parse(date1);
    Instant date2Instant = Instant.parse(date2);
    final long seconds = ChronoUnit.SECONDS.between(date1Instant, date2Instant);
    return getMinutesSecondsString(context, seconds);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM