Calculate Date And Time Difference In Java - java

I have three database (SQLServer) fields:
startDate (Date)
endDate (Date)
Duration (text).
I am calculating date and time difference by using java following code.
public static void main(String[] args) {
DateTimeUtils obj = new DateTimeUtils();
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("dd/M/yyyy hh:mm:ss");
try {
Date date1 = simpleDateFormat.parse("10/10/2013 11:30:10");
Date date2 = simpleDateFormat.parse("13/10/2013 20:55:55");
obj.printDifference(date1, date2);
} catch (ParseException e) {
e.printStackTrace();
}
}
public void printDifference(Date startDate, Date endDate){
//milliseconds
long different = endDate.getTime() - startDate.getTime();
String diff = "";
System.out.println("startDate : " + startDate);
System.out.println("endDate : "+ endDate);
System.out.println("different : " + different);
diff = String.format("%d:%d", TimeUnit.MILLISECONDS.toHours(different), TimeUnit.MILLISECONDS.toMinutes(different) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(different)));
And It returns “HH:MM” and updates the Duration field as String in my database. This works great.
Now there will be multiple duration, what I want to do is once I have Duration, I would like to do add up multiple duration and it should return totalDuration:
For Example:
In my table # 1 I have,
Id | Duration
1001 | 05:04
1001 | 12:19
1001 | 02:16
Table # 2
Id | totalDuration
1001 | 19:39
My Question is: How do I convert HH:Mm to Date and add multiple records together to get totalDuration. Total duration should be text and return the same format “HH:MM

If you actually have date values for start and end in table 1 it would be a lot easier to use datediff and sum the values.

If you still have all the values you worked out then just accumulate a long millisecond count as you go and use that.
If not then there are a few ways, the simplest is probably going to be:
String[] split = duration.split(":");
long duration = Long.parseLong(split[0])*60*60*1000 + Long.parseLong(split[1])*60*1000;
You can then loop through adding up all those durations, then at the end convert it back to a String.
Really you should store the millisecond count in your database and then convert it to text to display though.

Question Not Clear
Your question is not clear. (a) Question fails to address issue of time zones. Are these date-times all in UTC/GMT? (b) Your example dates seem to be 3 days apart, yet your code returns only hours and minutes.
Joda-Time
Trying to roll your own date-time calculations usually leads to trouble and frustration. See if a good date-time library can help you, such as Joda-Time or the new java.time.* classes bundled with Java 8.
ISO 8601 Duration
The international standard for date and time, ISO 8601, defines a way to work with what it calls durations. Historically, the concept has also been called periods. A duration tracks the concept of elapsed time in terms of years, months, days, hours, and minutes.
A value is represented as a string in the format of PnYnMnDTnHnMnS. The 'P' indicates the beginning of a duration (Period) string. A 'T' indicates the time portion. Each number precedes its element designator. For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".
Joda-Time is ISO 8601 savvy, offering the Period class to represent an ISO duration. A Period can be constructed by passing an ISO duration string. Likewise, the default toString implementation on Period outputs an ISO duration string. You could store that ISO duration string in your database. Joda-Time Period instances can be added together by calling the plus method.
Example Code
Here's example code using Joda-Time 2.3 in Java 7. I sourced the two date-time strings from your question. To demonstrate addition, I add an extra 5 minutes.
Good practice dictates being explicit about time zones rather than rely on defaults. Here I use Paris, choosing so arbitrarily. You may well be using UTC/GMT (no time zone offset), in which case you may pass the pre-defined time zone DateTimeZone.UTC.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" ); // Or for UTC/GMT, use: DateTimeZone.UTC
DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd/MM/yyyy HH:mm:ss" ).withZone( timeZone_Paris );
DateTime start = formatter.parseDateTime( "10/10/2013 11:30:10" );
DateTime stop = formatter.parseDateTime( "13/10/2013 20:55:55" );
Period period = new Period( start, stop );
DateTime now = new DateTime( timeZone_Paris );
Period period2 = new Period( now , now.plusMinutes( 5 ));
Period total = period.plus( period2 );
Dump to console…
System.out.println( "start: " + start.toString() );
System.out.println( "stop: " + stop.toString() );
System.out.println( "period: " + period.toString() );
System.out.println();
System.out.println( "now: " + now.toString() );
System.out.println( "period2: " + period2.toString() );
System.out.println();
System.out.println( "total: " + total.toString() );
When run…
start: 2013-10-10T11:30:10.000+02:00
stop: 2013-10-13T20:55:55.000+02:00
period: P3DT9H25M45S
now: 2013-12-24T01:03:10.029+01:00
period2: PT5M
total: P3DT9H30M45S
Note how the 25M increased to 30M.
Date-Time Strings
Tip: If you control those date-time strings as shown in your example code, your work will be easier if you switched to using the standard ISO 8601 format. For example: 2013-12-21T21:03:48+05:30 or 2013-12-21T21:03:48Z.
Using the "dd/M/yyyy hh:mm:ss" format is ambiguous. No reason to use that rather than the standard format. A bonus: The standard format gives a chronological order when sorting alphabetically.

