Reputation: 69
I was creating a masterpiece today in java and I needed to calcualte the difference between two times.
So I used Time.getTime()
to get long values of the times and subtracted them to get what I want ...
This is my test code :
public static void main(String[] args) {
Time time = new Time(00,00,00);
Time time2 = new Time(02,00,00);
long longTime = (time2.getTime() - time.getTime());
Time finalTime = new Time(longTime);
System.out.println(finalTime.toString());
}
Now Apparently the printed out string must be 02:00:00
But I am always getting 04:00:00
I tried to change the times a lot , I am always getting the time increased by two hours and I couldn't know why.
I even tried to subtract 00:00:00 and 00:00:00
and instead of getting 00:00:00
I got 02:00:00
So , any help for me ???
Upvotes: 4
Views: 1226
Reputation: 9544
The issue is that at the moment you print the time it is getting converted to your timezone. Basically timezones are for presentation only, not the way dates get stored. You have to display your time for GMT and then it will give you what you want. Like this:
Time time = new Time(00,00,00);
Time time2 = new Time(02,00,00);
long longTime = (time2.getTime() - time.getTime());
Time finalTime = new Time(longTime);
System.out.println(finalTime.toString());
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
//correct one
System.out.println(sdf.format(finalTime));
Also I think you are using the java.sql.Time
class which unless you are doing sql I would guess is the wrong class to use. The Date
class has everything you need, so do the Calendar
classes. Also there are some new java time classes which I haven't used but they look interesting https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
Upvotes: 3
Reputation: 338316
You used a leading zero on a literal number in Java. That means an octal number (base 8) rather than a decimal number (base 10).
You should be using 0
instead of 00
, and 2
instead of 02
.
Not likely the core issue in this particular example as octal zero and two have the same value in decimal.
This issue is moot in my perspective. There is a much better approach to your objective; read on.
The Question and other Answers use the old outmoded date-time classes bundled with the earliest versions of Java. Those old classes have proven to be quite troublesome, flawed, and poorly designed. They have been supplanted in Java 8 and later by the java.time framework. See Tutorial.
The new classes include LocalTime
for a time-of-day value without any date nor any time zone.
Use the LocalTime
class in preference over java.sql.Time
. The java.sql.* classes are intended only for transferring data in and out of databases, not for business logic. In particular, the java.sql.Time
class pretends to have only a time-of-day but actually subclasses from java.util.Date
(a hacked class design), so internally it does have a date and time zone (both UTC and another time zone buried in source code but ignored for some purposes) as well. Confused? As I said, the old date-time classes are a mess and should be avoided; use only where absolutely necessary and as briefly as possible.
Immediately after transfer, convert the java.sql type to a java.time type. The java.sql.Time
class offers the toLocalTime
method for convenient conversion.
LocalTime localTime = myJavaSqlTime.toLocalTime();
Seems that your Question is about determining the elapsed time between a pair of time-of-days.
Keep in mind the issues in determining elapsed time without a date. We must assume generic 24-hour long day while ignoring Daylight Saving Time (DST) or other anomalies that occur in the real world. And we must assume these are occurring within the same day, or rolling over into the next 24-hour clock. So generally, you are better off with actual moments on the timeline represented as Instant
, ZonedDateTime
, or OffsetDateTime
.
The java.time framework offers the Duration
class to represent a span of time as a number of whole seconds plus a fraction of a second in nanoseconds.
Let’s simulate getting a pair of values from the database by assuming you have retrieved java.sql.Time objects and converted them to java.time.LocalTime objects.
LocalTime start = LocalTime.of ( 0 , 0 , 0 ); // First moment of the day.
LocalTime stop = LocalTime.of ( 2 , 0 , 0 ); // 2 AM.
Calculate a span of time as a number of hours, minutes, and seconds.
Duration duration = Duration.between ( start , stop );
Dump to console.
System.out.println ( "start: " + start + " | stop: " + stop + " | duration: " + duration );
Note how the output of the implicit call to LocalTime::toString
uses the standard ISO 8601 format of PnYnMnDTnHnMnS
. In our case, PT2H
means “two hours”. The java.time classes can both parse and generate in the ISO 8601 formats. This standard format is much more sensible that using the ambiguous 02:00:00
which cannot be distinguished from a time-of-day.
start: 00:00 | stop: 02:00 | duration: PT2H
If you want numbers, you may get a total number of seconds in the duration. Remember that a Duration may include a fractional second of nanoseconds as well that is ignored by getting whole seconds.
long seconds = duration.get ( ChronoUnit.SECONDS ); // 7,200 seconds in 2 hours.
Or call the to
methods, such as toHours
or toMinutes
to get the duration as a total number of those units.
If you meant to apply these generic time-of-day values to a particular date to get an actual moment on the timeline, search Stack Overflow as that has been covered.
Upvotes: 0
Reputation: 69
Here is the deal ...
First of all if it is possible , I suggest to not use the class Time as its methods are mostly deprecated.
Instead try to use Date class or Duration and Instant https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
If you have to stick with this class for now , here is the trick.
The constructor new Time(long)
takes the timezone offset in consideration ...
So if you are at +02 timezone ... your time object will be increased in 120 minutes.
To solve this you can use Time.getTimezoneOffset()
This method will return an integer with the number of minutes from your timezone
I edited my code to this and now it is working properly:
public static void main(String[] args) {
Time time = new Time(00,00,00);
Time time2 = new Time(02,00,00);
long longTime = (time2.getTime() - time.getTime());
Time finalTime = new Time(longTime);
int timeOffset = time.getTimezoneOffset();
finalTime.setMinutes(finalTime.getMinutes()+timeOffset);
System.out.println(finalTime.toString());
}
Upvotes: 0
Reputation: 969
Here is a way to do what you are trying to do using GregorianCalendar:
Calendar time = new GregorianCalendar();
Calendar time2 = new GregorianCalendar();
time2.add(GregorianCalendar.HOUR, 2);
System.out.println(time2.getTimeInMillis() - time.getTimeInMillis());
Upvotes: 1
Reputation: 545
The Time-constructor new Time(long)
uses your timezone.
So your longTime
is 60*60*2*1000=7200000 as you expect.
But new Time(7200000)
will take 1. January 1970 00:00:00 UTC/GMT + 7200000 as it's new date, so it is shifted by your timezone.
For me, your code prints: 03:00:00. new Time(int, int, int)
is deprecated and should not be used.
So if possible, I would suggest to not use the old date&time stuff and use either jodatime or java8: Do we have a TimeSpan sort of class in Java
Upvotes: 1