I'm having an issue working with time in Java. I don't really understand how to efficiently solve comparing the time of now and 12 hours before and after
I get a set of starting times for a show from an API and then compare that starting time with LocalTime.now(). It looks something like this:
SimpleDateFormat sdt = new SimpleDateFormat("HH:mm:ss");
String temp = sdt.format(Local.time(now));
LocalTime secondTime = LocalTime.parse(parts1[0]);
LocalTime firstTime = LocalTime.parse(temp);
int diff = (int) ((MINUTES.between(firstDay, secondDay) + 1440) % 1440);
if(diff <= 720){
return true;
}
Where my idea is that if the difference between the two times is smaller than 720 minutes (12 hours) I should get the correct output. And this works for the 12 hours before now. I thought I might need to swap the parameters of .between, to get the other side of the day. That counts it completely wrong (If the time now is 15:00:00 it would accept all the times until 22:00:00 the same day). Is this just a really bad way of comparing two times? Or is it just my math that lacks understanding of what I'm trying to do?
Thanks
Using the 'new' (not that new) Java 8 time API:
Instant now = Instant.now();
Instant hoursAfter = now.plus(12, ChronoUnit.HOURS);
Instant hoursBefore = now.minus(12, ChronoUnit.HOURS);
First, doing this kind of operations on java.time.LocalTime won't work! Or at least only if the time is "12:00:00" …
That is because you will have an over-/underflow when you add/substract 12 hours from any other time.
So your starting point should be to go for java.time.LocalDateTime (at least, although I would go for java.time.Instant). Now you can handle the over-/underflow, as you will get another day when adding or subtracting 12 hours.
How this works is shown in this anwswer: LocalDateTime allows nearly the same operations as Instant.
Related
In my project, I need to find duration of staying outside in office time of an employee from goToVisitTime and returnTime. The main concerning point is goToVisitTime and returnTime both are date (java.util) type [getting from other method, can't change anymore] and styingOutSideTime also must be date (java.util) type. For example:
Date goTOvisitTime = "12:25";
Date returnTime = "14:19";
So, output should be like,
styingOutSideTime = "01:54";
Therefore my method looks like below:
public Date getDiffTime(Date goTOvisitTime, Date returnTime) {
//calculate difference
return styingOutSideTime;
}
I have spent lots of time to determine the solution. I tried to use almost all of Date and Time from Java and Joda Time as well. Additionally, I went through the following links
How to calculate time difference in java?
Java how to calculate time differences
Convert seconds value to hours minutes seconds?
How to get hour/minute difference in java
However, almost all of the solutions are either parameter or return value is a string. additionally, returning either hour or minute only.
First of all, the duration should not be a Date, it should be a java.time.Duration.
If you only want to the hour part and the minute part, you can do it like this:
Duration duration = Duration.between(goTOvisitTime.toInstant(), returnTime.toInstant());
int hours = duration.toHoursPart();
int minutes = duration.toMinutesPart();
String formattedDuration = String.format("%02d:%02d", hours, minutes);
Given an epoch time: eg (1513213212) I should get 1 since its 1 am right now UTC. How would I go about converting it into the hour of the day? Is it possible to do it just using math (division, mod)?
It would be close to impossible to do it by using maths only. (Leap year and all). It's better to use established APIs which will do all the hard work.
You can use following method to do this.
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1513213212* 1000L);
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(cal.get(Calendar.HOUR));//12 hour clock
System.out.println(cal.get(Calendar.HOUR_OF_DAY));//24 hour clock
Use java.time, the modern Java date and time API also known as JSR-310:
LocalTime timeOfDay = Instant.ofEpochSecond(1513213212L)
.atOffset(ZoneOffset.UTC)
.toLocalTime();
System.out.println(timeOfDay);
int hourOfDay = timeOfDay.getHour();
System.out.println(hourOfDay);
This prints:
01:00:12
1
Even if you just wanted to do the math, I would still prefer to use standard library methods for it:
long epochSeconds = 1513213212L;
// convert the seconds to days and back to seconds to get the seconds in a whole number of days
long secondsInWholeDays = TimeUnit.DAYS.toSeconds(TimeUnit.SECONDS.toDays(epochSeconds));
long hourOfDay = TimeUnit.SECONDS.toHours(epochSeconds - secondsInWholeDays);
System.out.println(hourOfDay);
This too prints 1.
Your intention was “Given an epoch time: eg (1513213212) I should get 1 since it’s 1 AM right now UTC.” Which of the above code snippets in your opinion most clearly expresses this intention? This is what I would use for making my pick.
While MadProgrammer is surely correct in his/her comment that date and time arithmetic is complicated and that you should therefore leave it to the date and time API, I believe that this is one of the rare cases where not too complicated math gives the correct answer. It depends on it being safe to ignore the issue of leap seconds, and if going for the math solution, you should make sure to check this assumption. Personally I would not use it anyway.
I'm trying to convert 5007 to HH:mm:ss:SSS, I'm using Netbeans IDE v8.2:
Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
String dateFormatted = formatter.format(date);
But this gives me an incorrect result:
01:00:05:007
^^-------------------------why does it print to me 01 in the hours?
But it should get:
00:00:05:007
^^-------------------------correct result
When I use ideone for example it gives me a correct result:
Any explication about this problem?
I testes with both versions: Java 7 and Java 8.
When you ask for the explanation of your problem I will be honest with you: You are misusing SimpleDateFormat for formatting a duration. It was never meant for this use and is not designed to give you the expected result if you try it anyway. The problem you got is not the only problem you will have. If your duration grows to more than 24 hours, the whole days will not be formatted, so your result will be wrong in a different way.
Apart from that, these days I recommend not using the SimpleDateFormat class at all. Its replacement is java.time.format.DateTimeFormatter, it came out in 2014 and comes with quite fewer negative surprises. It is not a good choice for formatting a duration either, though.
So what is a good choice? I will give you the Java 9 answer first because it is easy:
Duration dur = Duration.ofMillis(5007);
String hmss = String.format("%02d:%02d:%02d:%03d",
dur.toHours(),
dur.toMinutesPart(),
dur.toSecondsPart(),
dur.toMillisPart());
The main advantage isn’t even the ease, it’s the clarity. For example, with this code no one needs to ask the question I asked in a comment, is it a point it time or a duration? The code very clearly states that it is a duration.
For Java 6, 7 and 8, you may still use the Duration class (in Java 6 and 7 through the ThreeTen Backport), but it doesn’t lend itself that easily to formatting, so I think I would resort to using the TimeUnit enum as in the question I had linked to (the link you asked me to remove again):
long millis = 5007;
long hours = TimeUnit.MILLISECONDS.toHours(millis);
millis -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
millis -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
millis -= TimeUnit.SECONDS.toMillis(seconds);
String hmss = String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, millis);
The result is the desired
00:00:05:007
To illustrate the point I was trying to make about what happens when the duration is more than 24 hours, let’s try to give it 100 000 000 milliseconds (there are 86 400 000 millis in a day):
27:46:40:000
Date date = new Date(5007);
creates a Date which is 5007 milliseconds after January 1, 1970, 00:00:00 GMT.
When you format it with SimpleDateFormat, it is converted to your machine's timezone (which I'm assuming is GMT+1).
When I run your code I get
02:00:05:007
And my timezone is GMT+2.
If you set the timezone of the DateFormat instance to GMT, you'll get the expected output:
Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
formatter.setTimeZone (TimeZone.getTimeZone ("GMT"));
String dateFormatted = formatter.format(date);
System.out.println (dateFormatted);
This prints
00:00:05:007
It is definitely a Locale issue. When you do not specify one it will use the (your system) default one. To override this;
try either adding this
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
or passing a Locale when constructing the SimpleDateFormat instance. For example:
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS", Locale.ENGLISH);
I assume Locale.ENGLISH has UTC timezone btw, but I hope you get the idea.
I have two times in hours and minutes.
time[0]: hour1
time[1]: minutes1
time[2]: hour2
time[3]: minutes2
I've created this formula to calculate the difference in time in minutes:
((time[2] % 12 - time[0] % 12) * 60) + (time[3] - time[1])
I was wondering if there are any edge cases to this. In addition, what is the paradigm you would follow to create this formula (although it is very basic)?
You could express your times with the Date class instead, then calculate the difference and then express it in the time unit of your choice.
With this method, you will avoid a lot of tricky cases (difference between two times on two different days, time change, etc.).
I recommend you the reading of this post and this post but there are many answers to this same exact question on StackOverflow ;)
Note: before using Date, have a look to this excellent post: What's wrong with Java Date & Time API?
Your code assumes days are 24 hours long. Not all days are 24-hours long. Anomalies such as Daylight Saving Time (DST) mean days vary in length.
Also, we have classes already built for this. No need to roll your own. The LocalTime class represents a time-of-day without a date and without a time zone. A Duration represents a span of time not attached to the timeline.
LocalTime start = LocalTime.of( 8 , 0 ) ;
LocalTime stop = LocalTime.of( 14 , 0 ) ;
Duration d = Duration.between( start , stop );
long minutes = d.toMinutes() ; // Entire duration as a total number of minutes.
That code too pretends that days are 24 hours long.
For realistic spans of time, use the ZonedDateTime class to include a date and time zone along with your time-of-day.
We're using MySQL to store some dates. I'm looking to show these as relative time periods in the user interface: 2 hours ago, 3 days ago etc. (Like Twitter does for the updates for example)
Is there a well-known way to accomplish this, or should I get creative with it?
Just to be clear, I want to transform:
07/26/2009 12:20 -> '2 days ago'
As I understand your problem, the "Human Time" class is a solution.
check Date Formatting and Parsing for Humans in Java with HumanTime
.
I would take a look at the Joda library for performing this type of date-time arithmetic. For example, you could create a Joda Duration and then convert it to a Period, giving you access to numerous useful methods:
ResultSet rs = ...
Date dbDate = rs.getDate("Date"); // Get stored time in database.
long serverTime = System.currentTimeMillis(); // Get current server time.
// Compute absolute difference between two time-stamps.
Duration duration = new Duration(Math.abs(serverTime - dbDate.getTime()));
// Convert to period and make use of getHours(), getMinutes(), etc for display purposes.
Period period = duration.toPeriod();
System.err.println("Hours: " + period.getHours());
System.err.println("Minutes: " + period.getMinutes()); // etc.
The Java standard API method for date calculations is Calendar.add() (which also takes negative parameters).
I think the most common solution is to convert it to unix timestamps (or equivalent, milliseconds in Java normally), take the difference and start dividing away.
time = now - then;
time /= 1000; /* if milliseconds... */
seconds = time % 60; time /= 60;
minutes = time % 60; time /= 60;
hours = time % 60; time /= 60;
days = time % 24; time /= 24;
weeks = time % 7; time /= 7;
or months (although, then it starts to get tricky...), or whatever you want to use.
Have fun.
My advice is run your server in UTC and then use JodaTime to do any date arithmetic or conversion between timezones.
There's considerably more to date arithmetic than meets the eye once you factor in things like DSL, leap-seconds, convention changes, etc and it's really the last thing you want to be doing yourself.
The question is rather vague.
In Java, using JodaTime Date API;
3 days ago:
DateTime date = new DateTime();
DateTime threeDA = date.plusDays(-3);
int daysBetween = Days.daysBetween(dbDate, threeDA).getDays();
int monthsBetween = Months.monthsBetween(dbDate, threeDA).getMonths();
or you could use the JodaTime Period/Duration objects.
In MySQL, use a built-in MySQL Date Function e.g.:
SELECT SUBTIME(SYSDATE(),'3'); -- untested, no MySQL to hand
SELECT SUBTIME('2007-12-31 23:59:59.999999','3 0:0:0.000000');
For date differences:
SELECT DATEDIFF(columnname, SYSDATE()); -- Days since
SELECT TIMEDIFF(columnname, SYSDATE()); -- Time since
In Java, using Gregorian Calendar:
GregorianCalendar threeDA = new GregorianCalendar();
threeDA.add(GregorianCalendar.DAY_OF_YEAR, -3);
If you can use java for the conversion, have a look at the Joda library.
On the MySQL side:
CONVERT('date-time-value-here', DATETIME) - NOW()