Adding time doesn't add up - java

Sorry, but I come to you with a problem that should have been answered already. Alas, my google-foo is weak and I humbly come to ask for your guidance.
WHY DOES AN EXTRA 59 minutes appear??
Ok, so I got a "Clock In" thing going and my calculations go wrong when the persons out minutes are the same as the in minutes. I remember hearing about this problem before, but with no solution. Just a "Well, that's how it is. Good luck, brah." I've tried adding and subtracting minutes during calculation, but that just pushes the problem +/- the time added/subtracted. I've also tried calculating to the second (not shown below), but that also didn't help.
Obligatory, here's my code:
//calculateTotalHours()
public static String calculateTotalHours(Cell inTime, Cell outTime, Cell breakStart, Cell breakEnd)
{
System.out.println(LOG + "calculateTotalHours");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
Date in, out, start, end;
if(null != inTime && null != outTime && null != breakStart && null != breakEnd)
{
try
{
in = timeFormat.parse(inTime.getStringCellValue());
out = timeFormat.parse(outTime.getStringCellValue());
start = timeFormat.parse(breakStart.getStringCellValue());
end = timeFormat.parse(breakEnd.getStringCellValue());
long lunchTotal = end.getTime() - start.getTime();
long totalWork = out.getTime() - in.getTime();
long totalTime = totalWork - lunchTotal;
long diffHours = totalTime/HOURS % 24;
totalTime -= diffHours;
long diffMinutes = totalTime/MINUTES % 60;
totalTime -= diffMinutes;
return String.format("%02d:%02d", diffHours, diffMinutes);
}
catch (ParseException e) {e.printStackTrace();}
}
else
{
try
{
if(null == breakStart || null == breakEnd) {
in = timeFormat.parse(inTime.getStringCellValue());
out = timeFormat.parse(outTime.getStringCellValue());
long totalTime = out.getTime() - in.getTime();
long diffHours = totalTime/HOURS % 24;
totalTime -= diffHours;
long diffMinutes = totalTime/MINUTES % 60;
totalTime -= diffMinutes;
return String.format("%02d:%02d", diffHours, diffMinutes);
}
else if(null == inTime.getStringCellValue())
{
System.out.println(LOG + "inTime is blank");
return "-1";
}
}
catch (ParseException e) {e.printStackTrace();}
}
return "-1";
}
My sincere apologies for the mess I call my code. And let me know if calculating by the second or millisecond is the way to go. I may have overlooked something when trying it that way.
2020 UPDATE:
I wanted to update my code and what I should have done. First, I should have separated the cells, strings, and time more. Second, I should have broken it down to more methods for clarity.
I'll just show getTotalHours(startTimeString, endTimeString):
DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm");
LocalTime end = LocalTime.parse(endTimeString.trim(), format);
LocalTime start = LocalTime.parse(startTimeString.trim(), format);
return Duration.between(start, end).toHoursPart()%24
+ ":"
+ Duration.between(start, end).toMinutes()%60;

Your math is all wrong for dealing with the fact that the time values returned by getTime() are in milliseconds.
I'm guessing (since this isn't shown anywhere above) that HOURS and MINUTES are constants for the number of milliseconds in an hour and in a minute, respectively? If so, you're only partially dealing with the fact that the units are milliseconds, because when you do this:
totalTime -= diffHours;
...you'd be subtracting only a few milliseconds from your total time, not achieving what I think you think you're accomplishing, which is removing all of the hours so that what's left is minutes.
There are other problems with this code too, but that's the most glaring problem.

private static final String defaultHours = "-1";
public static String calculateTotalHours(Cell inTime, Cell outTime, Cell breakStart, Cell breakEnd)
{
try {
LocalTime inLocalTime = LocalTime.parse(inTime.getStringCellValue());
LocalTime outLocalTime = LocalTime.parse(outTime.getStringCellValue());
LocalTime breakStartTime = LocalTime.parse(breakStart.getStringCellValue());
LocalTime breakEndTime = LocalTime.parse(breakEnd.getStringCellValue());
Duration lunch = Duration.between(breakStartTime, breakEndTime);
Duration present = Duration.between(inLocalTime, outLocalTime);
Duration worked = present.minus(lunch);
return String.format("%02d:%02d", worked.toHours(), worked.toMinutesPart());
} catch (DateTimeParseException dtpe) {
System.out.println(dtpe);
return defaultHours;
}
}
The above code uses the toMinutesPart method that was introduced in Duration in Java 9. Assuming you are using ThreeTenABP (details below) or an earlier Java version, it’s:
long hours = worked.toHours();
long minutes = worked.minusHours(hours).toMinutes();
return String.format("%02d:%02d", hours, minutes);
For clarity I have omitted the null checks, I am sure you can handle those.
As said in the comments, leave time math to well-tested library methods. It’s not only less error-prone, it also gives clearer code. I am using java.time, the modern Java date and time API. It also saves us from specifying an explicit formatter since LocalTime.parse() parses your format of HH:mm as its default (it’s ISO 8601 format).
What went wrong in your code?
As kshetline in the other answer I believe that totalTime is in milliseconds and diffHours is hours. So when you do totalTime -= diffHours;, you subtract hours from milliseconds and you’re bound to get an incorrect result (same with totalTime -= diffMinutes;, by the way, but you’re not using the result of the latter subtraction, so this error doesn’t show).
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601

