I am trying to implement Joda-Time to count down to Christmas, but so far I'm struck. I tried java.util.Date and most StackOverflow questions and answers suggested to use Joda-Time. But I can't get it working. Some codes give different answers.
Here are some codes I tried,
DateTime now = new DateTime();
DateTime christmas = new DateTime(2012, 12, 25, 8, 0, 0, 0);
Days daysToChristmas = Days.daysBetween(today, christmas);
System.out.println(daysToChristmas.toString());
And this prints P187D as answer.
DateTime start = new DateTime(DateTime.now());
DateTime end = new DateTime(2012, 12, 25, 0, 0, 0 ,0);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println("Seconds " + period.getSeconds());
System.out.println("Minutes " + period.getMinutes());
System.out.println("Hours " + period.getHours());
System.out.println("Days " + period.getDays());
And this prints following result,
Seconds 36
Minutes 21
Hours 7
Days 4
Where I went wrong?
You should be using a Period in order to determine the number of months/days/etc involved:
Period period = new Period(start, end);
Converting an Interval to a period would have been fine too, but parameterless overload includes all period units - and you weren't printing out the months.
Now if you only want days, hours, minutes, seconds then you need to create an appropriate PeriodType, e.g.
PeriodType periodType = PeriodType.dayTime().withMillisRemoved();
Period period = new Period(start, end, periodType);
Then you can ask for those individual fields, and all should be well.
(You could actually use just dayTime(), given that the millis won't interfere with anything else.)
So you can either build your period directly from the start and end as above, or if you want to keep the Interval, you can use:
Period period = interval.toPeriod(periodType);
The first code prints P187D, in ISO 8601 format.
The second code prints only 4 days because you're missing the months (period.getMonths()).
You can use this code.
DateTime dt1 = new DateTime();
DateTime dt2 = new DateTime(2012, 12, 25, 0, 0, 0, 0);
int seconds=Seconds.secondsBetween(dt1, dt2).getSeconds();
int noOfDays=seconds/(24*60*60);
int noOfHours=(seconds%(24*60*60))/(60*60);
int noOfMinutes=((seconds%(24*60*60))%(60*60))/60;
int noSec=((seconds%(24*60*60))%(60*60))%60;
System.out.println("Time Left For christmas");
System.out.println("Days Left="+noOfDays+" Hours="+noOfHours+" Minutes="+noOfMinutes+" Seconds="+noSec);
Related
I am creating a Workday calendar program that calculates a 'start' and 'end' date
the results should output:
"Starting date: 24-05-2004 07:03 with addition of 8.276628 working days is end date: 04-06-2004 10:12"
or
24-05-2004 18:03 with the addition of -6.7470217 working days is 13-05-2004 10:02
The mathematical solution is to multiply hours pr day with incrementInWokringdays
like 8.0f hours a day * 2.5f days = 18.4f hours and then the result of this should be added to the Date calendar this way
-date.add( Calendar.Hours_of_Day, 18.0f ) //but from float converted to integers
-date.add( Calendar.Minutes_of_Day, 0.4f )//
how do i split the value 18.4f hours in to
'int hours = 18;'
and
'int minutes = 40;'
????
public Date getWorkdayIncrement(Calendar date, float incrementInWorkdays) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm");
System.out.println("start day: " + f.format(date.getTime()));
// so if chosen incrementDays is 2.3 days and workinghours pr day is 7.5h you multiply them together to get total working hours
float totalHoursWorkedPrDay = getWorkdayStartAndStop() * incrementInWorkdays;
// needed to convert hours and minutes to integer values in order to increment calendar
int hoursToIncrement = (int) totalHoursWorkedPrDay; //gets only hours
// get the last to decimals 0.25 representing the minutes which means 25 percent of 60min
float lastTwoDecimalsOfTotalWorkingHours = ((totalHoursWorkedPrDay - (float) hoursToIncrement) * 100);
//calculate percent of minutes and convert to integer (25 / 100 * 60) = 15min
int minutesToIncrement = (int) ((lastTwoDecimalsOfTotalWorkingHours / 100) *60);
System.out.println("Hours to increment: " + hoursToIncrement);
System.out.println("Minutes to increment: " + minutesToIncrement);
//increment calendar
date.add(Calendar.HOUR_OF_DAY, hoursToIncrement);
date.add(Calendar.MINUTE, minutesToIncrement);
Date endDate = date.getTime();
System.out.println("End date excluding holidays: " + f.format(endDate));
}
I didn’t follow everything you were doing in the question. So for now I focus on calculating the working hours of a working day given start and end time. I am assuming that you get start and end as GregorianCalendar objects from some legacy API that you cannot afford to upgrade to java.time just now.
I recommend that you use java.time, the modern Java date and time API, for your date and time work. Even if you are getting your data as objects of the old-fashioned date-time types. java.time is so much nicer to work with.
static float getHoursBetween(Calendar start, Calendar end) {
ZonedDateTime startZdt = ((GregorianCalendar) start).toZonedDateTime();
ZonedDateTime endZdt = ((GregorianCalendar) end).toZonedDateTime();
long wholeDays = ChronoUnit.DAYS.between(startZdt, endZdt);
startZdt = startZdt.plusDays(wholeDays);
Duration workDay = Duration.between(startZdt, endZdt);
return (float) workDay.toMinutes() / (float) Duration.ofHours(1).toMinutes();
}
The method ignores the date difference between start and end by adding the number of full days to the start time. This means that the result we get is based only on the hours and minutes. To try the method out, let’s construct a couple of GregorianCalendar objects (of course I am using java.time for that too):
ZoneId zone = ZoneId.of("America/Araguaina");
ZonedDateTime workDayStart = ZonedDateTime.of(2020, 6, 14, 7, 30, 0, 0, zone);
Calendar workDayStartCal = GregorianCalendar.from(workDayStart);
ZonedDateTime workDayEnd = ZonedDateTime.of(2020, 6, 15, 15, 15, 0, 0, zone);
Calendar workDayEndCal = GregorianCalendar.from(workDayEnd);
float workingDay = getHoursBetween(workDayStartCal, workDayEndCal);
System.out.println(workingDay);
Output from the example is:
7.75
Edit: for the opposite conversion this works since Java 9:
float hours = 7.75f;
Duration dur = Duration.ofMinutes(Math.round(hours * Duration.ofHours(1).toMinutes()));
System.out.println("Hours: " + dur.toHours());
System.out.println("Minutes: " + dur.toMinutesPart());
Hours: 7
Minutes: 45
Link
Oracle tutorial: Date Time explaining how to use java.time.
How can I get the number of hours since the start of January 1 of the current year in Java? I. e. first hour of January 1 = 0001
Can I accomplish this with JodaTime or any other lib?
Thanks,
Using the java.time package built into Java 8 and later (Tutorial):
ChronoUnit.HOURS.between(
LocalDateTime.of(LocalDateTime.now().getYear(), 1, 1, 0, 0),
LocalDateTime.now())
I think this is self-explenatory
Use the Java 8 API for date/time
LocalDateTime hournow = LocalDateTime.now();
LocalDateTime startOfYear = LocalDateTime.of(hournow.getYear(), 1, 1, 0, 0);
long hoursBetween = ChronoUnit.HOURS.between(startOfYear, hournow);
System.out.println("hours between: " + hoursBetween);
I strongly suspect that many users will rather expect to take dst-effects into account:
ZoneId zi = ZoneId.of("Europe/Paris"); // example
ZonedDateTime now = ZonedDateTime.now(zi);
ZonedDateTime start = ZonedDateTime.of(now.getYear(), 1, 1, 0, 0, 0, 0, zi);
long realDelta = ChronoUnit.HOURS.between(start, now);
System.out.println("hours between: " + realDelta); // 5386
// another way using Instant
Instant i2 = now.toInstant();
Instant i1 = start.toInstant();
System.out.println(i1); // 2014-12-31T23:00:00Z
System.out.println(i2); // 2015-08-13T09:55:53.353Z
System.out.println("duration=" + i1.until(i2, ChronoUnit.HOURS)); // 5386
The proposed solutions so far based on LocalDateTime without any time zone would yield a different result (here only a nominal and not a physical Duration):
LocalDateTime ldt2 = LocalDateTime.now();
LocalDateTime ldt1 = LocalDateTime.of(ldt2.getYear(), 1, 1, 0, 0);
long hoursBetween = ChronoUnit.HOURS.between(ldt1, ldt2);
System.out.println("hours between: " + hoursBetween); // 5385
In case of java.util.GregorianCalendar the result will be the same as for Java-8 based on ZonedDateTime. Other libraries also offer similar results but I leave out such details because it is more important to understand the impact of timezones on your result.
This question already has answers here:
Calculating the difference between two Java date instances
(45 answers)
Closed 7 years ago.
Im trying to calculate the time difference between 2 Timestamps, this is the code:
Calendar calendar = Calendar.getInstance();
java.util.Date now = calendar.getTime();
Timestamp currentTimestamp = new Timestamp(now.getTime());
System.out.println("Current\n"+currentTimestamp);
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = dateFormat.parse("28/02/2015");
Timestamp timestampBefore = new Timestamp(date.getTime());
System.out.println("Before\n"+timestampBefore);
Timestamp calculated = new Timestamp(currentTimestamp.getTime() - timestampBefore.getTime());
System.out.println("Calculated\n"+calculated);
Output:
Current
2015-02-28 12:12:40.975
Before
2015-02-28 00:00:00.0
Calculated
1970-01-01 13:12:40.975
I can understand why it returns 1970-01-01 but why does it return 13:12:40.975 ,1 hour more?
How to calculate the difference between 2 dates so the output is like this (based on this example):
Years:0, Months:0, Days:0, Hours:12, Minutes:12, Seconds:40 ?
Update: for java below 1.8 check out http://www.joda.org/joda-time/index.html
and for java 1.8 see answer.
Similar solution here: Java 8: Calculate difference between two LocalDateTime
(1) A timestamp is a point in time. If you calculate the difference between two timestamps, the result is not a timestamp (point in time), but a duration. So it is nonsense to convert the difference to a timestamp, hence it is useless to discuss the reason why the result is strange.
(2) You should probably use the new Java 8 time API (if you are able to use Java 8):
LocalTime now = LocalTime.now();
LocalTime previous = LocalTime.of(0, 0, 0, 0);
Duration duration = Duration.between(previous, now);
System.out.println(now);
System.out.println(previous);
System.out.println(duration);
Note that this just calculates the duration between two times of a day (hour-minute-second). If your want to include date information, use LocalDateTime instead:
LocalDateTime nextFirework = LocalDate.now()
.with(TemporalAdjusters.firstDayOfNextYear())
.atTime(LocalTime.MIDNIGHT);
LocalDateTime now = LocalDateTime.now();
// duration (in seconds and nanos)
Duration duration = Duration.between(now, nextFirework);
// duration in total hours
long hours = now.until(nextFirework, ChronoUnit.HOURS);
// equals to: duration.toHours();
If you want to have 'normalized' duration in years/months/days/hours/seconds, there is suprisingly no direct support. You could convert the duration to days, hours, minutes and seconds by yourself:
long d = duration.toDays();
long h = duration.toHours() - 24 * d;
long m = duration.toMinutes() - 60 * duration.toHours();
long s = duration.getSeconds() - 60 * duration.toMinutes();
System.out.println(d + "d " + h + "h " + m + "m " + s + "s ");
But note that you will have difficulties converting the days into months and years, as there is no unique number of days per month and a year can be a leap year with 366 days. For that, you can use Period, as in opposite to Duration, this class is associated with a timeline. Unfortunately, Period does only support dates, but no times:
// period in years/months/days (ignoring time information)
Period p = Period.between(now.toLocalDate(), nextFirework.toLocalDate());
System.out.println(p); // or use p.getYears(), p.getMonths(), p.getDays()
So probably you could combine both approaches - first, compute the Period from the dates and then the Duration using the times. Note that the duration can be negative, so you'll have to take care of that in case of:
Duration dur = Duration.between(start.toLocalTime(), end.toLocalTime());
LocalDate e = end.toLocalDate();
if (dur.isNegative()) {
dur = dur.plusDays(1);
e = e.minusDays(1);
}
Period per = Period.between(start.toLocalDate(), e);
System.out.println(per.toString() + ", " + dur.toString());
I'm trying to calculate the difference between two days in amount of days. For some reason comparing 01-03-2013 and 01-04-2013 gives the result 30, as does comparing 01-03-2013 and 31-03-2013
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2013, Calendar.MARCH, 1);
Date start = cal.getTime();
cal.set(2013, Calendar.APRIL, 1);
Date end = cal.getTime();
long days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime());
System.out.println("!!! Amount of days : " + String.valueOf(days));
>> 30
cal.set(2013, Calendar.MARCH, 1);
start = cal.getTime();
cal.set(2013, Calendar.MARCH, 31);
end = cal.getTime();
days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime());
System.out.println("!!! Amount of days : " + String.valueOf(days));
>> 30
Why is this?
You will get those results if daylight savings started in your time zone on 31 March.
Between 1 March and 1 April, you have 30 24-hour days and one 23-hour day, because of the start of daylight savings. If you divide the total number of milliseconds by 24 x 60 x 60 x 1000, then you will get 30 plus 23/24. This gets rounded down to 30.
Time Zone
The correct answer by David Wallace explains that Daylight Saving Time or other anomalies affects the results of your code. Relying on default time zones (or outright ignoring time zones) will get you into this kind of trouble.
Make Span Inclusive-Exclusive
Also, the proper way to define a span of time is to make the beginning inclusive and the ending exclusive. So if you want the month of March, you need to go from first moment of first day to first moment of first day after March (April 1).
For lengthy discussion of this idea, see my other answers such as this one and this one.
Here's a diagram of mine lifted from other answers:
Joda-Time
The java.util.Date/Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use either Joda-Time, or in Java 8, the new java.time.* package (inspired by Joda-Time).
The Joda-Time 2.3 library provides classes dedicated to spans of time: Period, Duration, and Interval. That library also has some handy static utility methods, such as Days.daysBetween.
Joda-Time's DateTime objects do know their own time zone, unlike java.util.Date/Calendar which seem to have a time zone but do not.
// Specify a timezone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime marchFirst = new DateTime( 2013, DateTimeConstants.MARCH, 1, 0, 0, 0, timeZone );
DateTime aprilFirst = new DateTime( 2013, DateTimeConstants.APRIL, 1, 0, 0, 0, timeZone );
int days = Days.daysBetween( marchFirst, aprilFirst).getDays();
Dump to console…
System.out.println( "marchFirst: " + marchFirst );
System.out.println( "aprilFirst: " + aprilFirst ); // Note the change in time zone offset in the output.
System.out.println( "days: " + days );
When run, notice:
The correct answer: 31
The difference in time zone offset because of Daylight Saving Time in France.
marchFirst: 2013-03-01T00:00:00.000+01:00
aprilFirst: 2013-04-01T00:00:00.000+02:00
days: 31
When I run this version of your code here in United States west coast time zone:
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.clear();
cal.set( 2013, java.util.Calendar.MARCH, 1 );
java.util.Date start = cal.getTime();
cal.set( 2013, java.util.Calendar.APRIL, 1 );
java.util.Date end = cal.getTime();
long days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays( end.getTime() - start.getTime() );
System.out.println( "!!! Amount of days : " + String.valueOf( days ) );
cal.set( 2013, java.util.Calendar.MARCH, 1 );
start = cal.getTime();
cal.set( 2013, java.util.Calendar.MARCH, 31 );
end = cal.getTime();
days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays( end.getTime() - start.getTime() );
System.out.println( "!!! Amount of days : " + String.valueOf( days ) );
I get:
!!! Amount of days : 30
!!! Amount of days : 29
For explanation, see comment by David Wallace on this answer.
Daylight Saving Time (United States) 2013 began at 2:00 AM on Sunday, March 10.
I executed same code in my system it is giving me output as :
!!! Amount of days : 31
please check your code again.
I create J2SE application and this application needs to format two times in milliseconds into a string that represents the interval between this two times.
long time1 = 1334331041677L; //Fri Apr 13 17:30:41 CEST 2012
long time2 = time1+1000*60*2; //Fri Apr 13 17:32:41 CEST 2012
and I would like to get something like "00:02:00". This would be simple, but I need to format interval which is long from few seconds up to several years - so the library should handle it. Ideally is if this library could format the interval according to the habbits of the country (if any).
I have searched throught the questions and answers and solution for me could be Jodatime or Lang library from Apache Commons. Could you provide me some recommendation which library from these solves my requirements in better way? Thank you in advance.
PeriodFormat in Joda Time is probably what you want - but you'll need to think very carefully about how you want to format values of more than a day. Bear in mind that months and years are of variable lengths - if you're happy to have the largest unit as a day, that would probably keep things simple.
You should also be aware of the difference in Joda Time between a Period (which can include things like "months") and a Duration which is a fixed number of milliseconds. Normalization between the two touches on exactly the problems mentioned above :) Basically, you should work out whether you're interested in the difference in elapsed time between two instants in time, or the difference in "calendar" time between two local date/time values. For example, between midnight and 2am on a particular date in a particular time zone may be 1 hour, 2 hours or 3 hours of elapsed time...
You can use standard Java Calendar for intervals up to one day (24 hours). It is not possible to use this trick for longer periods (days, years), though...
long start = System.currentTimeMillis();
/*
* perform the measured activity here,
* let's say it will take 2 minutes 5 seconds => 125 seconds => 125000ms
*/
Thread.sleep(125 * 1000);
long stop = System.currentTimeMillis();
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.setTimeInMillis(c.getTimeInMillis() + (stop - start));
DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
System.out.println(df.format(c.getTime()));
If I understood you correctly, the following (using Joda Time) should help
import org.joda.time.DateTime;
import org.joda.time.Period;
private String formatDuration(DateTime dt1, DateTime dt2) {
Period period = new Period(dt1, dt2);
String str = String.format("%s:%02d:%02d:%02d:%02d:%02d",
period.getYears(), period.getMonths(), period.getDays(),
period.getHours(), period.getMinutes(), period.getSeconds());
// Ignoring milliseconds
String[] tokens = str.split(":");
boolean currNonZero = false, flag = false, isFirst = true;
int ctr = 0, pos = 0;
StringBuilder sb = new StringBuilder();
for (String token : tokens) {
pos++;
int val = Integer.parseInt(token);
currNonZero = (val > 0);
if ((ctr < 3 && (flag || currNonZero)) || (ctr == 0 && pos > 3)) {
if (isFirst) { isFirst = false; }
else { sb.append(":"); }
sb.append(token);
flag = (++ctr < 3);
}
}
return sb.toString();
}
A few tests,
DateTime dt1 = new DateTime(2012, 1, 1, 8, 3, 5, 0);
DateTime dt2 = new DateTime(2012, 1, 2, 9, 5, 6, 0);
DateTime dt3 = new DateTime(2012, 2, 3, 11, 3, 5, 0);
DateTime dt4 = new DateTime(2012, 2, 3, 11, 3, 10, 0);
DateTime dt5 = new DateTime(2012, 2, 3, 11, 3, 10, 5); //5 millis away from dt4
formatDuration(dt1, dt2); // Returns "01:01:01"
formatDuration(dt1, dt3); // Returns "01:02:03"
formatDuration(dt3, dt4); // Returns "00:00:05"
formatDuration(dt4, dt5); // Returns "00:00:00"
According to this answer, this is the most efficient way of formatting elapsed time:
public static String combinationFormatter(final long millis) {
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis));
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis)
- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis));
long hours = TimeUnit.MILLISECONDS.toHours(millis);
StringBuilder b = new StringBuilder();
b.append(hours == 0 ? "00" : hours < 10 ? String.valueOf("0" + hours) :
String.valueOf(hours));
b.append(":");
b.append(minutes == 0 ? "00" : minutes < 10 ? String.valueOf("0" + minutes) :
String.valueOf(minutes));
b.append(":");
b.append(seconds == 0 ? "00" : seconds < 10 ? String.valueOf("0" + seconds) :
String.valueOf(seconds));
return b.toString();
}
Detailed Answer: https://stackoverflow.com/a/39600534/5330578
Simple formatting for elapsed time less than 24h. Over 24h the code will only display the hours within the next day and won't add the elapsed day to the hours.
public static String formatElapsedTime(long milliseconds) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(milliseconds);
}