【问题标题】:Countdown adds one hour between April and October倒计时在 4 月和 10 月之间增加一小时
【发布时间】:2021-02-17 08:46:07
【问题描述】:

我正在开发一个简单的倒计时应用程序来告诉我距离某个 GMT 时间还有多长时间。

示例:

输入:01-05-2021-02-00-00

输出:(如果输入的时间是本地时间)72 天 15 小时 21 分钟 49 秒

输出(如果输入的时间是格林威治标准时间):72 天 17 小时 21 分钟 33 秒

...我相信应该是 16 小时而不是 17 小时。

在输入时间为 4 月 1 日至 10 月 31 日之前,一切正常。我给它格林威治标准时间,并将其转换为我的本地(柏林+1)时间。如果输入的时间来自提到的时间间隔,它会显示柏林和格林威治标准时间之间的 +2 小时差异。因为它只在一年中的特定时期(任何一年)都是这样,所以看起来很奇怪,我不知道出了什么问题?

我的代码:

String result = "";
        
        
        String date = input;
        
        SimpleDateFormat date_format = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
        Date target_date = null;
        try {
            target_date = date_format.parse(date);
        } catch (ParseException e) {
          result += e.getMessage(); 
        }
        
        Date now = new Date();      
        
        long secs = 0;
        if(local_time_radio_btn.isSelected()) {
            secs = (target_date.getTime() - now.getTime()) / 1000;
        }else {
            int offset = target_date.getTimezoneOffset();
            long n = 1000 * offset * 60;
            long gmt = target_date.getTime() -n;
            long now_gmt = now.getTime();           
            secs = (gmt - now_gmt) / 1000;
        }
        
        long days = secs / (60*60*24);
        secs = secs % (60*60*24);
        long hours = secs / (60*60);    
        secs = secs % (60*60);
        long mins = secs / 60;
        secs = secs % 60;

        result += days+" days, "+hours+" hours, "+mins+" mins, "+secs +" secs";

【问题讨论】:

  • 不,编辑帖子并不奇怪。这是 StackOverflow 的关键特性之一——任何人都可以改进帖子。我的贡献是让您的帖子更具可读性,并符合网站指南。
  • 如果您认为 wiki 令人毛骨悚然,那么您可能需要考虑避免使用 StackOverflow 和 Wikipedia。
  • @Flimzy 肯定会觉得很糟糕
  • 显而易见的问题:您是否考虑了夏令时(如果适用)?既然我在评论:编辑很好,没有超出规范。
  • @John3136 谢谢! :) 我会检查一下,听起来可能是这样......但是真实性/个性/美不是所有东西都是一样的,主要是避免规范:D

标签: java date time countdown


【解决方案1】:

java.time

我强烈建议您使用现代 Java 日期和时间 API java.time 进行日期和时间工作。

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-uuuu-HH-mm-ss");
    
    String input = "01-05-2021-02-00-00";

    LocalDateTime targetLdt = LocalDateTime.parse(input, formatter);

    // German time case
    ZoneId zone = ZoneId.of("Europe/Berlin");

    ZonedDateTime now = ZonedDateTime.now(zone);
    ZonedDateTime target = targetLdt.atZone(zone);
    long days = ChronoUnit.DAYS.between(now, target);
    ZonedDateTime afterDays = now.plusDays(days);
    Duration timeDiff = Duration.between(afterDays, target);
    
    String result = days + " days, " + timeDiff.toHours() + " hours, "
            + timeDiff.toMinutesPart() + " mins, "
            + timeDiff.toSecondsPart() + " secs";
    
    System.out.println(result);

我刚才运行代码时(2021-02-18T17:23:35.47 in Berlin),输出为:

71 天 8 小时 36 分钟 24 秒

对于 UTC(或 GMT)情况,您只需更改一行:

    // GMT case
    ZoneId zone = ZoneOffset.UTC;

71 天 9 小时 36 分钟 24 秒

你的代码出了什么问题?

首先,不要使用SimpleDateFormatDate,因为它们的设计很差而且已经过时了。即使你坚持使用Date,你也绝对应该远离它的getTimezoneOffset 方法。它自 1997 年以来已被弃用,因为它跨时区工作不可靠。

为什么您的代码在您提到的月份中给出不正确的结果是因为它总是将一天计算为 24 小时。 3 月 28 日,欧盟将过渡到夏令时 (DST),因此这一天只有 23 小时,因此会产生正好 1 小时的误差。今年 10 月 31 日可能会发生相反的过渡(我认为还没有决定,但 Java 认为已经决定了),所以这一天是 25 小时,以平衡之后的日期。直到明年夏天。

这就引出了下一点:不要自己做时间数学。很容易出错。即使你做对了,读者也很难说服自己它是对的。你有一个可靠的日期和时间库,很乐意为你做这件事。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。

【讨论】:

    【解决方案2】:

    您的代码的奇怪之处在于,您首先根据配置为使用本地时区的 SimpleDateFormat 实例解析输入字符串(因此,如果输入是 UTC,则生成的日期是错误的),并且如果这是用户要求的,那么花很多精力将时间点重新调整为 UTC。

    相反,拥有两个 SimpleDateFormat 实例会更清晰、更健壮,一个使用本地时区,一个使用 UTC,例如:

    SimpleDateFormat dateFormatLocal = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
    SimpleDateFormat dateFormatUTC = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
    dateFormatUTC.setTimeZone(TimeZone.getTimeZone("UTC"));
    

    并在解析时选择正确的。

    顺便说一句,您的重新调整代码使用了 Date 类的已弃用功能,例如 getTimezoneOffset(),这是自 Java 1.1 以来应该避免的。

    【讨论】:

    • 谢谢。我已经改了,可能看起来更好,但仍然有两个小时的差异
    • 它的夏令时......因此它应该是 2 小时差异......一切都很好:)
    • @vuktctgck 从您的评论来看,您似乎已经解决了您的问题。如果此答案(或任何其他答案)对您有所帮助,请考虑 voting on and/or accepting the answer。 :)
    • 嗯,说“它会更健壮”然后坚持SimpleDateFormat 对我来说很独特。
    猜你喜欢
    • 2019-09-30
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 2018-06-23
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多