Related

How to get Elapsed time in Android TimeUnit

I have a 5 minutes timer. In case i finish 30 seconds its shown 4:30 but i want set 30 seconds .
code to decrease time
String timeReminder= String.format(Locale.ENGLISH , "%02d:%02d" , TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) , TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)) );
timerText.setText(timeReminder);
i want only reminder time.
java.time
You can use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
import java.time.Duration;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Duration total = Duration.ofMinutes(5);
Duration elapsed = Duration.ofSeconds(30);
Duration remaining = total.minus(elapsed);
// ###############Java 8###########################
String timeReminder = String.format(Locale.ENGLISH, "%02d:%02d", remaining.toMinutes(),
remaining.toSeconds() % 60);
System.out.println(timeReminder);
// ################################################
// ###############Java 9###########################
timeReminder = String.format(Locale.ENGLISH, "%02d:%02d", remaining.toMinutesPart(), remaining.toSecondsPart());
System.out.println(timeReminder);
// ################################################
}
}
Output:
04:30
04:30
Learn more about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Ok, I guess the word you are looking for is elapsed time, however, your logic doesn't seem correct.
So here is the example,
Long startTime = System.currentTimeMillis();
Long estimatedTime = TimeUnit.MINUTES.toMillis(10); // For 10 minutes
To calculate elapsed time :
Long elapsedTime = System.currentTimeMillis() - startTime;
To calculate Remaining time :
Long remainingTime = estimatedTime - System.currentTimeMillis();
Now you have both times in Millis, You can easily convert and format in Minutes:Second format.

How to measure time elapsed, immune to system time server automatic updates [duplicate]