Related

Calculate Number of Days between Given time in ISO format and Current time

I have to find out number of days between a given Time and current time. Given time is in ISO format and one example is "2021-01-14 16:23:46.217-06:00".
I have tried it using "java.text.SimpleDateFormat" but it's not giving me accurate results.
In Below Given date, for today's time I am getting output as "633" Days which isn't correct. somehow after parsing it is taking date as "21 december 2020" which isn't correct
String TIMESTAMP_FORMAT = "YYYY-MM-DD hh:mm:ss.s-hh:mm" ;
int noOfDays = Utility.getTimeDifferenceInDays("2021-01-14 16:23:46.217-06:00", TIMESTAMP_FORMAT);
public static int getTimeDifferenceInDays(String timestamp, String TIMESTAMP_FORMAT) {
DateFormat df = new SimpleDateFormat(TIMESTAMP_FORMAT);
try {
Date date = df.parse(timestamp);
long timeDifference = (System.currentTimeMillis() - date.getTime());
return (int) (timeDifference / (1000*60*60*24));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
Looking for a better solution which gives me correct number of days. Thanks
Use java.time API
Classes Date and SimpleDateFormat are legacy.
Since Java 8 (which was released 10 years ago) we have a new Time API, represented by classes from the java.time package.
To parse and format the data, you can use DateTimeFormatter. An instance of DateTimeFormatter can be obtained via static method ofPattern(), or using DateTimeFormatterBuilder.
ofPattern():
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSXXX");
DateTimeFormatterBuilder:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss.") // main date-time part
.appendValue(ChronoField.MILLI_OF_SECOND, 3) // fraction part of second
.appendOffset("+HH:MM", "+00:00") // can be substituted with appendPattern("zzz") or appendPattern("XXX")
.toFormatter();
The string "2021-01-14 16:23:46.217-06:00", which you've provided as an example, contains date-time information and UTC offset. Such data can be represented by OffsetDateTime.
To get the number of days between two temporal objects, you can use ChronoUnit.between() as #MC Emperor has mentioned in the comments.
That's how the whole code might look like:
String toParse = "2021-01-14 16:23:46.217-06:00";
OffsetDateTime dateTime = OffsetDateTime.parse(toParse, formatter);
System.out.println("parsed date-time: " + dateTime);
Instant now = Instant.now();
long days = ChronoUnit.DAYS.between(dateTime.toInstant(), now);
System.out.println("days: " + days);
Output:
parsed date-time: 2021-01-14T16:23:46.217-06:00
days: 615
Note that since in this case you need only difference in days between the current date instead of OffsetDateTime you can use LocalDateTime, UTC offset would be ignored while parsing a string. If you decide to do so, then the second argument passed to ChronoUnit.between() should be also of type LocalDateTime.

How to parse a date with timezone only, in Joda-Time?

I'd like to use Joda-Time to parse a date with an optional timezone: 2014-08-08+02:00
I tried ISODateTimeFormat.dateTimeParser().parseDateTime(date); but that gives me the following error:
java.lang.IllegalArgumentException: Invalid format: "2014-08-08+02:00" is malformed at "+02:00"
I'm not aware of a better way to handle optional data than to have several patterns and parse them in turn. See code example below:
public static void main(String[] args) throws Exception {
System.out.println(parseWithOptionalTZ("2014-08-08+02:00"));
System.out.println(parseWithOptionalTZ("2014-08-08"));
}
private static DateTime parseWithOptionalTZ(String date) {
DateTimeFormatter[] formatters = {
DateTimeFormat.forPattern("YYYY-MM-dd"),
DateTimeFormat.forPattern("YYYY-MM-ddZ")
};
for (DateTimeFormatter dateTimeFormatter : formatters) {
try {
return dateTimeFormatter.parseDateTime(date);
} catch (IllegalArgumentException e) {
// ignore
}
}
throw new IllegalArgumentException("Could not parse: " + date);
}
Output:
2014-08-07T23:00:00.000+01:00
2014-08-08T00:00:00.000+01:00
Time Zone Is Crucial
Do not ignore the time zone or offset, as mentioned in the comments.
Ignoring time zone on a date-time is like ignoring the C/F (Celsius/Fahrenheit) on a temperature reading or ignoring the character set encoding of text. You will be misinterpreting your data.
Parsing With Time Zone
Specifying a time zone during parsing can have two different effects in Joda-Time. Mull this over and you’ll realize it is logical and is doing the right thing.
After Parsing
If you specify a time zone on a formatter that parses an input containing an offset or time zone, then Joda-Time pays attention to the contained offset during the parsing. After the date-time is determined (where it falls on the timeline of the Universe defined as number of milliseconds since the beginning of 1970 in UTC time zone, that is, no time zone), then your specified time zone is assigned to the DateTime object. In this case, passing the specified time zone did not affect the parsing. The specified time zone affects the generation of String representations of that date-time value.
During Parsing
If, on the other hand, you specify a time on a formatter that parses an input lacking any offset or time zone information, then Joda-Time uses your specified time zone during the parsing of the input String.
Example Code, Joda-Time
Here is example code using Joda-Time 2.3. First is the right way, using the offset during parsing of the string. Second is the wrong way, ignoring the offset. Notice the different results, different date-time values, even possibly different dates (depending on the time zone used to create String representations).
With Offset
String input = "2014-08-08+02:00";
DateTimeFormatter formatter = DateTimeFormat.forPattern( "yyyy-MM-ddZ" ).withZone( DateTimeZone.UTC );
DateTime dateTimeUsingOffset = formatter.parseDateTime( input ); // Offset used to determine date-time during parsing. After parsing the UTC time zone is assigned.
Without Offset
String inputTruncatedOffset = input.substring( 0, 10 );
DateTime dateTimeIgnoringOffset = new DateTime( inputTruncatedOffset, DateTimeZone.UTC ); // In contrast to above, the UTC time zone is used *during* parsing to determine date-time as the input string contained no hint about offset or time zone.
Dump to console.
System.out.println( "input: " + input );
System.out.println( "dateTimeUsingOffset: " + dateTimeUsingOffset );
System.out.println( "inputTruncatedOffset: " + inputTruncatedOffset );
System.out.println( "dateTimeIgnoringOffset: " + dateTimeIgnoringOffset );
When run.
input: 2014-08-08+02:00
dateTimeUsingOffset: 2014-08-07T22:00:00.000Z
inputTruncatedOffset: 2014-08-08
dateTimeIgnoringOffset: 2014-08-08T00:00:00.000Z

Get current Date with custom time

I have some time Strings such as "09:00" and "17:30" and I need to check if the current time is between that range.
I thought I could make this comparison:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date now = new Date();
Date begin;
Date end;
begin = format.parse(begin_string);
end = format.parse(end_string);
if (now.compareTo(begin) > 0 && end.compareTo(now) > 0)
return true;
else
return false;
Turns out that when I parse the strings, the times are parsed correctly, but the date is set to Jan 1st 1970. This way, the code will always return false.
I'd like to know how can I set begin and end to the current date, but with the times from their strings.
You could also just reuse your format object for current time like this way:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date now = new Date();
String time = format.format(now); // format to wall time loosing current date
System.out.println(time);
now = format.parse(time); // reparse wall time
System.out.println(now);
So you transform now to 1970 using implicitly the standard time zone of your system and can then use it for direct comparisons with begin and end.
Date begin = format.parse("09:00");
Date end = format.parse("21:30");
return (begin.before(now) && end.after(now)); // open-bounded interval
Get current time, Calendar.getInstance();
Get another 2 instance of current time, and set time fields based on your input
For example:
Calendar.set(Calendar.HOUR_OF_DAY, 1);
and invoke compare() on the boundry of time
You should really use a Calendar. Then you can individually set the hours and minutes from values parsed from the string. Then get the time in milliseconds and compare those.
Date now = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(now);
cal.set(Calendar.HOUR_OF_DAY, hours);
cal.set(Calendar.MINUTE, minutes);
long time = cal.getTimeInMillis();
You could also use the wonderful Joda library. In my opinion Joda is a much better way to work with Dates and Times.
The bundled java.util.Date & .Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time library or the new java.time package found in Java 8 (inspired by Joda-Time, defined by JSR 310).
If you truly do not care about time zone or date, use either the Joda-Time LocalTime class or the java.time LocalTime class.
Caution: Naïve programmers often think they need only local time and can therefore ignore time zones, but then live to regret that position.
Joda-Time
If your times are in proper ISO 8601 format (24-hours, correct number of digits), then you can directly pass the string inputs to the constructor of LocalTime without bothering to parse. That class has a built-in ISO 8601 style parser.
String inputStart = "09:00";
String inputStop = "17:30";
LocalTime start = new LocalTime( inputStart );
LocalTime stop = new LocalTime( inputStop );
LocalTime now = LocalTime.now();
// Comparing using Half-Open logic, where beginning is inclusive and ending is exclusive.
boolean isNowContainedWithinInterval = ( ( now.isEqual( start ) ) || ( now.isAfter( start ) ) ) && ( now.isBefore( stop ) );
Dump to console…
System.out.println( "start: " + start );
System.out.println( "stop: " + stop );
System.out.println( "now: " + now );
System.out.println( "isNowContainedWithinInterval: " + isNowContainedWithinInterval );
When run…
start: 09:00:00.000
stop: 17:30:00.000
now: 12:42:06.567
isNowContainedWithinInterval: true
In the real-world, I would add an assertion test proving the stop time is later than the start time, to validate inputs.

Create a Java Date from a String and vise versa

I have a date in Integer format(YYYYMMDD). And a start_time as a String (HH:mm 24 hour system). and a time_duration in hours as a double.
int date = 20140214;
String start_time = "14:30";
double duration = 50.30;
I want to use these 3 values and create 2 Java Date Objects. One is start_date and one is end_date. They should be in the format YYYY-MM-DD HH:mm.
And then after I get 2 data Strings like YYYY-MM-DD HH:mm. how can I obtain those previous variables. date, start_time, duration.
This is my attempt.
public void solve() throws IOException {
int date = 20140214;
String start_time = "14:30";
double duration = 24.50;
String startDate = "";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
startDate = getDate(date) + " " + start_time;
try {
Date start_Date = df.parse(startDate);
Date end_Date = new Date(start_Date.getTime()+(int)(duration*3600*1000));
System.out.println(df.format(start_Date));
System.out.println(df.format(end_Date));
} catch (ParseException ex) {
}
}
public String getDate(int dateInt) {
String date = "";
String dateIntString = String.valueOf(dateInt);
date = date + dateIntString.substring(0, 4) + "-";
date = date + dateIntString.substring(4, 6) + "-";
date = date + dateIntString.substring(6, 8);
return date;
}
Is there any easy way to do it. ? Or some built-in capabilities I can use other than those I have used ?
Strange Data Types For Date-Time
Using:
An int to represent the digits of a calendar date
A string to represent time-of-day digits
A double to represent a duration of fractional hours
…are all unusual approaches. Probably not the wisest choices in handling date-time values.
Avoid java.util.Date/Calendar
Know that the bundled classes java.util.Date and .Calendar are notoriously troublesome and should be avoided. Use either Joda-Time or the new java.time.* package (Tutorial) in Java 8. And get familiar with the handy ISO 8601 standard.
Time Zone
Your question and example ignore the crucial issue of time zone. Handling date-time data without time zone is like handling text files without knowing their character encoding. Not good.
Use proper time zone names to create time zone object. Avoid the non-standard 3-letter codes.
Joda-Time
In Joda-Time, a DateTime object is similar to a java.util.Date object but actually knows its own assigned time zone.
Joda-Time offers three classes for representing spans of time: Period, Duration, and Interval.
The Interval class uses the "Half-Open" approach, where the beginning is inclusive and the ending is exclusive. This approach works well for handling spans of time and comparisons. Look for the handy contains, abuts, overlap, and gap methods.
int dateInput = 20140214;
String start_timeInput = "14:30";
double durationInput = 50.30;
// Clean up these inputs.
String datePortion = Integer.toString( dateInput );
String input = datePortion + " " + start_timeInput;
DateTimeFormatter formatterInput = DateTimeFormat.forPattern( "yyyyMMdd HH:mm");
// Specify the time zone this date-time represents.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); // Or, DateTimeZone.UTC
DateTime dateTime = formatterInput.withZone( timeZone ).parseDateTime( input );
// Convert fractional hours to milliseconds, then milliseconds to a Duration object.
long millis = ( 60L * 60L * (long)(1000L * durationInput) ); // 1 hour = 60 minutes * 60 seconds * 1000 milliseconds.
Duration duration = new Duration( millis );
Interval interval = new Interval( dateTime, duration );
DateTimeFormatter formatterOutput = DateTimeFormat.forStyle( "MM" ).withLocale( Locale.FRANCE );
String description = "De " + formatterOutput.print( interval.getStart() ) + " à " + formatterOutput.print( interval.getEnd() );
Dump to console…
System.out.println( "input: " + input );
System.out.println( "dateTime: " + dateTime );
System.out.println( "duration: " + duration ); // Format: PnYnMnDTnHnMnS (from ISO 8601)
System.out.println( "interval: " + interval ); // Format: <start>/<end> (from ISO 8601)
System.out.println( "description: " + description );
When run…
input: 20140214 14:30
dateTime: 2014-02-14T14:30:00.000+01:00
duration: PT181080S
interval: 2014-02-14T14:30:00.000+01:00/2014-02-16T16:48:00.000+01:00
description: De 14 févr. 2014 14:30:00 à 16 févr. 2014 16:48:00
You have very many representations of date.
When in doubt, I usually head for getting to unix standard time (milliseconds since 1970) as soon as possible.
In this case it would be to convert the Integer date to a String, read out the four first as a year, two digits as month and the last two as day day, and then do the similar thing for the 24h time, and create a java.util.Date from this like so:
SimpleDateFormat dateParser=new SimpleDateFormat("yyyyMMdd HH:mm"); //please double check the syntax for this guy...
String yyyyMmDd = date.toString();
String fullDate = yyyyMmDd + " " + start_time;
java.util.Date startDate = dateParser.parse(fullDate);
long startTimeInMillis = startDate.getTime();
final long MILLISECONDS_PER_HOUR = 1000*60*60;
long durationInMillis = (long)duration*MILLISECONDS_PER_HOUR;
java.util.Date endDate = new java.util.Date(startTimeInMillis + durationInMillis);
Don't miss Joda time or Java 8 new, finally improved date handling named java.time.
you can write like
int date = 20140214;
String s=""+date;
Date date = new SimpleDateFormat("yyyyMMdd").parse(s);

Check if 24 hours have passed (reading from a string)

I am saving date's in a file in the following format as a string.
Sat Jul 21 23:31:55 EDT 2012
How can I check if 24 hours have passed? I am a beginner so please explain it a little bit =)
I am not sure if I completely understood the question - do you have two dates for comparison or do you wish to keep checking periodically if 24 hours have elapsed?
If comparing two date/times, I would suggest looking at joda or perhaps date4j. Using joda, one could look into using interval between two dates:
Interval interval = new Interval(previousTime, new Instant());
where previous time would be the time you mentioned
You can do something like this:
try {
// reading text...
Scanner scan = new Scanner( new FileInputStream( new File( "path to your file here..." ) ) );
String dateString = scan.nextLine();
// creating a formatter.
// to understand the format, take a look here: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
// EEE: Day name of week with 3 chars
// MMM: Month name of the year with 3 chars
// dd: day of month with 2 chars
// HH: hour of the day (0 to 23) with 2 chars
// mm: minute of the hour with 2 chars
// ss: second of the minute with 2 chars
// zzz: Timezone with 3 chars
// yyyy: year with 4 chars
DateFormat df = new SimpleDateFormat( "EEE MMM dd HH:mm:ss zzz yyyy", Locale.US );
// parsing the date (using the format above, that matches with your date string)
Date date = df.parse( dateString );
// now!
Date now = new Date();
// gets the differente between the parsed date and the now date in milliseconds
long diffInMilliseconds = now.getTime() - date.getTime();
if ( diffInMilliseconds < 0 ) {
System.out.println( "the date that was read is in the future!" );
} else {
// calculating the difference in hours
// one hour have: 60 minutes or 3600 seconds or 3600000 milliseconds
double diffInHours = diffInMilliseconds / 3600000D;
System.out.printf( "%.2f hours have passed!", diffInHours );
}
} catch ( FileNotFoundException | ParseException exc ) {
exc.printStackTrace();
}
I would suggest storing your information as a java.util.Calendar which has a compareTo ()function.
If you want to compare now to current time, you can use System.getCurrentTimeMillis() to get the current time.
Define A Day
Do you really mean one day or 24-hours? Because of Daylight Saving Time nonsense, a day can vary in length such as 23 or 25 hours in the United States.
Avoid 3-Letter Time Zone Codes
That String format is a terrible representation of a date-time. It is difficult to parse. It uses a 3-letter time zone code, and such codes are neither standardized nor unique. If possible, choose another format. The obvious choice is ISO 8601, for example: 2014-07-08T04:17:01Z.
Use proper time zone names.
Avoid j.u.Date & .Calendar
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them.
Instead use either the venerable Joda-Time library or the new java.time package bundled in Java 8 (and inspired on Joda-Time).
Joda-Time
Here is some example code in Joda-Time.
Get the current moment.
DateTime now = DateTime.now();
Parse the input string.
String input = "Sat Jul 21 23:31:55 EDT 2012";
DateTime formatter = DateTimeFormat.forPattern( "EEE MMM dd HH:mm:ss zzz yyyy" ).with Locale( java.util.Locale.ENGLISH );
DateTime target = formatter.parseDateTime( input );
Calculate 24 hours (or next day).
DateTime twentyFourHoursLater = target.plusHours( 24 );
Test if current moment happened after.
boolean expired = now.isAfter( twentyFourHoursLater );
Or, if you want next day rather than 24-hours, use plusDays rather than plusHours. If necessary, adjust to desired time zone. Time zone is crucial as it defines the day/date and applies rules for anomalies such as Daylight Saving Time.
DateTime targetAdjusted = target.withZone( DateTimeZone.forID( "Europe/Paris" ) );
…
DateTime aDayLater = targetAdjusted.plusDays( 1 ); // Go to next day, accounting for DST etc.
boolean expired = now.isAfter( aDayLater ); // Test if current moment happened after.

Categories