【问题标题】:Compare Date using GregorianCalendar使用 GregorianCalendar 比较日期
【发布时间】:2016-09-13 21:47:53
【问题描述】:

我正在尝试将当前日期 (2016-08-31) 与给定日期 (2016-08-31) 进行比较。 我当前的移动设备时区是 GMT-08:00 太平洋时间。

如果我在设备上禁用自动日期和时区并将时区设置为 GMT+08:00 Perth,method1 将返回 true,但 method2 返回 false;

method2的结果是预期的,因为我比较了没有时区的日期,所以“2016-08-31”之前的“2​​016-08-31”是假的;为什么method1返回true?

    public boolean method1() {
        try {
            GregorianCalendar currentCalendar = new GregorianCalendar();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date endDate = sdf.parse("2016-08-31");
            Calendar endCalendar = new GregorianCalendar();
            endCalendar.setTime(endDate);

            if (endCalendar.before(currentCalendar)) {
                return true;
            } else {
                return false;
            }
        } catch (ParseException e) {
            ...
        }
    }


    public boolean method2() {    
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date currentDate = sdf.parse(formatter.format(new Date())); 
            Date endDate = sdf.parse("2016-08-31");

            if (endDate.before(currentDate)) {
                return true;
            } else {
                return false;
            }

        } catch (ParseException e) {
            ...
        }
    }

【问题讨论】:

    标签: android date gregorian-calendar


    【解决方案1】:

    有和没有时区

    可能的解释:您的代码混合使用分区和 UTC 日期时间对象。在某些行中,您为对象分配了时区 (java.util.Calendar),即 JVM 当前的默认时区。在其他行中,您有一个对象 (java.util.Date) 固定在 UTC 中。 Australia/Perth 时区比 UTC 早 8 小时,因此您当然可以看到日期的差异。打印出它们的自纪元以来的毫秒数将使比较结果变得明显。

    帮自己一个个忙:避免这些臭名昭著的麻烦的旧课程。请改用 java.time。

    Boolean isFuture = 
        LocalDate.parse( "2016-08-31" )
                 .isAfter( LocalDate.now( ZoneId.of( "Australia/Perth" ) ) ) ;
    

    使用 java.time

    您正在使用麻烦的旧日期时间类,现在已被 java.time 类所取代。

    获取当前日期需要时区。对于任何给定的时刻,日期在全球范围内因区域而异。如果省略,则隐式应用 JVM 当前的默认时区。最好指定,因为该默认值可以随时更改。

    指定proper time zone name。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

    ZoneId z = ZoneId.of( "Australia/Perth" ) ;
    

    LocalDate 类表示没有时间和时区的仅日期值。

    LocalDate today = LocalDate.now( z );
    

    您的输入字符串恰好符合标准 ISO 8601 格式。所以直接用LocalDate解析。无需指定格式模式。

    LocalDate ld = LocalDate.parse( "2016-08-31" );
    

    isBeforeisAfterisEqualcompareTo 比较。

    Boolean isFuture = ld.isAfter( today );
    

    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date.Calendarjava.text.SimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

    大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 等等。

    【讨论】:

    • 谢谢@Basil Bourque,非常详细。
    猜你喜欢
    • 1970-01-01
    • 2021-05-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    相关资源
    最近更新 更多