This question already has answers here:
How do I time a method's execution in Java?
(42 answers)
How do I calculate the elapsed time of an event in Java? [duplicate]
(6 answers)
Closed 4 years ago.
I want to have something like this:
public class Stream
{
public startTime;
public endTime;
public getDuration()
{
return startTime - endTime;
}
}
Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.
Which types to use in order to accomplish this in Java?
Unfortunately, none of the ten answers posted so far are quite right.
If you are measuring elapsed time, and you want it to be correct, you must use System.nanoTime(). You cannot use System.currentTimeMillis(), unless you don't mind your result being wrong.
The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected. This correction might either happen manually, or in the case of most machines, there's a process that runs and continually issues small corrections to the system clock ("wall clock"). These tend to happen often. Another such correction happens whenever there is a leap second.
Since nanoTime's purpose is to measure elapsed time, it is unaffected by any of these small corrections. It is what you want to use. Any timings currently underway with currentTimeMillis will be off -- possibly even negative.
You may say, "this doesn't sound like it would ever really matter that much," to which I say, maybe not, but overall, isn't correct code just better than incorrect code? Besides, nanoTime is shorter to type anyway.
Previously posted disclaimers about nanoTime usually having only microsecond precision are valid. Also it can take more than a whole microsecond to invoke, depending on circumstances (as can the other one), so don't expect to time very very small intervals correctly.
Which types to use in order to accomplish this in Java?
The short answer is a long. Now, more on how to measure...
System.currentTimeMillis()
The "traditional" way to do this is indeed to use System.currentTimeMillis():
long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;
o.a.c.l.t.StopWatch
Note that Commons Lang has a StopWatch class that can be used to measure execution time in milliseconds. It has methods methods like split(), suspend(), resume(), etc that allow to take measure at different points of the execution and that you may find convenient. Have a look at it.
System.nanoTime()
You may prefer to use System.nanoTime() if you are looking for extremely precise measurements of elapsed time. From its javadoc:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Jamon
Another option would be to use JAMon, a tool that gathers statistics (execution time, number of hit, average execution time, min, max, etc) for any code that comes between start() and stop() methods. Below, a very simple example:
import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();
Check out this article on www.javaperformancetunning.com for a nice introduction.
Using AOP
Finally, if you don't want to clutter your code with these measurement (or if you can't change existing code), then AOP would be a perfect weapon. I'm not going to discuss this very deeply but I wanted at least to mention it.
Below, a very simple aspect using AspectJ and JAMon (here, the short name of the pointcut will be used for the JAMon monitor, hence the call to thisJoinPoint.toShortString()):
public aspect MonitorAspect {
pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..));
Object arround() : monitor() {
Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString());
Object returnedObject = proceed();
monitor.stop();
return returnedObject;
}
}
The pointcut definition could be easily adapted to monitor any method based on the class name, the package name, the method name, or any combination of these. Measurement is really a perfect use case for AOP.
Your new class:
public class TimeWatch {
long starts;
public static TimeWatch start() {
return new TimeWatch();
}
private TimeWatch() {
reset();
}
public TimeWatch reset() {
starts = System.currentTimeMillis();
return this;
}
public long time() {
long ends = System.currentTimeMillis();
return ends - starts;
}
public long time(TimeUnit unit) {
return unit.convert(time(), TimeUnit.MILLISECONDS);
}
}
Usage:
TimeWatch watch = TimeWatch.start();
// do something
long passedTimeInMs = watch.time();
long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);
Afterwards, the time passed can be converted to whatever format you like, with a calender for example
Greetz,
GHad
If the purpose is to simply print coarse timing information to your program logs, then the easy solution for Java projects is not to write your own stopwatch or timer classes, but just use the org.apache.commons.lang.time.StopWatch class that is part of Apache Commons Lang.
final StopWatch stopwatch = new StopWatch();
stopwatch.start();
LOGGER.debug("Starting long calculations: {}", stopwatch);
...
LOGGER.debug("Time after key part of calcuation: {}", stopwatch);
...
LOGGER.debug("Finished calculating {}", stopwatch);
tl;dr
for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.
Not possible. If you have only time-of-day, the clock stops at midnight. Without the context of dates, how do we know if you mean 1 AM on the next day, next week, or next decade?
So going from 11 PM to 1 AM means moving backwards in time 22 hours, running the hands of the clock counterclockwise. See the result below, a negative twenty-two hours.
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
LocalTime.of( 23 , 0 ) , // A time-of-day without a date and without a time zone.
LocalTime.of( 1 , 0 ) // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT-22H
Crossing midnight requires the larger context of date in addition to time-of-day (see below).
How do I measure time elapsed in Java?
Capture the current moment in UTC, with Instant.now().
Capture another such moment later.
Pass both to Duration.between.
(a) From the resulting Duration object, extract a number of 24-hour days, hours, minutes, seconds, and fractional second in nanoseconds by calling the various to…Part methods.(b) Or, call toString to generate a String in standard ISO 8601 format of PnYnMnDTnHnMnS.
Example code, using pair of Instant objects.
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
then , // Some other `Instant` object, captured earlier with `Instant.now()`.
Instant.now() // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT3M27.602197S
New Technology In Java 8+
We have new technology for this now built into Java 8 and later, the java.time framework.
java.time
The java.time framework is defined by JSR 310, inspired by the highly successful Joda-Time project, extended by the ThreeTen-Extra project, and described in the Oracle Tutorial.
The old date-time classes such as java.util.Date/.Calendar bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. They are supplanted by the java.time classes.
Resolution
Other answers discuss resolution.
The java.time classes have nanosecond resolution, up to nine digits of a decimal fraction of a second. For example, 2016-03-12T04:29:39.123456789Z.
Both the old java.util.Date/.Calendar classes and the Joda-Time classes have millisecond resolution (3 digits of fraction). For example, 2016-03-12T04:29:39.123Z.
In Java 8, the current moment is fetched with up to only millisecond resolution because of a legacy issue. In Java 9 and later, the current time can be determined up to nanosecond resolution provided your computer’s hardware clock runs so finely.
Time-Of-Day
If you truly want to work with only the time-of-day lacking any date or time zone, use the LocalTime class.
LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );
A Duration represents a span of time it terms of a count of seconds plus nanoseconds.
Duration duration = Duration.between ( sooner, later );
Dump to console.
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
sooner: 17:00 | later: 19:00 | duration: PT2H
ISO 8601
Notice the default output of Duration::toString is in standard ISO 8601 format. In this format, the P marks the beginning (as in 'Period'), and the T separates any years-months-days portion from the hours-minutes-seconds portion.
Crossing Midnight
Unfortunately, working with time-of-day only gets tricky when you wrap around the clock crossing midnight. The LocalTime class handles this by assuming you want to go backwards to an earlier point in the day.
Using the same code as above but going from 23:00 to 01:00 results in a negative twenty-two hours (PT-22H).
LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );
sooner: 23:00 | later: 01:00 | duration: PT-22H
Date-Time
If you intend to cross midnight, it probably makes sense for you to be working with date-time values rather than time-of-day-only values.
Time Zone
Time zone is crucial to dates. So we specify three items: (1) the desired date, (2) desired time-of-day, and (3) the time zone as a context by which to interpret that date and time. Here we arbitrarily choose the time zone of the Montréal area.
If you define the date by only an offset-from-UTC, use a ZoneOffset with a OffsetDateTime. If you have a full time zone (offset plus rules for handling anomalies such as Daylight Saving Time), use a ZoneId with a ZonedDateTime.
LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );
We specify the later time as next day at 1:00 AM.
ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );
We calculate the Duration in the same manner as seen above. Now we get the two hours expected by this Question.
Duration duration = Duration.between ( sooner, later );
Dump to console.
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
sooner: 2016-01-23T23:00-05:00[America/Montreal] | later: 2016-01-24T01:00-05:00[America/Montreal] | duration: PT2H
Daylight Saving Time
If the date-times at hand had involved Daylight Saving Time (DST) or other such anomaly, the java.time classes would adjust as needed. Read class doc for details.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
It is worth noting that
System.currentTimeMillis() has only millisecond accuracy at best. At worth its can be 16 ms on some windows systems. It has a lower cost that alternatives < 200 ns.
System.nanoTime() is only micro-second accurate on most systems and can jump on windows systems by 100 microseconds (i.e sometimes it not as accurate as it appears)
Calendar is a very expensive way to calculate time. (i can think of apart from XMLGregorianCalendar) Sometimes its the most appropriate solution but be aware you should only time long intervals.
Which types to use in order to accomplish this in Java?
Answer: long
public class Stream {
public long startTime;
public long endTime;
public long getDuration() {
return endTime - startTime;
}
// I would add
public void start() {
startTime = System.currentTimeMillis();
}
public void stop() {
endTime = System.currentTimeMillis();
}
}
Usage:
Stream s = ....
s.start();
// do something for a while
s.stop();
s.getDuration(); // gives the elapsed time in milliseconds.
That's my direct answer for your first question.
For the last "note" I would suggest you to use Joda Time. It contains an interval class suitable for what you need.
Java provides the static method System.currentTimeMillis(). And that's returning a long value, so it's a good reference. A lot of other classes accept a 'timeInMillis' parameter which is long as well.
And a lot of people find it easier to use the Joda Time library to do calculations on dates and times.
If you prefer using Java's Calendar API you can try this,
Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();
If you are writing an application that must deal with durations of time, then please take a look at Joda-Time which has class specifically for handling Durations, Intervals, and Periods. Your getDuration() method looks like it could return a Joda-Time Interval:
DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);
public Interval getInterval() {
Interval interval = new Interval(start, end);
}
Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs
import java.io.*;
import java.io.IOException;
import java.util.Scanner;
class ElaspedTimetoCopyAFileUsingByteStream
{
private long startTime = 0;
private long stopTime = 0;
private boolean running = false;
public void start()
{
this.startTime = System.currentTimeMillis();
this.running = true;
}
public void stop()
{
this.stopTime = System.currentTimeMillis();
this.running = false;
}
public long getElapsedTime()
{
long elapsed;
if (running) {
elapsed = (System.currentTimeMillis() - startTime);
}
else {
elapsed = (stopTime - startTime);
}
return elapsed;
}
public long getElapsedTimeSecs()
{
long elapsed;
if (running)
{
elapsed = ((System.currentTimeMillis() - startTime) / 1000);
}
else
{
elapsed = ((stopTime - startTime) / 1000);
}
return elapsed;
}
public static void main(String[] args) throws IOException
{
ElaspedTimetoCopyAFileUsingByteStream s = new ElaspedTimetoCopyAFileUsingByteStream();
s.start();
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("vowels.txt"); // 23.7 MB File
out = new FileOutputStream("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
s.stop();
System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
}
}
[Elapsed Time for Byte Stream Reader][1]
**Character Stream Reader Elapsed Time for 23.7 MB is 3 secs**
import java.io.*;
import java.io.IOException;
import java.util.Scanner;
class ElaspedTimetoCopyAFileUsingCharacterStream
{
private long startTime = 0;
private long stopTime = 0;
private boolean running = false;
public void start()
{
this.startTime = System.currentTimeMillis();
this.running = true;
}
public void stop()
{
this.stopTime = System.currentTimeMillis();
this.running = false;
}
public long getElapsedTime()
{
long elapsed;
if (running) {
elapsed = (System.currentTimeMillis() - startTime);
}
else {
elapsed = (stopTime - startTime);
}
return elapsed;
}
public long getElapsedTimeSecs()
{
long elapsed;
if (running)
{
elapsed = ((System.currentTimeMillis() - startTime) / 1000);
}
else
{
elapsed = ((stopTime - startTime) / 1000);
}
return elapsed;
}
public static void main(String[] args) throws IOException
{
ElaspedTimetoCopyAFileUsingCharacterStream s = new ElaspedTimetoCopyAFileUsingCharacterStream();
s.start();
FileReader in = null; // CharacterStream Reader
FileWriter out = null;
try {
in = new FileReader("vowels.txt"); // 23.7 MB
out = new FileWriter("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
s.stop();
System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
}
}
[Elapsed Time for Character Stream Reader][2]
[1]: https://i.stack.imgur.com/hYo8y.png
[2]: https://i.stack.imgur.com/xPjCK.png
If you're getting your timestamps from System.currentTimeMillis(), then your time variables should be longs.
i found this code to be useful when timing things:
public class Et {
public Et() {
reset();
}
public void reset() {
t0=System.nanoTime();
}
public long t0() {
return t0;
}
public long dt() {
return System.nanoTime()-t0();
}
public double etms() {
return etms(dt());
}
#Override public String toString() {
return etms()+" ms.";
}
public static double etms(long dt) {
return dt/1000000.; // 1_000_000. breaks cobertura
}
private Long t0;
}
Use this:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date d1 = format.parse(strStartTime);
Date d2 = format.parse(strEndTime);
long diff = d2.getTime() - d1.getTime();
long diffSeconds,diffMinutes,diffHours;
if (diff > 0) {
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000);
}
else{
long diffpos = (24*((60 * 60 * 1000))) + diff;
diffSeconds = diffpos / 1000 % 60;
diffMinutes = diffpos / (60 * 1000) % 60;
diffHours = (diffpos / (60 * 60 * 1000));
}
(Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.)
the "else" part can get it correct
I built a formatting function based on stuff I stole off SO. I needed a way of "profiling" stuff in log messages, so I needed a fixed length duration message.
public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
StringBuffer elapsed = new StringBuffer();
Map<String, Long> units = new HashMap<String, Long>();
long milliseconds = aEndTime - aInitialTime;
long seconds = milliseconds / 1000;
long minutes = milliseconds / (60 * 1000);
long hours = milliseconds / (60 * 60 * 1000);
long days = milliseconds / (24 * 60 * 60 * 1000);
units.put("milliseconds", milliseconds);
units.put("seconds", seconds);
units.put("minutes", minutes);
units.put("hours", hours);
units.put("days", days);
if (days > 0)
{
long leftoverHours = hours % 24;
units.put("hours", leftoverHours);
}
if (hours > 0)
{
long leftoeverMinutes = minutes % 60;
units.put("minutes", leftoeverMinutes);
}
if (minutes > 0)
{
long leftoverSeconds = seconds % 60;
units.put("seconds", leftoverSeconds);
}
if (seconds > 0)
{
long leftoverMilliseconds = milliseconds % 1000;
units.put("milliseconds", leftoverMilliseconds);
}
elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
.append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
.append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
.append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
.append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");
return elapsed.toString();
}
private static String PrependZeroIfNeeded(long aValue)
{
return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}
And a test class:
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import junit.framework.TestCase;
public class TimeUtilsTest extends TestCase
{
public void testGetElapsed()
{
long start = System.currentTimeMillis();
GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
calendar.setTime(new Date(start));
calendar.add(Calendar.MILLISECOND, 610);
calendar.add(Calendar.SECOND, 35);
calendar.add(Calendar.MINUTE, 5);
calendar.add(Calendar.DAY_OF_YEAR, 5);
long end = calendar.getTimeInMillis();
assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));
}
}

