Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 计时器倒计时为负数_Java_Date_Timer_Calendar_Countdown - Fatal编程技术网

Java 计时器倒计时为负数

Java 计时器倒计时为负数,java,date,timer,calendar,countdown,Java,Date,Timer,Calendar,Countdown,我有一个用于创建24小时倒计时的代码 此代码检查日期文件是否存在,如果不存在,则创建一个日期文件,其中包含24小时/天的日期和时间。然后获取当前时间并比较两者,以创建从当前日期到文档中日期的倒计时 这样就可以保存计时器,并检查它已经走了多远,即使代码已关闭。唯一的问题是,有时计时器会转为负数。比如,如果我从一开始就运行代码,没有在周一创建日期文件,就在午夜之前,比如周一晚上11点半。然后,如果我停止代码并在当前日期已过午夜时再次运行它,那么实际上是星期二,但在它到达实际目标计时器之前,仍然缺少多

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

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

这样就可以保存计时器,并检查它已经走了多远,即使代码已关闭。唯一的问题是,有时计时器会转为负数。比如,如果我从一开始就运行代码,没有在周一创建日期文件,就在午夜之前,比如周一晚上11点半。然后,如果我停止代码并在当前日期已过午夜时再次运行它,那么实际上是星期二,但在它到达实际目标计时器之前,仍然缺少多达23个小时。如果是这种情况,倒计时中剩余的时间是负数。就像它会显示的那样-1天23小时60分60秒。但如果作为一个例子,它在周二午夜之后从头开始运行,然后在当天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

瞬间 该类表示时间线上的某个时刻,分辨率高达9位小数

Instant instantNow = Instant.now();
期间 未附加到时间线的时间跨度由Duration或Period类表示

您可以执行日期-时间数学,将持续时间添加到瞬间。time类使用不可变对象,因此这种操作的结果是一个新对象,其值基于原始对象

Instant instantLater = instantNow.plus( duration );
ISO 8601 要将日期-时间值(如文本)序列化,请使用标准格式。在生成和解析字符串时,java.time类默认使用ISO8601

String output = instantNow.toString(); 
2017-04-03T03:18:48.183Z

计算剩余时间 要获得剩余的时间,让java.time进行计算

Duration remaining = Duration.between( Instant.now() , instantLater );
要以标准ISO 8601格式报告,请调用toString。这是PnYnMnDTnHnMnS。P标记周期的开始,T将任何年、月、日期和时、分、秒分开

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

为了生成更长的字符串,在Java9中,每单位小时、分钟、秒调用To…Part方法。奇怪的是,这些方法在Java8的原始java.time.Duration类中被省略了。您可以参考Java9的源代码来编写类似的代码

或者更简单地说,操纵标准字符串。删除PT。将H替换为小时,以此类推。先做S以避免其他两个词中的复数S。诚然,这是一种黑客行为,但幸亏运气好,它的工作原理是字母的英文拼写是小时分秒

String outputRemaining = remaining.toString();
String output = remaining.toString()
                         .replace( "PT" , "" )
                         .replace( "S" , " seconds " )
                         .replace( "H" , " hours " )
                         .replace( "M" , " minutes " ) ;
23小时34分22秒

分区截止时间 如果要在用户所需/预期时区中显示目标日期时间,请应用ZoneId以获取ZonedDateTime对象

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

要生成其他格式的字符串,请在堆栈溢出中搜索类的许多示例

转换为java.util.Date 该类尚未更新,无法使用java.time类型。因此,在本例中,通过添加到旧类中的新方法将其转换回对象

或者使用对象的毫秒计数

ScheduledExecutorService 仅供参考,Timer和TimeTask类已被框架取代。特别是为了您的目的,ScheduledExecutorService。搜索堆栈溢出以获取许多示例和讨论

关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

从哪里获得java.time类

后来 内置的。 标准JavaAPI的一部分,带有捆绑实现。 Java9添加了一些次要功能和修复。 和 大部分java.time功能都在中向后移植到Java6和Java7。 该项目特别针对Android采用了上述Three-Ten Backport。 看见 该项目使用其他类扩展了java.time。该项目是未来可能的addit的试验场
下载到java.time。您可以在这里找到一些有用的类,如、、和。

首先使用Java 8或JodaTime中较新的日期/时间API。如果您使用的是早期版本的Java,它们可以计算两个时间点之间的持续时间。好主意,@MadProgrammer。我不想破译问题中代码末尾附近发生的时间算术。看起来很复杂。只是,我听说如果您不能使用Java8,并且愿意依赖第三方库,那么您应该更喜欢中提到的而不是JodaTime。@OleV.V。这是一个不错的建议,我更喜欢JodaTime,因为它是一个更丰富的API,但这让我非常感谢您对信息的惊人消耗,我接受了您的答案,认为它很可能会解决所有问题。完成后我会给你回复。
java.util.Date date = java.util.Date.from( instantLater );
long milliseconds = duration.toMillis() ;