java - 计时器倒数为负

标签 java date timer calendar countdown

我有一个用于创建24小时倒计时的代码。

此代码检查“日期”文件是否存在,如果不存在,则创建一个文件,其中包含每天24小时的日期和时间。然后,它获取当前时间并进行比较,以创建从当前日期到文档中日期的倒计时。

即使代码已“关闭”,这也可以保存计时器并检查计时器的时间。唯一的问题是计时器有时会变为负数。就像如果我从头开始运行代码时,没有在星期一(午夜之前)创建任何“日期”文件,那么可以说星期一是晚上11点半。然后,如果我停止代码并在当前日期已经过了午夜时再次运行它,那么实际上是星期二,但是在达到实际目标计时器之前,仍然有多达23小时的时间缺失。在这种情况下,倒数时间为负。就像它会显示“ -1day 23hours 60minutes and 60seconds left”。但是,例如,如果从周二午夜开始重新运行,然后在当天30分钟后重新启动,则没有问题。

希望您能理解问题所在,很难通过文字表达。但是我附上了我的全部代码,这是我正在使用的确切代码,并且其中存在这个问题。该代码对每一个发生的动作都有注释,因此应该很容易理解。

static File dFileD = new File("date.txt");
    static String date = "";

  public static void main(String[] args) throws ParseException {

      Timer tickTock = new Timer();
      TimerTask tickTockTask = new TimerTask(){

          public void run(){
              try {
                timFunRun(); //Timer calls method to start the countdown
            } catch (ParseException e) {
                e.printStackTrace();
            }
          }
      };

      tickTock.schedule(tickTockTask, 1000, 1000);

  }

  static void timFunRun() throws ParseException {

      if (!dFileD.exists()){ //if it doesn't exist, first part

          //Get current date and time
          Calendar startDat = Calendar.getInstance();
          System.out.println("Current date: " + startDat.getTime());

          //Get that current date and time and then add 1 day
          Calendar todAdd = Calendar.getInstance();
          todAdd.add(Calendar.DATE, 1);
          System.out.println("Date in 1 day: " + todAdd.getTime());

          //Create a format for sending date to text file
          SimpleDateFormat formDat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
          String formatted = formDat.format(todAdd.getTime());
          System.out.println("Formatted: " + formatted);

          try{
              PrintWriter dW = new PrintWriter("date.txt");
              dW.println(formatted);
              dW.close();
          } catch (IOException e) {
          }

          System.out.println(formDat.parse(formatted));

      } else { //if it does exist, second part

          //Get current date and time
          Calendar currentDeT = Calendar.getInstance();
          System.out.println("Current date: " + currentDeT.getTime());
          SimpleDateFormat formDat2 = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");

          Date dateFroText = null; //Get the "goal" date
          try {
              Scanner dateRead = new Scanner(dFileD);
              while (dateRead.hasNextLine()) {
                  date = dateRead.nextLine();
                  dateFroText = formDat2.parse(date);
                  System.out.println("Date from text new format: " + dateFroText);
              }
              dateRead.close();
            } catch (Exception e) {
                System.out.println("Error!");
            }

          if (dateFroText != null){ //method to compare the current date and the goal date
              Calendar dateFromTxtCal = Calendar.getInstance();
              dateFromTxtCal.setTime(dateFroText);
          int yearDiff = dateFromTxtCal.get(Calendar.YEAR) - currentDeT.get(Calendar.YEAR);
          int dayDiff = ((yearDiff*365) + dateFromTxtCal.get(Calendar.DAY_OF_YEAR)) - currentDeT.get(Calendar.DAY_OF_YEAR);
          dayDiff--;
          int hourDiffer = dateFromTxtCal.get(Calendar.HOUR_OF_DAY)+23 - currentDeT.get(Calendar.HOUR_OF_DAY);
          int minuDiff = dateFromTxtCal.get(Calendar.MINUTE)+60 - currentDeT.get(Calendar.MINUTE);
          int secoDiff = dateFromTxtCal.get(Calendar.SECOND)+60 - currentDeT.get(Calendar.SECOND);
          System.out.println(dayDiff + " days " + hourDiffer + " hours " + minuDiff +" minutes " + secoDiff + "seconds remaining");
          }

      }

  }

