Is there any easy library or approach to get the week (from which date ~ date) of certain periods?
Example:
There is 6 weeks(variable) (start from 1 July, 2012 ~ 11 Aug, 2012).
I want to cut off the 6 weeks into 2 portions (variable). So the results will be
1) 1 July,2012 ~ 21 July, 2012
2) 22 July,2012 ~ 11 Aug, 2012... etc
With jodatime, I can easily get the number of weeks between certain periods though.
All I know is Start Date and End Date which both are variables and cutoffweeks amount(eg.6 weeks or 4 weeks).
final LocalDate start = new LocalDate();
final LocalDate end3 = start.plusWeeks(3)
Its not exactly clear what you want, but Joda-Time makes most things rather easy.
I guess you need something like :
public void doStruff(int cutOff){
int portion = cutoff/2;
final LocalDate start = new LocalDate();
final LocalDate end = start.plusWeeks(portion)
}
you can try this code:
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class DateDiff {
public static void main(String[] args) {
String s1 = "06/01/2012";
String s2 = "06/24/2012";
DateDiff dd = new DateDiff();
Date then = null, now = null;
DateFormat df = DateFormat.getInstance();
df.setTimeZone( TimeZone.getDefault() );
try {
then = df.parse( s1 + " 12:00 PM" );
now = df.parse( s2 + " 12:00 PM" );
} catch ( ParseException e ) {
System.out.println("Couldn't parse date: " + e );
System.exit(1);
}
long diff = dd.getDateDiff( now, then, Calendar.WEEK_OF_YEAR );
System.out.println("No of weeks: " + diff );
}
long getDateDiff( Date d1, Date d2, int calUnit ) {
if( d1.after(d2) ) { // make sure d1 < d2, else swap them
Date temp = d1;
d1 = d2;
d2 = temp;
}
GregorianCalendar c1 = new GregorianCalendar();
c1.setTime(d1);
GregorianCalendar c2 = new GregorianCalendar();
c2.setTime(d2);
for( long i=1; ; i++ ) {
c1.add( calUnit, 1 ); // add one day, week, year, etc.
if( c1.after(c2) )
return i-1;
}
}
}
Related
A duration is given.
Ex: Jan 15-March 15
I want to count the number of days which belongs to each month, in that given duration.
In this example,
number of days of January in that duration; 15
number of days of February in that duration; 28
number of days of March in that duration; 15
I'm looking for a solution other that traversing through each date of the duration and checking if Date.getMonth() = "Month I want to check against"
Is there an easier way of doing this using methods in Java Date or Java SQL Date or using any other Date type?
Map < YearMonth , Long > with lambda syntax
Here is a solution using a bit of terse code using streams and lambdas. While this solution does traverse each date of the time range, the simplicity and clarity of the code may outweigh that inefficiency.
Use LocalDate for the starting and stopping date. Use YearMonth to track each month.
LocalDate start = LocalDate.of( 2019 , 1 , 15 );
LocalDate stop = LocalDate.of( 2019 , 3 , 16 );
Make a Map to keep a number of days for each month.
Map < YearMonth, Long > map =
start
.datesUntil( stop )
.collect(
Collectors.groupingBy(
( LocalDate localDate ) -> YearMonth.from( localDate ) ,
TreeMap::new ,
Collectors.counting()
)
);
Dump to console.
{2019-01=17, 2019-02=28, 2019-03=15}
System.out.println( map );
Given a starting date, LocalDate::datesUntil provides a Stream of LocalDate objects, incremented by days.
Then just do a grouping into a SortedMap (a TreeMap) to keep months in chronological order, classified by the YearMonth and counting the days for that month in the range.
If you want the total days you can just do
long totalDays = d.datesUntil(LocalDate.of(2019, 3, 16)).count();
This is just a simple example I threw together with some basic research.
LocalDate from = LocalDate.of(2019, Month.JANUARY, 15);
LocalDate to = LocalDate.of(2019, Month.MARCH, 15);
DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("MMM");
LocalDate date = from;
while (date.isBefore(to)) {
LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
if (endOfMonth.isAfter(to)) {
endOfMonth = to;
}
// Inclusive to exclusive comparison
long days = ChronoUnit.DAYS.between(date, endOfMonth.plusDays(1));
System.out.println(days + " days in " + date.format(monthFormatter));
date = date.plusMonths(1).withDayOfMonth(1);
}
This will output
17 days in Jan.
28 days in Feb.
15 days in Mar.
There are probably better ways to achieve the same result, but as I said, I just threw it together with a little bit of Googling and trial and error.
As has already been stated, you should avoid using the older, out-of-date and effectively deprecated Date, Calendar and associated classes.
Try this. May be something like this you want. So it set a startdate and enddate, then loop for each moth till the end date and calculate the day count. I have not tested it thoroughly, but should be close to your concept.
public static void main(String[] args) throws ParseException {
String startDateS = "01/15/2019";
String endDateS = "03/15/2019";
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
Date startDate = dateFormat.parse(startDateS);
Date endDate = dateFormat.parse(endDateS);
while (endDate.compareTo(startDate) > 0) {
Calendar c = Calendar.getInstance();
c.setTime(startDate);
c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
Date endOfMonth = c.getTime();
if( endDate.compareTo(endOfMonth) > 0 )
System.out.println("Count Month " + getMonthForInt(c.get(Calendar.MONTH)) + " " + getDifferenceDays(startDate, endOfMonth));
else
System.out.println("Count Month " + getMonthForInt(c.get(Calendar.MONTH)) + " " + getDifferenceDays(startDate, endDate));
c.add(Calendar.DAY_OF_MONTH, 1);
startDate = c.getTime();
}
}
static String getMonthForInt(int num) {
String month = "wrong";
DateFormatSymbols dfs = new DateFormatSymbols();
String[] months = dfs.getMonths();
if (num >= 0 && num <= 11) {
month = months[num];
}
return month;
}
public static int getDifferenceDays(Date d1, Date d2) {
int daysdiff = 0;
long diff = d2.getTime() - d1.getTime();
long diffDays = diff / (24 * 60 * 60 * 1000) + 1;
daysdiff = (int) diffDays;
return daysdiff;
}
You can do the same using Java.time in Java 8.
public static void main(String[] args) throws ParseException {
String startDateS = "01/15/2019";
String endDateS = "03/15/2019";
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("MM/dd/yyyy");
LocalDate startDate = LocalDate.parse(startDateS, format1);
LocalDate endDate = LocalDate.parse(endDateS, format1);
while (endDate.compareTo(startDate) > 0) {
LocalDate endOfMonth = startDate.minusDays(startDate.getDayOfMonth()).plusMonths(1);
if( endDate.compareTo(endOfMonth) > 0 )
System.out.println("Count Month " + getMonthForInt(startDate) + " " + getDifferenceDays(startDate, endOfMonth));
else
System.out.println("Count Month " + getMonthForInt(startDate) + " " + getDifferenceDays(startDate, endDate));
startDate = endOfMonth.plusDays(1);
}
}
static String getMonthForInt(LocalDate startDate) {
return startDate.getMonth().getDisplayName(
TextStyle.FULL ,
Locale.US
);
}
public static long getDifferenceDays(LocalDate d1, LocalDate d2) {
// return Duration.between(d2.atStartOfDay(), d1.atStartOfDay()).toDays();
return ChronoUnit.DAYS.between(d1, d2) + 1;
}
public static void main(String[] args) throws ParseException {
String myTime = "08:00";
int diffHour = 2;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
Date d = df.parse(myTime);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
for (int i=0; i<=diffHour; i++) {
cal.add(Calendar.HOUR, i);
String newTime = df.format(cal.getTime());
System.out.println(newTime);
}
}
The output is:
08:00
09:00
11:00
I want it to be:
08:00
09:00
10:00
because in the different two hours only until 10:00 if we started with 08:00.
Why did the output jump from 10:00 to 11:00?
The answer by Draken is correct. You are adding i where you should be adding a number one 1.
java.time
You are also using old troublesome classes now outmoded by the java.time classes.
LocalTime
The LocalTime class represents a time-of-day-only value without date and without time zone.
LocalTime start = LocalTime.parse( "08:00" );
int hours = 2;
LocalTime time = start;
for ( int i = 0 ; i <= hours ; i++ ) {
String output = time.toString();
// Set up next loop.
time = time.plusHours( 1 );
}
cal.add(Calendar.HOUR, 1);
You're adding i, which will increase by one on each loop, so for the first it will add zero, then one, and then two. Instead, since you want to add by a concrete number, try instead to add just 1.
Though that does mean you would need to start at 07:00, the other choice is to put some logic in, but that depends on what you are expecting. Something like this could work:
for (int i=0; i<=diffHour; i++) {
if (i <= 1) {
cal.add(Calendar.HOUR, i);
} else {
cal.add(Calendar.HOUR, 1);
}
String newTime = df.format(cal.getTime());
System.out.println(newTime);
}
Here's a fiddle of it working
Try something like this:
package org.app.temputil;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
String myTime = "08:00";
int diffHour = 2;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
Date d = df.parse(myTime);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
for (int i = 0; i <= diffHour; i++) {
cal.add(Calendar.HOUR, i == 0 ? 0 : 1);
String newTime = df.format(cal.getTime());
System.out.println("i=[" + i + "], time=" + newTime);
}
}
}
Here is the description of your code -
for (int i=0; i<=diffHour; i++) {
cal.add(Calendar.HOUR, i);
String newTime = df.format(cal.getTime());
System.out.println(newTime);
}
Here the loop is running for i = 0, 1, 2.
For i = 0, 0 is added to calendar so that value remains same as it was earlier 8.
For i = 1, 1 is added to calendar so the value becomes 8 (earlier value) + 1 = 9
For i = 2, 2 is added to calendar so the value becomes 9 (earlier value) + 2 = 11.
To make it work,
Remove the line - cal.add(Calendar.HOUR, i);
Add this line -
if (i == 0) {
cal.add(Calendar.HOUR, 0);
} else {
cal.add(Calendar.HOUR, 1);
}
change your loop to this
for (int i=0; i<=diffHour; i++) {
String newTime = df.format(cal.getTime());
System.out.println(newTime);
cal.add(Calendar.HOUR, 1);
}
I used this code to convert number of days into respecting days,months and year
But the result are not precise because i don't take account for leap year and month with 31 days
What is the best way to solve/encounter this issue
field_Date1 and field_Date2 are input from my program
duration=field_Date2-field_Date1
duration is the number of days(int b)
In the if else i do the conversion(but the condition are not precise)
import java.util.concurrent.TimeUnit;
import java.math.RoundingMode;
import java.text.DecimalFormat;
if (field_Date1 == null || field_Date2 == null){
return "";
} else {
Date startDate = (Date)field_Date1;
Date endDate = (Date)field_Date2;
long duration = endDate.getTime() - startDate.getTime();
long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
long diff = duration - TimeUnit.DAYS.toMillis(diffInDays);
double diffToHours = TimeUnit.MILLISECONDS.toHours(diff);
float hoursToDay = (float) (diffToHours / 24.0);
float a =hoursToDay+diffInDays;
a=Math.floor(a)
int b = (int)a
if(b<30)
{
StringBuilder sb = new StringBuilder("Day: ")
sb.append(b)
String c = sb.toString()
c
}
else if(b<366)
{
int months = b/30
int days_out=b%30
StringBuilder p1 = new StringBuilder("Days: ")
StringBuilder p2 = new StringBuilder("Months: ")
StringBuilder p3 = new StringBuilder(" ")
p1.append(days_out)
p2.append(months)
p2.append(p3)
p2.append(p1)
String c=p2.toString()
c
}
else
{
StringBuilder p1 = new StringBuilder("Months: ")
StringBuilder p2 = new StringBuilder("Years: ")
StringBuilder p3 = new StringBuilder(" ")
StringBuilder p4 = new StringBuilder("Days: ")
int years = b/365
int days_out=b%365
if(days_out>30)
{
int m1 = days_out/30
int m2 = days_out%30
p2.append(years)
p1.append(m1)
p4.append(m2)
p2.append(p3)
p2.append(p1)
p2.append(p3)
p2.append(p4)
String hj = p2.toString()
return hj
}
else
{
p4.append(days_out)
p2.append(years)
p2.append(p3)
p2.append(p4)
String c=p2.toString()
return c
}
}
}
Joda-Time
Try using Joda-Time 2.5:
Snippet will look something like this:
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.Days;
Date startDate = (Date)field_Date1;
Date endDate = (Date)field_Date2;
int days = Days.daysBetween( new DateTime(startDate), new DateTime(endDate) ).getDays();
java.time
Or the following method from java.time (Java8) can be used:
public static Period between(LocalDate startDateInclusive,
LocalDate endDateExclusive)
This obtains a period between two dates, consisting of the number of years, months, and days.
If you want the difference between two dates in days, including taking into account leap years etc, the java.time package (new in Java 8) gives you:
LocalDate firstDate = LocalDate.of(2014, Month.DECEMBER, 1);
LocalDate secondDate = LocalDate.of(2016, Month.MARCH, 12);
long days = firstDate.until(secondDate,ChronoUnit.DAYS);
gives you 467 days.
Alternatively,
Period period = firstDate.until(secondDate);
will give you a Period object, which stores the time broken down into years, months and days ie. instead of 467 days, you get 1 year, 3 months and 11 days. This is good for human readability. However, if you want the total days, it's not easy to get that from the Period object, so you're better off going with the first option I gave.
This question was asked in my interview.
String d1="7 dec 2012";
String d2="15 dec 2012";
String d3="12 dec 2012";
String d4="16 dec 2012";
String d5="16 dec 2012";
String d6="24 dec 2012";
Number of days between d1 and d2 is: 9
Number of days between d3 and d4 is: 1 (12 Dec to 15 Dec counted in d1 and d2,
don't count overlapping days)
Number of days between d3 and d4 is: 8 (16 Dec counted in d3 and d4,
don't count overlapping days)
Now final output should be: 9 + 1 + 8
What algorithm should I use?
Below Code is basic coding(Very simple basic approach) to calculate the date difference between 2 days. It does not take into account the daylight savings and any overlapping dates.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class TestJava {
public static int daysBetween(Date d1, Date d2)
{
/*This function returns the difference in days given 2 dates as input*/
return (int)( (d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
}
public static void main(String args[]) throws ParseException
{
Calendar cal1 = new GregorianCalendar();
Calendar cal2 = new GregorianCalendar();
SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
Date date = sdf.parse("07122012"); // Date1
cal1.setTime(date);
date = sdf.parse("15122012"); // Date2
cal2.setTime(date);
int daysBetween = daysBetween(cal1.getTime(),cal2.getTime()); // Days between Date1 and Date2
int interval = daysBetween(cal1.getTime(),cal2.getTime());
System.out.println("Interval1 == "+ interval);
date = sdf.parse("12122012"); // Date3
cal1.setTime(date);
date = sdf.parse("16122012"); // Date4
cal2.setTime(date);
daysBetween += daysBetween(cal1.getTime(),cal2.getTime()); // Days between Date3 and Date4 is added to the previously available value of days between Date1 and Date2
interval = daysBetween(cal1.getTime(),cal2.getTime());
System.out.println("Interval2 == "+ interval);
date = sdf.parse("16122012");
cal1.setTime(date);
date = sdf.parse("24122012");
cal2.setTime(date);
daysBetween += daysBetween(cal1.getTime(),cal2.getTime()); // Total required difference as per the question
interval = daysBetween(cal1.getTime(),cal2.getTime());
System.out.println("Interval3 == "+ interval);
System.out.println("Total Interval == "+ daysBetween);
}
}
The problem should be solved in three steps:
step 1: Find the number of overlapping days.
step 2: Find the difference between the dates given.
step 3: Subtract the difference obtained in step 2 by the number of overlapping days obtained in step 1, which will give u the exact difference between the dates with out overlapping dates counted.........!
The Code below will serve your purpose:
package mypack;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DatesNoOverlap
{
public static void main(String args[])
{
String d[]=new String[6];
d[0]="7/12/2012";
d[1]="15/12/2012";
d[2]="12/12/2012";
d[3]="16/12/2012";
d[4]="16/12/2012";
d[5]="24/12/2012";
int num[]=new int[6];
int counter=0;
for(int i=0;i<d.length;i++)
{
for(int j=0;j<d[i].length();j++)
{
if(d[i].charAt(j)=='/')
{
num[counter]=Integer.parseInt(d[i].substring(0,j));
counter++;
break;
}
}
}
int sum1=0;
for(int m=0;m<counter-1;m++)
{
if(m>0&&m%2!=0)
{
if(num[m+1]<=num[m])
{
sum1=sum1+(num[m]-num[m+1]+1);
}
}
}
System.out.println("Number of overlapping days........="+sum1);
long sum2=0;
for(int n=0;n<counter-1;n=n+2)
{
SimpleDateFormat format = new SimpleDateFormat("dd/mm/yyyy");
Date d1 = null;
Date d2 = null;
try {
d1 = format.parse(d[n]);
d2 = format.parse(d[n+1]);
//in milliseconds
long diff = d2.getTime() - d1.getTime();
long diffDays = diff / (24 * 60 * 60 * 1000);
sum2=sum2+diffDays+1;
}
catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Complete Difference = "+sum2);
System.out.println("Exact Difference = "+(sum2-sum1));
}
}
I'm working on a report that calculates a sum of the data in it and some of the data are timestamps, for example:
----------------------
| Activity | Time |
----------------------
| 1 | 11:00:00 |
-----------------------
| 2 | 12:00:00 |
-----------------------
| 3 | 13:00:00 |
-----------------------
| Total | 36:00:00 |
----------------------
I'm trying to sum timestamps as below:
final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
final Calendar c = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
c.setTimeInMillis(0);
for (final String t : timestampsList) {
c.add(Calendar.MILLISECOND, (int) dt.parse(t).getTime());
}
The variable timestampsList is an ArrayList of String's, all respecting the pattern used by the SimpleDateFormat object. The problem with the given code is that I can't generate the value of the sum of the timestamps, by using the same SimpleDateFormat what I get is an hour in the pattern informed in a future date.
I also have seen Joda Time Duration class but I'm not familiar with this lib and I 'don't know if I'm in a correct path that will lead me to the right answer.
Does anyone know how to handle it by using J2SE or Joda Time?
I would just parse these Strings myself, convert them to
seconds or milliseconds and sum them up. See answer 2 below.
ANSWER 1
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
public class Test051 {
public static void main(String[] args) throws Exception {
String pt = "1970-01-01-";
ArrayList<String> timestampsList = new ArrayList<String>();
timestampsList.add("01:00:05");
timestampsList.add("01:00:05");
timestampsList.add("10:00:05");
final DateFormat dt = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
final Calendar sum = Calendar.getInstance();
sum.setTimeInMillis(0);
long tm0 = new SimpleDateFormat("yyyy-MM-dd").parse(pt).getTime();
System.out.println("tm0 = " + tm0);
for (final String t : timestampsList) {
// System.out.println(dt.parse(pt + t).getTime());
Date x = dt.parse(pt + t);
// System.out.println(x.getTime());
sum.add(Calendar.MILLISECOND, (int)x.getTime());
sum.add(Calendar.MILLISECOND, (int)-tm0);
}
long tm = sum.getTime().getTime();
System.out.println("tm = " + tm);
tm = tm / 1000;
long hh = tm / 3600;
tm %= 3600;
long mm = tm / 60;
tm %= 60;
long ss = tm;
System.out.println(format(hh) + ":" + format(mm) + ":" + format(ss));
}
private static String format(long s){
if (s < 10) return "0" + s;
else return "" + s;
}
}
ANSWER 2
import java.util.ArrayList;
public class Test051 {
public static void main(String[] args) throws Exception {
ArrayList<String> timestampsList = new ArrayList<String>();
timestampsList.add("01:00:05");
timestampsList.add("01:00:05");
timestampsList.add("10:00:05");
long tm = 0;
for (String tmp : timestampsList){
String[] arr = tmp.split(":");
tm += Integer.parseInt(arr[2]);
tm += 60 * Integer.parseInt(arr[1]);
tm += 3600 * Integer.parseInt(arr[0]);
}
long hh = tm / 3600;
tm %= 3600;
long mm = tm / 60;
tm %= 60;
long ss = tm;
System.out.println(format(hh) + ":" + format(mm) + ":" + format(ss));
}
private static String format(long s){
if (s < 10) return "0" + s;
else return "" + s;
}
}
ANSWER 3
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
public class Test051 {
public static void main(String[] args) throws Exception {
ArrayList<String> timestampsList = new ArrayList<String>();
timestampsList.add("01:00:00");
timestampsList.add("02:00:00");
timestampsList.add("03:00:00");
timestampsList.add("04:00:00");
timestampsList.add("02:00:00");
timestampsList.add("04:00:00");
Date dt0 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01");
// Check very carefully the output of this one.
System.out.println(dt0.getTime());
final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
final Calendar c = Calendar.getInstance();
c.setTimeInMillis(0);
for (final String t : timestampsList) {
c.add(Calendar.MILLISECOND, (int) dt.parse(t).getTime());
c.add(Calendar.MILLISECOND, (int)-dt0.getTime());
}
// We need to add this back. This is basically the time zone offset.
c.add(Calendar.MILLISECOND, (int)dt0.getTime());
System.out.println(c.getTime().getTime());
System.out.println(c.getTimeInMillis());
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(c.getTime()));
System.out.println(new SimpleDateFormat("HH:mm:ss").format(c.getTime()));
}
}
If you don't wanna use peter petrov solution to parse your String yourself, the way to do it with Calendar and SimpleDateFormat is as follow :
List<String> timestampsList = new ArrayList<String>();
timestampsList.add("11:00:00");
timestampsList.add("12:00:00");
timestampsList.add("13:00:00");
final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
final Calendar c = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
long milliseconds = 0;
c.clear();
long startingMS = c.getTimeInMillis();
for (final String t : timestampsList) {
milliseconds = milliseconds + (dt.parse(t).getTime() - startingMS);
}
System.out.println(milliseconds + " milliseconds");
System.out.println(milliseconds / 1000 + " seconds");
System.out.println(milliseconds / 1000 / 60 + " minutes");
System.out.println(milliseconds / 1000 / 60 / 60 + " hours");
Or use
long startingMS = dt.parse("00:00:00").getTime();
for (final String t : timestampsList) {
milliseconds = milliseconds + (dt.parse(t).getTime() - startingMS);
}
instead, removing the need for the Calendar.
Both result in :
129600000 milliseconds
129600 seconds
2160 minutes
36 hours
Note that you might wanna make the results a double not to miss part of the time.
This is a original code from petrov with some edits made by me. Since it's quite dificult to discuss in comments providing big snippets of code I posted it as an answer so we can discuss petrov's other considerations.
public static void somaTempos(final String[] listaTempos) throws ParseException {
long tm = 0;
final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
final Calendar c = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
for (String tmp : listaTempos) {
c.setTime(dt.parse(tmp));
tm += c.get(Calendar.SECOND) + 60 * c.get(Calendar.MINUTE) + 3600 * c.get(Calendar.HOUR_OF_DAY);
}
final long l = tm % 3600;
System.out.println(SIGRUtil.format(tm / 3600) + ':' + SIGRUtil.format(l / 60) + ':' + SIGRUtil.format(l % 60));
}
private static String format(long s) {
if (s < 10) {
return "0" + s;
}
return String.valueOf(s);
}
UPDATE: An alternative that also solves my problem:
public static String sumTimes(final String[] timestampList) {
long milliseconds = 0;
final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
dt.setLenient(false);
try {
final long timezoneOffset = dt.parse("00:00:00").getTime();
for (final String t: timestampList) {
milliseconds += (dt.parse(t).getTime() - timezoneOffset);
}
} catch (final ParseException e) {
throw new BusinessException(
"One of the timestamps in the timestamp list cannot be applied to the HH:mm:ss pattern.", e);
}
((SimpleDateFormat) dt).applyPattern(":mm:ss");
return new StringBuilder(8).append(milliseconds / 3600000).append(
dt.format(new Date(milliseconds))).toString();
}
Actually, the API gives me for free the minutes and the seconds by only reaplying another pattern in the DateFormat after calculating the sum of the time stamps, without forgetting to consider the timezone offset in this calculation, my real problem was how to calculate the number of hours which really is the less dificult part.
Any suggestions of improvements?
If those data input Strings represent durations in hours:minutes:seconds without any date or time-of-day, then the other answers are working much too hard.
Generally, the old java.util.Date and .Calendar classes are notoriously troublesome and should be avoided. Specifically here, those classes have no notion of a span of time. Instead you should be using either Joda-Time or maybe java.time.
Joda-Time
Joda-Time offers three classes to represent a span of time: Interval, Period, and Duration. The first is tied to points along the timeline of the Universe. The other two are not.
The Period and Duration classes are very close cousins. Period is a tuple with a number of years, months, days, hours, minutes, and seconds. Duration is a number of milliseconds with no concept of fields such as days or seconds.
Joda-Time uses the ISO 8601 standard for its defaults in parsing and generating strings. For period/duration time, this means the PnYnMnDTnHnMnS format. The P means "period" and the T is a separator between date and time portions.
Here is some example code in Joda-Time 2.3. Basically a couple of lines: parsePeriod & durationSum.plus seen below.
Simulate input strings.
List<String> durationStrings = new ArrayList<String>();
durationStrings.add( "11:00:00" ); // Number of hours/minutes/seconds. Not time-of-day.
durationStrings.add( "12:00:00" );
durationStrings.add( "13:00:00" ); // Expect sum of 36 hours = 11 + 12 + 13.
Define a formatter to parse those strings. Joda-Time might have such a formatter built-in, but I could not locate it. So I defined one.
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours()
.appendSeparator( ":" )
.appendMinutes()
.appendSeparator( ":" )
.appendSeconds()
.toFormatter();
Loop the input strings, parsing each one, then adding its duration to the sum.
Duration durationSum = Duration.ZERO; // Initializing to empty amount. Add to this in loop below.
for ( String durationString : durationStrings ) {
Period period = formatter.parsePeriod( durationString );
Duration duration = period.toStandardDuration();
durationSum = durationSum.plus( duration );
System.out.println( "period: " + period );
System.out.println( "duration: " + duration );
}
System.out.println( "durationSum: " + durationSum );
System.out.println( "durationSum as Period: " + durationSum.toPeriod() );
When run…
period: PT11H
duration: PT39600S
period: PT12H
duration: PT43200S
period: PT13H
duration: PT46800S
durationSum: PT129600S
durationSum as Period: PT36H