Sum of time duration's from a list in android studio

I am trying to calculate the sum of a list of time duration for an attendance app. I was able to calculate the difference of 2 times but not sure how to traverse through the list to add the dates together.
The below code is what I have attempted so far. There are 2 time durations in the list and they are added to the list from Firebase using an object class.
Duration 1 = 0:5:42
Duration 2 = 0:0:09
Expected Total = 0:5:51
//initialized
long sum;
//current method attempted
public void grandTotal() throws ParseException {
java.util.Date date1;
java.util.Date date2;
DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
for(int i = 0 ; i < newList.size(); i++) {
String str_time1 = newList.get(i).getDuration();
date1 = formatter.parse(str_time1);
for (int j = 1; j < newList.size(); j++) {
String str_time2 = newList.get(j).getDuration();
date2 = formatter.parse(str_time2);
sum = date1.getTime() + date2.getTime();
}
}
secs = sum/1000;
mins = secs/60;
secs%=60;
hours = mins/60;
mins%=60;
txtDailyBalance.setText(hours+":"+mins+":"+String.format("%02d",secs));
}
Result output I get is = -1:59:42
I got the solution using this method but I don't think this is good practice so I have been looking into learning more about the different methods in this post so thank you.
//Sum of time durations for that day
public void grandTotal() throws ParseException {
java.util.Date date1;
java.util.Date date2;
DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
for(int i = 0 ; i < newList.size(); i++) {
timeDuration.add(newList.get(i).getDuration());
}
long tDur = 0;
for (String tmp : timeDuration){
String[] arr = tmp.split(":");
tDur += Integer.parseInt(arr[2]);
tDur += 60 * Integer.parseInt(arr[1]);
tDur += 3600 * Integer.parseInt(arr[0]);
}
long hours = tDur / 3600;
tDur %= 3600;
long mins = tDur / 60;
tDur %= 60;
long secs = tDur;
txtDailyBalance.setText(hours+":"+mins+":"+String.format("%02d",secs));
}
As I have said in the comments, use the Duration class for durations:
List<Duration> durations = List.of(
Duration.ofMinutes(5).plusSeconds(42), // 0:05:42
Duration.ofSeconds(9), // 0:00:09
Duration.parse("PT11M")); // 0:11:00
Duration sum = Duration.ZERO;
for (Duration dur : durations) {
sum = sum.plus(dur);
}
System.out.println(sum);
This prints
PT16M51S
So 16 minutes 51 seconds.
Durations parse and produce ISO 8601 format natively, it goes like what you just saw, PT16M51S. If you need to have your duration strings in hh:mm:ss format, I am sure you can write auxiliary methods for formatting and parsing that format. For formatting there are already a couple of questions on Stack Overflow, for example How to format a duration in java? (e.g format H:MM:SS) (search for more).
Why not Date?
Using a Date for a duration is incorrect. A point in time and an amount of time are two different concepts. The error you saw may be due to time zone offset, but you risk other errors along the way, and worse, your code is difficult to read and easy to misunderstand.
Also the Date class is long outdated and replaced by classes in java.time, the modern Java date and time API. The same API introduces the classes Period (for years, months and days) and Duration (for hours, minutes, seconds and fraction of second).
Question: Can I use java.time on Android?
Yes, you can use java.time on Android. It just requires at least Java 6.
In Java 8 and later and on newer Android devices the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
If you don't insist on having a customized format but just look for an easier way to add duration objects then Oles answer might be okay for you. However, ThreetenABP lacks a duration formatter.
But if you want to avoid writing auxiliary methods for formatting and parsing durations in the format "hh:mm:ss" (and are willing to add a 3rd-party-dependency) then you might try my lib Time4A and use a pattern-based approach:
Duration.Formatter<ClockUnit> parser = Duration.formatter(ClockUnit.class, "#h:#m:ss");
String[] durations = { "0:5:42", "0:0:09" };
Duration<ClockUnit> d = Duration.ofZero();
for (String duration : durations) {
d = d.plus(parser.parse(duration));
}
d = d.with(Duration.STD_CLOCK_PERIOD); // normalization
Duration.Formatter<ClockUnit> printer = Duration.formatter(ClockUnit.class, "hh:mm:ss");
System.out.println(printer.format(d)); // 00:05:51

