定时器倒计时为负

时间:2017-04-03 00:41:16

标签: java date timer calendar countdown

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

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

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

      }

  }

1 个答案:

答案 0 :(得分:1)

避免遗留日期时间classe

你工作太辛苦了。而且你正在使用麻烦的旧日期时间类,现在已经过时并被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

仅供参考,TimerTimeTask类已被Executors框架取代。专门为您的目的,ScheduledExecutorService。搜索Stack Overflow以获取许多示例和讨论。

关于java.time

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

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore