date.getTime() is shorter than System.getCurrentTimeMillis()

I'm trying to create a simple Alarm Clock, but I stumbled upon a problem that I can't seem to fix. I'm trying to parse a string to a date so I can get the difference between the current time and the time to set off the alarm.

Here's my code to parse the time:

SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
sdf.setTimeZone(getTimezone());

Date date = sdf.parse(args[0]);

Here's my getTimezone() method:

public static TimeZone getTimezone() {
    Calendar cal = Calendar.getInstance();
    long milliDiff = cal.get(Calendar.ZONE_OFFSET);

    String [] ids = TimeZone.getAvailableIDs();
    String name = null;
    for (String id : ids) {
      TimeZone tz = TimeZone.getTimeZone(id);
      if (tz.getRawOffset() == milliDiff) {
        // Found a match.
        name = id;
        break;
      }
    }
    return TimeZone.getTimeZone(name);
}

And here's my code for figuring out the difference:

long diff = date.getTime() - System.currentTimeMillis();

So my problem is that the date.getTime() returns 79680000, while System.currentTimeMillis() returns 1473538047978 (This is of course different every time, but for some odd reason, date.getTime() is not).

Which means that I get a negative number when trying to figure out the difference, and therefore I cannot use it.

EDIT: After a little bit of debugging, I realised that it has to do with the year, month and day not being set, however I do not know how to get those.

Upvotes: 1

Views: 726

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 339422

The accepted answer by Ronin is correct. You are trying to put a time-of-day value into a date-time type.

java.time

Also, you are using troublesome old legacy date-time classes. Now supplanted by the java.time classes.

For a time-of-day value without a date and without a time zone, use LocalTime.

LocalTime alarmTime = LocalTime.parse( "12:34" );

Getting current time-of-day requires a time zone.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalTime now = LocalTime.now( z );

But since we are setting an alarm, we care about the date too.

ZonedDateTime now = ZonedDateTime.now( z );
ZonedDateTime alarm = null;
if ( now.toLocalTime().isBefore( alarmTime ) ) {
    alarm = ZonedDateTime.of( now.toLocalDate() , alarmTime , z );
} else {. // Else too late for today, so set alarm for tomorrow.
    alarm = ZonedDateTime.of( now.toLocalDate().plusDays( 1 ) , alarmTime , z );
}

To calculate the elapsed time until the alarm, use the Duration class.

Duration untilAlarm = Duration.between( now , alarm );

You can interrogate the duration for a total number of milliseconds. But know that java.time classes are capable of handling nanoseconds.

long millis = untilAlarm.toMillis();

Upvotes: 1

Wladimir Schmidt
Wladimir Schmidt

Reputation: 274

Updated. You are using only time without a date with you date object in code (parses only time). If you add there date to you time, your date should be comparable to your System.getCurrentTimeMillis() call. And if you subtracting current millis from date in the past, you will have negative numbers. I prefer this convertion (date2 is after date1):

long diffInMillies = date2.getTime() - date1.getTime();
return TimeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);

Upvotes: 0

pr0gramista
pr0gramista

Reputation: 9038

You did notice that date.getTime() returns 79680000 which is 22 hours and 20 minutes after 1 January 1970. The problem is (as you noticed) that you did not parse year, month and day.

You can do it by:

SimpleDateFormat sdf = new SimpleDateFormat("DD/MM/YYYY hh:mm:ss"); 

Example input 20/04/2016 20:20:0 returns time as Mon Jan 04 20:20:00 CET 2016 (don't look at the timezone). It is 1451935200000 miliseconds after 1 January 1970.

Note: change string to match your format requirements (the syntax is self-explanatory).

Upvotes: 3

Related Questions