如何在Android中比较两个日期?

4
我从服务器上获得了一个格式为 yyyy-mm-dd HH:mm:ss 的日期。我通过 System.currentTimeMillis() 方法获取了当前时间的毫秒值。我想要比较这两个日期并判断是否是未来的日期,如果是,则安排一个闹钟来提醒。我的问题是如何比较这两个不同格式的日期,并如何获取剩余时间(未来时间 - 当前时间),以便安排闹钟。
编辑: 我已经尝试将日期解析为毫秒值,但它没有返回与 System.currentTimeMillis() 相同格式的值,所以失败了。

请看我的编辑,我有一个不同的问题。 - JAAD
为什么它们会相同呢?一个是当前时间,另一个是其他日期时间。我仍然不理解问题所在。 - tyczj
1
服务器的日期时间是否在UTC?若不是,则需要在解析前设置服务器时间的时区。 - tyczj
1
这与讨论无关,但是您的代码是否考虑了时区?例如,在东京现在是3月11日06:26,而在洛杉矶是3月10日13:26。如果您的代码忽略了时区,可能会导致不匹配。 - user2340612
@ankitagrawal 好的,那么在解析日期字符串之前,您需要在代码中设置时区。 - tyczj
显示剩余16条评论
2个回答

8
您可以利用DateFormat类解析yyyy-mm-dd HH:mm:ss格式的日期,比如SimpleDateFormat类。这个操作会返回一个Date对象。
您也可以根据当前时间的毫秒数创建一个Date对象。
当您有这两个对象后,您可以使用compareTo方法进行比较。
例如以下代码:
try {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date parsed = sdf.parse("2016-03-10 22:05:20");

    Date now = new Date(System.currentTimeMillis()); // 2016-03-10 22:06:10

    System.out.println(parsed.compareTo(now));
} catch (Exception e) {
    e.printStackTrace();
}

将会打印-1,这意味着parsednow之前

编辑:

下面是一个简单但无用的应用程序的代码,它使用了AlarmManager。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Log.d("TAG", "From intent: "+getIntent().getStringExtra("MyEXTRA"));
}

@Override
protected void onResume() {
    super.onResume();

    try {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long parsedMillis = sdf.parse("2016-03-10 22:54:30").getTime();
        long now = System.currentTimeMillis(); // 22:54:15

        if (parsedMillis > now) {
            Log.d("TAG", "In the future!");

            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            Intent intent = new Intent(this, MyActivity.class);
            intent.putExtra("MyEXTRA", "From alarm");
            PendingIntent broadcast = PendingIntent.getActivity(this, 0, intent, 0);
            am.setExact(AlarmManager.RTC_WAKEUP, parsedMillis, broadcast);

        } else {
            Log.d("TAG", "In the past...");
        }


    } catch (Exception e) {
        e.printStackTrace();
    }
}

在LogCat中,您将看到:
03-10 22:54:20.925    3946-3946/com.example.myapp D/TAG﹕ From intent: null
03-10 22:54:21.227    3946-3946/com.example.myapp D/TAG﹕ In the future!
03-10 22:54:30.513    3946-3946/com.example.myapp D/TAG﹕ From intent: From alarm
03-10 22:54:30.577    3946-3946/com.example.myapp D/TAG﹕ In the past...

最后一行被打印是因为闹钟导致活动重新启动,因此 onResume 将再次被调用,并且 System.currentTimeMillis() 将大于硬编码时间。但是,正如您所看到的,闹钟在预定时间正确触发。
此外,您应该考虑边缘情况:如果 parsedMillis 仅比 now 多几毫秒,您可能会设置一个永远不会被触发的闹钟,因为它是在过去设置的。这是因为操作系统需要一些时间来执行您的代码,因此您应该检查 parsedMillis > now + DELTA,其中 DELTA 是取决于您在 System.currentTimeMillis()am.setExact(...) 之间执行的代码的合理时间量。

获取毫秒级时间差以安排闹钟怎么样? - JAAD
你可以调用 parsed.getTime() 方法来获取毫秒级别的时间。之后只需要进行简单的数学计算即可。 - user2340612
我尝试使用setExact但不起作用,你能发布一些在alarmManager中有效的代码吗? - JAAD
你应该检查parsed是否在未来,可以通过将其与System.currentTimeMillis()进行比较来判断。如果它在未来并且你希望在那个时间触发闹铃,你应该使用parsed.getTime()作为alarmManager.setExact(...)方法的triggerAtMillis参数。 - user2340612
1
我解决了,这只是一个 HH 问题,我太慌了,所以时间不对,既然你帮了我,我就接受了答案。 - JAAD

2
我建议您使用现代日期时间API*来完成它。
使用现代API的简单方法是将服务器的日期时间字符串解析为带有服务器时区的ZonedDateTime对象,并将结果对象转换为您可以与Instant#now进行比较的Instant
演示:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // An arbitrary date for demo
        String strDateTime = "2021-05-09 10:20:30";

        // Replace JVM's default time zone, ZoneId.systemDefault() with applicable time
        // zone e.g. ZoneId.of("America/New_York")
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH)
                                    .withZone(ZoneId.systemDefault());

        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);

        Instant instantServer = zdt.toInstant();
        Instant now = Instant.now();

        if (instantServer.isBefore(now))
            System.out.println("The server time is before the current time.");
        else if (instantServer.isAfter(now))
            System.out.println("The server time is after the current time.");
        else
            System.out.println("The server time is the same as the current time.");
    }
}

在我的系统上运行它时的输出:
The server time is before the current time.

了解有关现代日期时间 API*的更多信息,请访问教程:日期时间
* 如果由于任何原因,您必须坚持使用Java 6或Java 7,则可以使用ThreeTen-Backport,该工具将大部分java.time功能迁移至Java 6和7。如果您正在为Android项目工作,并且您的Android API级别仍不符合Java-8,请查看通过解糖使用Java 8+ APIs如何在Android项目中使用ThreeTenABP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接