最佳答案

避免遗留日期时间类

你太辛苦了而且您正在使用麻烦的旧日期时间类,而现在这些类已经被java.time类取代并取代了。

在UTC工作

另外,如果您只关心接下来的24小时,则无需时区。只需使用UTC。

Instant

Instant类代表UTC在时间轴上的时刻,分辨率为nanoseconds(最多九(9)个十进制小数位)。

Instant instantNow = Instant.now();


Duration

DurationPeriod类表示未附加到时间线上的时间跨度。

Duration duration = Duration.ofHours( 24 );


您可以执行日期时间数学,将Duration添加到Instant。 java.time类使用不可变的对象,因此这种操作的结果是一个具有基于原始值的新鲜对象。

Instant instantLater = instantNow.plus( duration );


ISO 8601

要将日期时间值(例如那些时间值)序列化为文本,请使用标准的ISO 8601格式。生成和解析字符串时,java.time类默认使用ISO 8601。

String output = instantNow.toString(); 



  2017-04-03T03:18:48.183Z


计算剩余时间

要获取剩余时间,请让java.time进行数学运算。

Duration remaining = Duration.between( Instant.now() , instantLater );


要以标准ISO 8601格式报告该事件,请调用toStringformat for durationsPnYnMnDTnHnMnSP标记开始(对于Period),T将任何年-月-日期与小时-分钟-秒分开。

String outputRemaining = remaining.toString();



  PT23H34M22S


要生成更长的字符串,请在Java 9中为每个单位(小时,分钟,秒)调用to…Part方法。奇怪的是,这些方法在Java 8的原始java.time.Duration类中被省略了。您可以查看Java 9的源代码来编写类似的代码。

或更简单地,操作标准字符串。删除PT。将H替换为hours,依此类推。首先执行S以避免在其他两个单词中使用复数s。诚然,这是一种技巧,但由于运气好,因为字母的出现是小时-分钟-秒的英语拼写,所以它可以工作。

String output = remaining.toString()
                         .replace( "PT" , "" )
                         .replace( "S" , " seconds " )
                         .replace( "H" , " hours " )
                         .replace( "M" , " minutes " ) ;



  23小时34分22秒


ZonedDateTime

如果要在用户的期望/期望时区中显示目标日期时间,请应用ZoneId以获取ZonedDateTime对象。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );


要生成标准格式的字符串,请调用toString。实际上,ZonedDateTime类通过将时区的名称附加在方括号中来扩展标准。

要生成其他格式的字符串,请在Stack Overflow中搜索DateTimeFormatter类的许多示例。

转换为java.util.Date

Timer类尚未更新为可与java.time类型一起使用。因此,通过添加到旧类中的新方法(在本例中为Date)转换回from对象。

java.util.Date date = java.util.Date.from( instantLater );


或者使用Duration对象中的毫秒数。

long milliseconds = duration.toMillis() ;


ScheduledExecutorService

仅供参考,Executors框架已取代TimerTimeTask类。专为您的目的,ScheduledExecutorService。搜索堆栈溢出以获取许多示例和讨论。



关于java.time

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

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

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

在哪里获取java.time类?


Java SE 8SE 9及更高版本


内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。

Java SE 6SE 7


ThreeTen-Backport中的许多java.time功能都已反向移植到Java 6和7。

Android


ThreeTenABP项目专为Android改编了ThreeTen-Backport(如上所述)。
请参见How to use ThreeTenABP…



ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

关于java - 计时器倒数为负,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43175049/

相关文章:

java - 这有什么意义呢?

php - 如何用 php/MySQL 做循环日期

sql - SQL 中的四舍五入日期

Android 相当于 javascript 的 setTimeout 和 clearTimeout?

javassist hotswapper 出现错误--- java.lang.ClassNotFoundException : com. sun.jdi.connect.IllegalConnectorArgumentsException

java - twitter4j 程序上出现 "unexpected token: int"错误

iOS:后台任务长度问题设计计时器应用程序+ Apple Watch注意事项

java - 获取到特定时间点的时间

java - 调用事务方法 Play Java JPA Hibernate

ios - 证书截止日期为 28/06/21 如何更新?