2

I have the following snippet of code that determines if a job is within its runtimes:

private boolean isDuringRuntime(Job job) {

    Date now = new Date();

    System.out.println(DateUtil.getToday());
    System.out.println(job.getStartTime().toString());
    System.out.println(job.getEndTime().toString());

    Date startTime = new Date(job.getStartTime().getTime() 
                                      + DateUtil.getToday().getTime());

    Date endTime = new Date(job.getEndTime().getTime() 
                                      + DateUtil.getToday().getTime());


    System.out.println("Start Time: " + startTime.toString());
    System.out.println("Stop Time: " + endTime.toString());

    return now.after(startTime) && now.before(endTime);
}

DateUtil.getToday()

public static Date getToday() {
    Date now = new Date();
    Calendar cal = Calendar.getInstance();
    cal.setTime(now);

    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    return cal.getTime();
}

Here is the output of one run:

Sun Jul 14 00:00:00 EDT 2013 //This is DateUtil.getToday();
1970-01-01 13:15:00.0  //Raw Start Time
1970-01-01 18:15:00.0  //Raw End Time
Start Time: Sun Jul 14 18:15:00 EDT 2013  //Computed Start Time 
Stop Time: Sun Jul 14 23:15:00 EDT 2013   //Computed End Time

I am not sure why the computed start time and computed end times are five hours ahead. I would expect that Start Time would be Sun Jul 14 13:15:00 EDT 2013 and End Time would be Sun Jul 14 18:15:00 EDT 2013.

Can anyone point out where I am going wrong? I'm not intimately familiar with Date and I suspect I'm overlooking something simple.

Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • 1
    It is formatted using your device's timezone. Are you ahead of 5 hours from GMT? – Wand Maker Jul 14 '13 at 18:24
  • I'm EDT. But I read that `java.util.Date` doesn't take timezone into consideration, here: http://stackoverflow.com/a/2892156/714969 Does it take this into consideration in the constructor? – Kevin Bowersox Jul 14 '13 at 18:25
  • Could you provide the code of DateUtil.getToday() and job.getStartTime()? Also, you're printing the start and end time of `followJob`, but you're adding the start and end times of `job` to today. – JB Nizet Jul 14 '13 at 18:26
  • @JBNizet I provided `getToday()`. `getStartTime` is an accessor that retrieves a MySql `DATETIME` via Hibernate (JPA), which is stored in a `Date` field – Kevin Bowersox Jul 14 '13 at 18:30
  • Oh, I see now, `getToday()` is using Calendar which defaults to my timezone, so when I call `getTime` it accounts for the difference. The problem is I use this method in other places. Wow, I always heard Time & Date were a mess in Java, I think I'm starting to experience it. – Kevin Bowersox Jul 14 '13 at 18:31
  • 1
    Yes, Date is time zone independent, but toString() method may not be, it always uses default locale. Try Date.toGMTString() and see what values it prints – Wand Maker Jul 14 '13 at 18:31
  • @DavidPitre How is that answer applicable? I want the date without time information in `getToday()` – Kevin Bowersox Jul 14 '13 at 18:32
  • @KevinBowersox: How could it be a Date (I assume java.sql.Date) and have Time information printed? Also, please tell us if followJob is a typo, because that might just be the problem: you're looking at two different information and thinking it's the same. – JB Nizet Jul 14 '13 at 18:34
  • @JBNizet First, followJob is a typo. An error creating a SCCE. Second, doesn't `java.util.Date` contain time info as well? The startTime field on Job is of type `java.util.Date`, so is EndTime. – Kevin Bowersox Jul 14 '13 at 18:37
  • So, its actual type is java.sql.Timestamp, I guess? – JB Nizet Jul 14 '13 at 18:44
  • @JBNizet The type of the field is `java.util.Date` or are you saying I'm getting returned a `java.sql.Date` and its working because it extends `java.util.Date` ? – Kevin Bowersox Jul 14 '13 at 18:44
  • What's the goal here? To add a given offset to the beginning of today? I don't understand why you want to _add_ a Date to the beginning of today. What is supposed to be returned by `job.getStartDate()`? A real date or a relative offset? Seems like you should be storing/adding timestamps (stored as milliseconds) rather than dates. – jahroy Jul 14 '13 at 18:51
  • @jahroy That is the goal. To say this job runs between, say 3 and 6 everyday. So I want to store those times in the database. It appears I'm doing that incorrectly. So lets say I switch over to the timestamp in the database, then what type of field would I use in java? – Kevin Bowersox Jul 14 '13 at 18:53
  • I think you should store a `long` in your database that represents the number of milliseconds into the day at which your jobs should run. You should always use millis for date/time math... Starting to type an answer. – jahroy Jul 14 '13 at 18:53

2 Answers2

2

What is the meaning of the Date fields in your job object?

I get the feeling you're trying to represent a "time of day" with a date object.

This is probably not a good idea.

If you want a job to run 6 hours into the day, I would store a long that represents 6 hours in millis:

static final long ONE_HOUR = 1000L * 60L * 60L;

Date today = DateUtil.getToday();
Date todayExecTime = new Date(today.getTime() + 6 * ONE_HOUR);

Of course, if your locale uses daylight saving time, this method could be off by an hour twice per year (if your exec time is after the change in time, which is usually early in the morning). If you just want JobA to run 6 hours into the day (rather than running at 6:00AM) it won't matter.


If this is a small piece of a more complicated scheduling system, you might want to look into using a library.

I've never used one, but I hear people talking about Quartz all the time.

jahroy
  • 22,322
  • 9
  • 59
  • 108
  • I'm almost too ashamed to admit this, but this method is being called within a Quartz job. The job needs to execute every 15 minutes between certain hours (varies by job). I didn't think I could do this with a cron trigger. – Kevin Bowersox Jul 14 '13 at 19:15
  • @KevinBowersox - If you need that (run job every 15 minutes) you might look into a [TimerTask](http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html), some of the [new concurrency APIs](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html), or even an [EJB timer](http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html) (depending on what frameworks you're using). Is this a web-app using EJB by any chance? – jahroy Jul 14 '13 at 19:24
  • Its a web app using Spring – Kevin Bowersox Jul 14 '13 at 19:25
  • Thanks for the suggestions & answer I am pretty far along and at this point I am locked into quartz – Kevin Bowersox Jul 14 '13 at 19:31
  • @KevinBowersox - You're probably quite familiar with this already (my apologies if so), but [this](http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html) looks very appropriate for what you're describing (maybe it can work alongside Quartz, too). – jahroy Jul 14 '13 at 19:32
1

Understand that Dates do not wrap fully localized datetimes that reflect the current reportable time in your locale.

A Date is a (mutable) wrapper around a long integer that is the number of milliseconds that have elapsed since January 1, 1970 UTC. Note that the long reflects UTC (as best as your system understand it, but almost all systems these days are synchronized after a fashion with some kind of network time service), and not your time zone.

When mapping a Date to a localized datetime string, you'll need to make sure that the Calendar that you are using knows that it needs to map from UTC to, say, EST (plus or minus DST if applicable). The problem you're describing sounds like a time zone mapping issue, and the Calendar instance you create is not initialized with a TimeZone.

scottb
  • 9,908
  • 3
  • 40
  • 56