NumberFormatException while parsing date with SimpleDateFormat.parse()

Have a function that creates a time-only Date object. (why this is required is a long story which is irrelevant in this context but I need to compare to some stuff in XML world where TIME (i.e. time-only) is a valid concept).
private static final SimpleDateFormat DF_TIMEONLY = new SimpleDateFormat("HH:mm:ss.SSSZ");
public static Date getCurrentTimeOnly() {
String onlyTimeStr = DF_TIMEONLY.format(new Date()); // line #5
Date onlyTimeDt = null;
try {
onlyTimeDt = DF_TIMEONLY.parse(onlyTimeStr); // line #8
} catch (ParseException ex) {
// can never happen (you would think!)
}
return onlyTimeDt;
}
There are probably at least a couple other ways to create a time-only Date in Java (or more precisely one where the date part is 1970-01-01) but my question is really not about that.
My question is that this piece of code starts randomly throwing NumberFormatException on line #8 after having run in production for long time. Technically I would say that this should be impossible, right ?
Here's an extract of random NumberFormatExceptions that come from above piece of code:
java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: For input string: ".11331133EE22"
java.lang.NumberFormatException: For input string: "880044E.3880044"
java.lang.NumberFormatException: For input string: "880044E.3880044E3"
First of all I hope we can agree that formally this should be impossible? The code uses the same format (DF_TIMEONLY) as output and then input. Let me know if you disagree that it should be impossible.
I haven't been able to re-produce the problem in a standalone environment. The problem seems to come when the JVM has run for a long time (>1 week). I cannot find a pattern to the problem, i.e. summer time / winter time, AM/PM, etc. The error is sporadic, meaning that one minute it will throw NumberFormatException and the next minute it will run fine.
I suspect that there's some kind of arithmetic malfunction somewhere in either the JVM or perhaps even in the CPU. The above exceptions suggests that there's floating point numbers involved but I fail to see where they would come from. As far as I know Java's Date object is a wrapper around a long which holds the number of millis since the epoch.
I'm guessing what is happening is that there's an unexpected string onlyTimeStr created in line #5 so the problem really lies here rather than in line #8.
Here's an example of a full stacktrace:
java.lang.NumberFormatException: For input string: "880044E.3880044E3"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2086)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at org.mannmann.zip.Tanker.getCurrentTimeOnly(Tanker.java:746)
Environment: Java 7
The likely cause is the fact that SimpleDateFormat isn't threadsafe, and you're referencing it from multiple threads. While extremely difficult to prove (and about as hard to test for), there is some evidence this is the case:
.11331133EE22 - notice how everything is doubled
880044E.3880044E3 - same here
You probably have at least two threads interleaving. The E was throwing me, I was thinking it was attempting to deal with scientific notation (1E10, etc), but it's likely part of the time zone.
Thankfully, the (formatting) basic fix is simple:
private static final String FORMAT_STRING = "HH:mm:ss.SSSZ";
public static Date getCurrentTimeOnly() {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_STRING);
String onlyTimeStr = formatter.format(new Date());
return formatter.parse(onlyTimeStr);
}
There's a couple of other things you could be doing here, too, with a few caveats:
1 - If the timezone is UTC (or any without DST), this is trivial
public static Date getCurrentTimeOnly() {
Date time = new Date();
time.setTime(time.getTime() % (24 * 60 * 60 * 1000));
return time;
}
2 - You're going to have trouble testing this method, because you can't safely pause the clock (you can change the timezone/locale). For a better time dealing with date/time in Java, use something like JodaTime. Note that LocalTime doesn't have a timezone attached, but Date only returns an offset in integer hours (and there are zones not on the hour); for safety, you need to either return a Calendar (with the full timezone), or just return something without it:
// This method is now more testable. Note this is only safe for non-DST zones
public static Calendar getCurrentTimeOnly() {
Calendar cal = new Calendar();
// DateTimeUtils is part of JodaTime, and is a class allowing you to pause time!
cal.setTimeInMillis(DateTimeUtils.currentTimeMillis() % (24 * 60 * 60 * 1000));
return cal;
}
Joda-Time
FYI, the Joda-Time 2.3 library provides a class expressly for your purpose, time-only, without any date: LocalTime. And, it is thread-safe (immutable instances). Seems a much better option than manhandling the troublesome java.util.Date class.
LocalTime localTime = new LocalTime();
Dump to console…
System.out.println( "localTime: " + localTime );
When run…
localTime: 16:26:28.065
java.time
Java 8 brings the new java.time package, inspired by Joda-Time, defined by JSR 310.
In java.time, you will find a LocalTime class similar to the one in Joda-Time.
SimpleDateFormat is not thread safe. the following program will reproduce NumberFormatException while parsing string represented date to date object.
public class MaintainEqualThreadsPatallel {
static int parallelCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService executorPool = Executors.newFixedThreadPool(parallelCount);
int numberOfThreads = 150; // Total thread count = 150*2= 300.
List<Future<Object>> futureReturns = new LinkedList<Future<Object>>();
for (int i = 0; i < numberOfThreads; i++) {
int uniqueRandomValues = uniqueRandomValues(1, 10);
// Callable Thread - call()
Future<Object> submit = executorPool.submit( new WorkerCallable(uniqueRandomValues) );
futureReturns.add(submit);
// Runnable Thread - run()
executorPool.execute( new WorkerThread(uniqueRandomValues) );
}
// WorkerCallable: Blocking main thread until task completes.
waitTillThreadsCompleteWork(futureReturns);
// Terminate Pool threads in-order to terminate main thread
executorPool.shutdown();
}
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
public static Date numberFormatEx(Date date) throws ParseException { // synchronized
String dateStr = sdf.format(date);
Date dateParsed = sdf.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
protected void loopFunction(int repeatCount) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName +":START");
for (int i = 1; i <= repeatCount; i++) {
try {
System.out.println(threadName +":"+ i);
sleepThread(100);
numberFormatEx(new Date());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(threadName +":END");
}
public static void waitTillThreadsCompleteWork(List<Future<Object>> futureReturns) throws Exception {
for (Future<Object> future : futureReturns) {
int threadReturnVal = (int) future.get();
System.out.println("Future Response : "+threadReturnVal);
}
}
public static int uniqueRandomValues(int min, int max) {
int nextInt = ThreadLocalRandom.current().nextInt(min, max);
System.out.println("Random Vlaue : "+nextInt);
return nextInt;
}
public void sleepThread(long mills) {
try {
Thread.sleep(mills);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class WorkerThread extends MaintainEqualThreadsPatallel implements Runnable {
int randomValue = 0;
public WorkerThread(int randomValue) {
this.randomValue = randomValue;
}
#Override
public void run() {
// As separate stack run() function doesn't accepts parameters, pass to constructor.
loopFunction(randomValue);
}
}
class WorkerCallable extends MaintainEqualThreadsPatallel implements Callable<Object> {
int randomValue = 0;
public WorkerCallable(int randomValue) {
this.randomValue = randomValue;
}
public Object call() {
// As separate stack run() function doesn't accepts parameters, pass to constructor.
loopFunction(randomValue);
return randomValue;
}
}
NumberFormatException with different messages:
java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: For input string: ""
java.lang.NumberFormatException: For input string: "186E.2"
java.lang.NumberFormatException: For input string: "186E.2186E2"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE4"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE44"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
In Multi-Threading/Web Application with Multi-Requests concept parse function leads to NumberFormatException which can be handled using synchronized block.
To overcome NumberFormatException on parse() function use any of the following scenarios.
Separate Object: Every request/thread works on its own object.
public static Date numberFormatEx(Date date) throws ParseException {
SimpleDateFormat ObjInstance = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
String dateStr = ObjInstance.format(date);
Date dateParsed = ObjInstance.parse(dateStr);
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
Unnecessary creating reusable object for each thread.
Static Object synchronized block: Every request/thread shares the common object to perform operation. As multiple threads share same object at same time then the object data gets clear/overrride ""/"186E.2186E2" at some point and leads to error.
static SimpleDateFormat objStatic = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
public static synchronized Date numberFormatEx(Date date) throws ParseException {
String dateStr = objStatic.format(date);
Date dateParsed = objStatic.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
NOTE: In case of Memory management it better to use synchronized block with static object which is reusable.
I have got the same question, the cause is SimpleDateFormat is not thread-safe, I just add syncronized in the method, and it doesn't happen again.
You can use "sychronized" block to make it thread safe.
Something like:
synchronized (lastUpdatedFormat) {
date =
lastUpdatedFormat.parse(lastUpdatedFormat.format(currentDate));
}
The diagnosis in the accepted answer is correct. I am providing the modern answer: do use java.time, the modern Java date and time API, for your date and time work. In Java 7 too. SimpleDateFormat is notoriously troublesome, its lack of thread safety is only one of its many problems. So don’t use that class.
OffsetTime.now() and ThreeTen Backport
You want the current time only, though with an offset from UTC, if your format pattern is to be believed. We have got a method exactly for that in java.time, the modern Java date and time API. So no reason to format into a string and parse back.
OffsetTime timeOnly = OffsetTime.now(ZoneId.systemDefault());
System.out.println(timeOnly);
When I ran the code just now in my time zone, Europe/Copenhagen, on jdk.1.7.0_67, the output was:
06:21:55.419+01:00
By the way this is also the XML format for the concept of a time with time zone. Are we done?
The Date class you were returning is poorly designed and long outdated, so avoid it if you can. If you need one for a legacy API that you cannot afford to change just now, convert like this:
Instant asInstant = LocalDate.of(1970, Month.JANUARY, 1)
.atTime(timeOnly)
.toInstant();
Date oldfashionedDateObject = DateTimeUtils.toDate(asInstant);
System.out.println("As java.util.Date: " + oldfashionedDateObject);
As java.util.Date: Thu Jan 01 06:21:55 CET 1970
Question: Does it work on Java 7?
Environment: Java 7
java.time just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in. In this case use Date.from(asInstant) for converting from Instant to Date instead of the way shown in the code above.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
While the correct answer is the one by Clockwork-Muse (the cause of the problems is the fact that SimpleDateFormat isn't thread safe) I just wanted to deliver another method of creating a time-only Date object:
public static Date getCurrentTimeOnly() {
Calendar rightNow = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
int hour = rightNow.get(Calendar.HOUR_OF_DAY);
int minute = rightNow.get(Calendar.MINUTE);
int second = rightNow.get(Calendar.SECOND);
int msecond = rightNow.get(Calendar.MILLISECOND);
long millisSinceMidnight
= (hour * 60 * 60 * 1000)
+ (minute * 60 * 1000)
+ (second * 1000)
+ (msecond);
return new Date(millisSinceMidnight);
}
This method is somewhat more formally correct, i.e. it handles leap-seconds. It doesn't assume, like other methods, that all days since epoch has always had 24*60*60*1000 milliseconds in them.
It doesn't however handle the case where the leap second is on the current day.

Time within a particular time interval

i'm trying to solve a seemingly simple problem, but just can't quite get my mind around it.
i have two times startTime and stopTime, which can be considered to be in the format: hh:mm:ss [24hr format].
Now given a third time - timeToTest - i need to find out if timeToTest lies between startTime and stopTime. There is no date information involved, other than just the times.
So for example - if i have startTime = '22:30:00' and stopTime = '03:30:00', then for timeToTest = '01:14:23', the test should return true.
I've tried a solution with java.util.Date by converting the times to milliseconds using getTime(), but with any interval which rolls over the 24 hr barrier, the logic fails.
I'm trying to build a solution using Java - but i believe the logic is language independent.
So the simplest solution i could come up with, sticking to plain old java.util.Date, is shown below:
String d1 = "21:00:00";
String d2 = "04:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String dToTest = "16:00:00";
boolean isSplit = false, isWithin = false;
Date dt1 = null, dt2 = null, dt3 = null;
dt1 = sdf.parse(d1);
dt2 = sdf.parse(d2);
dt3 = sdf.parse(dToTest);
isSplit = (dt2.compareTo(dt1) < 0);
System.out.println("[split]: " +isSplit);
if (isSplit)
{
isWithin = (dt3.after(dt1) || dt3.before(dt2));
}
else
{
isWithin = (dt3.after(dt1) && dt3.before(dt2));
}
System.out.println("Is time within interval? " +isWithin);
feel free to point out any mistakes - would love to work and fix it.
You must add a "day" where "0" == current day, "1" == next day and so on. So in fact when stopTime == '03:30:00' it should be '27:30:00' (i.e. on the next day).
In your case, if the stopTime < startTime, then add 86400 seconds.
anirvan's solution using JodaTime :
public class TimeInterval24H {
private final LocalTime start;
private final LocalTime end;
public TimeInterval24H(LocalTime start, LocalTime end) {
this.start = start;
this.end = end;
}
public TimeInterval24H(Date start, Date end) {
this(new LocalTime(start), new LocalTime(end));
}
public boolean contains(Date test) {
return contains(new LocalTime(test));
}
public boolean contains(LocalTime test) {
if (isAccrossTwoDays()) {
return (test.isAfter(getStart()) || test.isBefore(getEnd()));
} else {
return (test.isAfter(getStart()) && test.isBefore(getEnd()));
}
}
boolean isAccrossTwoDays() {
return getEnd().isBefore(getStart());
}
public LocalTime getStart() {
return start;
}
public LocalTime getEnd() {
return end;
}
}
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
String strStartTime = "22:30:00", strStopTime = "03:30:00", strTestTime = "01:14:23";
LocalDate today = LocalDate.now();
LocalDateTime startTime = today.atTime(LocalTime.parse(strStartTime));
LocalDateTime stopTime = today.atTime(LocalTime.parse(strStopTime));
if (stopTime.isBefore(startTime))
stopTime = stopTime.plusDays(1);
LocalDateTime testTime = today.atTime(LocalTime.parse(strTestTime));
if (testTime.isBefore(startTime))
testTime = testTime.plusDays(1);
if (!testTime.isBefore(startTime) && !testTime.isAfter(stopTime))
System.out.println(strTestTime + " is at or after " + strStartTime + " and is before or at " + strStopTime);
}
}
Output:
01:14:23 is at or after 22:30:00 and is before or at 03:30:00
ONLINE DEMO
Note: If the start time and stop time are not inclusive, change the condition as follows:
if (testTime.isAfter(startTime) && testTime.isBefore(stopTime))
System.out.println(strTestTime + " is after " + strStartTime + " and is before " + strStopTime);
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
How about:
Find the next occurrence of the specified time after the start instant
Check whether that occurrence is before the end instant or not
The first step can probably be broken down pretty easily:
Is the specified time on/after the time of the start instant?
Yes: the next occurrence is that time on the same day as the start instant
No: the next occurrence is that time on the next day from the start instant
All of this is likely to be somewhat easier to write in Joda Time than using java.util.*, by the way :)
I strongly recommend java.util.Calendar, the before() and after() can be useful. However, you'll need a date like 5/18/2011 specified together with your time. Is it possible to specify a mock date (or a pair of date in your case) to leverage the Calendar?

Categories