Android使用时区检查打开和关闭时间之间是不是已经过去

Posted

技术标签:

【中文标题】Android使用时区检查打开和关闭时间之间是不是已经过去【英文标题】:Android check if between open and closing time has elapsed using timezoneAndroid使用时区检查打开和关闭时间之间是否已经过去 【发布时间】:2021-10-28 15:30:06 【问题描述】:

如何在 android 中检查两次之间的时间? 我有开放时间和关闭时间,我想使用特定的国家时区检查关闭时间是否已经过去。

 public void timeElapse(String start, String end, String tz)
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm aa", Locale.getDefault());
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm\\aa", Locale.getDefault());
        try 
            sdf.setTimeZone(tzs);
            Date currentTimeDate = sdf.parse(start);
            Date endTimeDate = sdf.parse(end);
            int a = currentTimeDate.compareTo(endTimeDate); // false / current time has not passed end time.
            int b = endTimeDate.compareTo(currentTimeDate); // true / end time has passed current time.

            Log.e("timeElapse", "("+end+") A = " + a + " B = " + b);
         catch (ParseException ignored) 

        
    

第二次尝试

public void timeElapse(String start, String end, String tz)
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm\\aa", Locale.getDefault());
    try 
        TimeZone tzs = TimeZone.getTimeZone(tz);
        sdf.setTimeZone(tzs);
        long currentTimeDate = sdf.parse(start).getTime();
        long endTimeDate = sdf.parse(end).getTime();
        if(currentTimeDate>endTimeDate)
            Log.e("timeElapse", "Time has passed");
        else
            Log.e("timeElapse", "You are on time");
        
     catch (ParseException ignored) 

    

用法

timeElapse("10:00AM", "10:00PM", "Asia/Kuala_Lumpur");
timeElapse("10:00AM", "12:00PM", "Asia/Kuala_Lumpur");
timeElapse("11:30AM", "05:00PM", "Asia/Kuala_Lumpur");
timeElapse("10:00AM", "01:00AM", "Asia/Kuala_Lumpur");

我的代码不起作用。我收到错误 java.text.ParseException: Unparseable date: "10:00AM"

【问题讨论】:

一般情况下,您将时间保存在单个时区(通常为 UTC)中,并将当前时区转换为 UTC 以进行比较。将所有数据保存在一个时区中可以使代码更易于理解,并减少将来出现问题的可能性。 @GabeSechan 你能举个例子吗? 顺便考虑扔掉长期过时且臭名昭著的麻烦SimpleDateFormat和朋友。看看您是否可以使用desugaring 或将ThreeTenABP 添加到您的Android 项目中,以便使用现代Java 日期和时间API 的java.time。使用起来感觉好多了。 您的尝试是否按预期工作?如果您得到任何意想不到的结果,请为我们说明。 @OleV.V.我的代码不起作用我收到错误java.text.ParseException: Unparseable date: "10:00AM" 【参考方案1】:

java.time 脱糖

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

在仔细阅读问题后对代码进行了编辑。

private static final DateTimeFormatter TIME_PARSER
        = DateTimeFormatter.ofPattern("hh:mma", Locale.ENGLISH);

public static void timeElapse(String start, String end) 
    LocalTime currentTime = LocalTime.parse(start, TIME_PARSER);
    LocalTime endTime = LocalTime.parse(end, TIME_PARSER);
    if (currentTime.isAfter(endTime)) 
        System.out.println("Time has passed");
     else 
        System.out.println("You are on time");
    

代码不是很容易解释吗?这是我觉得 java.time 不错的一件事。并且在 cmets 中已经暗示,我们不需要时区(极端情况除外)。所以我省略了第三个参数。让我们用你的例子来试试吧:

    timeElapse("10:00AM", "10:00PM");
    timeElapse("10:00AM", "12:00PM");
    timeElapse("11:30AM", "05:00PM");
    timeElapse("10:00AM", "01:00AM");

输出是:

You are on time
You are on time
You are on time
Time has passed

时区不重要吗?如果您的时间落入回退中,时钟倒转并且相同的时钟小时重复,我们将无法判断哪个更早。我上面的代码没有考虑这种极端情况,为此,我们也需要知道日期。

原码

private static final DateTimeFormatter TIME_PARSER
        = DateTimeFormatter.ofPattern("hh:mma", Locale.ENGLISH);

public static void timeElapse(String start, String end, String tz)
    LocalTime startTime = LocalTime.parse(start, TIME_PARSER);
    LocalTime endTime = LocalTime.parse(end, TIME_PARSER);
    LocalTime now = LocalTime.now(ZoneId.of(tz));
    if (now.isBefore(startTime)) 
        System.out.println("Not open yet");
     else if (now.isAfter(endTime)) 
        System.out.println("Time has passed");
     else 
        System.out.println("You are on time");
    

代码不是很容易解释吗?这是我觉得 java.time 不错的一件事。让我们用你的例子来试试吧:

    timeElapse("10:00AM", "10:00PM", "Asia/Kuala_Lumpur");
    timeElapse("10:00AM", "12:00PM", "Asia/Kuala_Lumpur");
    timeElapse("11:30AM", "05:00PM", "Asia/Kuala_Lumpur");
    timeElapse("10:00AM", "01:00AM", "Asia/Kuala_Lumpur");

我在马来西亚凌晨 2 点 15 分左右运行了这段代码,所以正如预期的那样,输出有点枯燥:

Not open yet
Not open yet
Not open yet
Not open yet

我们也试试:

    timeElapse("12:00AM", "03:00AM", "Asia/Kuala_Lumpur");
    timeElapse("01:00AM", "02:00AM", "Asia/Kuala_Lumpur");
You are on time
Time has passed

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

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

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

你的代码出了什么问题?

您在格式模式字符串中的分钟和 AM/PM 标记之间有一个反斜杠:"hh:mm\\aa"。这需要在您的时间字符串中使用反斜杠,但它们就像"10:00AM",即没有任何反斜杠。我相信这导致了您的ParseException。为格式化程序指定 Locale.getDefault() 也可能存在问题。 AM 和 PM 在英语以外的其他语言中几乎不使用,但在某些语言中确实有其他名称(文本)。您要求文本使用 JVM(和您的设备)的默认语言。

另外请注意,如果您想将解析的时间与现在的时间进行比较,使用 java.time 很容易。它不适用于DateSimpleDateFormatSimpleDateFormat 将每个字符串解析为 1970 年 1 月 1 日的指定时间,因此与现在的时间比较没有意义。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。 Java Specification Request (JSR) 310,其中首次描述了 java.time。 ThreeTen Backport project,java.time 的向后移植到 Java 6 和 7(JSR-310 的 ThreeTen)。 Java 8+ APIs available through desugaring ThreeTenABP,Android 版 ThreeTen Backport Question: How to use ThreeTenABP in Android Project,解释得很透彻。

【讨论】:

这很好,但有一点我注意到timeElapse("10:00AM", "05:00AM", "Asia/Kuala_Lumpur"),当在10AM 附近打开并在5AM 附近关闭时,它总是显示未打开。有什么办法可以查到关门时间是不是隔天? @Peter 只是有点复杂。参见例如Check if a given time lies between two times regardless of date。如果您需要更多,请搜索更多。

以上是关于Android使用时区检查打开和关闭时间之间是不是已经过去的主要内容,如果未能解决你的问题,请参考以下文章

android如何修改时区

如何检查设备是不是有闪光灯 LED android

安卓手机怎样更新时间?

JavaScript 检查时区名称是不是有效

如何检查到 UNIX 时间戳之间是不是有时间变化

检查打开的窗口是不是已关闭