Military Time Difference in Java - java

Here's my TimeInterval class:
public class TimeInterval {
private int fTime;
private int sTime;
public TimeInterval(int fTime, int sTime) {
if(fTime < 0 || fTime > 2400 || sTime < 0 || sTime > 2400) {
System.out.println("Illegal times, must be < 2400 and > 0)");
System.exit(0);
} else {
this.fTime = fTime;
this.sTime = sTime;
}
}
public int getHours() {
return Math.abs((fTime - sTime) / 100);
}
public int getMinutes() {
return Math.abs((fTime - sTime) % 100);
}
public double getDecimalTime() {
return getHours() + ((double) getMinutes() / 60);
}
}
and my tester class:
import java.util.*;
public class TestTimeInterval {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Please enter the first time: ");
int fTime = s.nextInt();
System.out.print("Please enter the second time: ");
int sTime = s.nextInt();
TimeInterval t = new TimeInterval(fTime, sTime);
System.out.printf("%s: %2d hours %2d minutes \n", "Elapsed time in hrs/min ", t.getHours(), t.getMinutes());
System.out.printf("%s: %.2f", "Elapsed time in decimal", t.getDecimalTime());
}
}
However, it calculates certain time correctly, but if I enter for example 0150 and 0240, the difference should be 50 minutes, but instead it displays 90, and I need to make it not go over 60, and transform the remainder to hours and minutes. While if I enter some other numbers, it works. Any help is appreciated.

tl;dr
Duration
.between(
LocalTime.parse( "0150" , DateTimeFormatter.ofPattern( "HHmm" ) ) ,
LocalTime.parse( "0240" , DateTimeFormatter.ofPattern( "HHmm" ) )
)
.toString()
PT50M
Details
Perhaps you are just working on homework. If so, make that clear in your Question.
But you should know that Java provides classes for this purpose.
java.time
The modern approach uses the java.time classes. These classes work in 24-hour clock by default.
LocalTime
For a time-of-day without a date and without a time zone, use LocalTime.
LocalTime start = LocalTime.of( 1 , 50 );
LocalTime stop = LocalTime.of( 2 , 40 );
Duration
Calculate elapsed time as a Duration.
Duration d = Duration.between( start , stop );
Generate text representing that Duration value. By default, standard ISO 8601 format is used.
System.out.println( d );
PT50M
Parts
You can extract the parts if desired.
int hours = d.toHoursPart() ;
int minutes = d.toMinutesPart() ;
Parsing
To parse your HHMM format provided by your users, use DateTimeFormatter.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "HHmm" ) ;
LocalTime lt = LocalTime.parse( "0150" , f ) ;
Zones
Be aware that working only with time-of-day without the context of date and time zone can lead to incorrect results. If working in UTC, no problem. But if your time-of-day values are actually intended to represent the wall-clock time of a particular region, then anomalies such as Daylight Saving Time (DST) will be ignored by use of LocalTime only. In your example, there may be no two o'clock hour, or two o'clock have have been repeated, if occurring on a DST cut-over date in the United States.
If you implicitly intended a time zone, make that explicit by applying a ZoneId to get a ZonedDateTime object.
LocalDate ld = LocalDate.of( 2018 , 1 , 23 ) ;
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
…
Duration d = Duration.between( zdt , laterZdt ) ;
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, Java SE 11, and later - 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
Most 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.

So to figure out elapsed time between two 24 hour times you need to transfer to total minutes now the modulo functions you are using will not work as 1 hour = 60 min not 100 min.
So first to transfer all hours/minuets to minute time.
int ftminuets = 0;
int stminuets = 0;
int totalmin = 0;
int elapsed = = 0
while(fTime >= 100)
{
ftminuets += 60;
fTime -= 100;
}
ftminuets += fTime; //gets remaining minuets from fTime.
while(sTime >= 100)
{
stminuets += 60;
sTime -= 100;
}
stminuets += sTime; //gets remaining minuets from sTime.
//time to subtract
totalmin = stminuets - ftminuets;
//now total min has the total minuets in what can be considered to be 60 min increments. Now just to switch it back into a 24 hours time.
while(totalmin >= 60)
{
elapsed += 100;
totalmin -= 60;
}
elapsed += totalmin; //get rest of the minuets.
elapsed should now have the elapsed time in 24 hours time.

I've answered my own question, the solution was that I seperated the hours from the minutes part (e.g. 1159 to 11 and 59), multiplied the hours to get the minutes and added that to the rest of the minutes.
this.fTimeInMin = ((fTime / 100) * 60) + (fTime % 100);
this.sTimeInMin = ((sTime / 100) * 60) + (sTime % 100);
And then, in the getHours() and the getMinutes() method transformed the minutes to hours and minutes:
public int getHours() {
return Math.abs((this.fTimeInMin - this.sTimeInMin) / 60);
}
public int getMinutes() {
return Math.abs((this.fTimeInMin - this.sTimeInMin) % 60);
}

Well, this is the solution you are looking. Splitting the mil.time so you can get the hours and minutes separately, then the rest is just somputations. Only thing you would accept the two params as Strings.
public class TimeInterval {
private String fTime;
private String sTime;
private static int timeDiffMinutes;
public static void main(String[] args) {
String fTime = "0330";
String sTime = "1330";
TimeInterval t = new TimeInterval(fTime, sTime);
System.out.println("timeDiff " + getTimeDiffMinutes());
System.out.println(t.getHours() + "...." + t.getMinutes());
System.out.println(t.getDecimalTime());
}
public TimeInterval(String fTime, String sTime) {
int fTimeInt = Integer.valueOf(fTime);
int sTimeInt = Integer.valueOf(sTime);
if (fTimeInt < 0 || fTimeInt > 2400 || sTimeInt < 0 || sTimeInt > 2400) {
System.out.println("Illegal times, must be < 2400 and > 0)");
System.exit(0);
} else {
this.fTime = fTime;
this.sTime = sTime;
getTimeDiff();
}
}
public static int getTimeDiffMinutes() {
return timeDiffMinutes;
}
public int getHours() {
return Math.abs(timeDiffMinutes / 60);
}
public int getMinutes() {
return Math.abs(timeDiffMinutes);
}
public double getDecimalTime() {
return getHours() + ((double) getMinutes() / 60);
}
public void getTimeDiff() {
final int mid1 = fTime.length() / 2; //get the middle of the String
String[] parts = {fTime.substring(0, mid1), fTime.substring(mid1)};
String fPart = parts[0];
final int mid = sTime.length() / 2; //get the middle of the String
String[] sParts = {sTime.substring(0, mid), sTime.substring(mid)};
String sPart = sParts[0];
int toBeExcluded = (Integer.valueOf(sPart) - Integer.valueOf(fPart)) * 40;
this.timeDiffMinutes = (Integer.valueOf(sTime) - Integer.valueOf(fTime)) - toBeExcluded;
}
}

how do you check for wrong invalid entry? is that not necessary? if do, your method eventhough currently only need about less thann 30 operations will grow to much2 more operations, that is not to include the 0000 hours or 2400 hours issues.

Related

Java Parking fee calculations

It seems like, I couldn't find the answer for my problem, so here I am, first on Stackoverflow :)
The If statement tree that will be mentioned:
buttonSzamol.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Változók
int StartHour = 18;
int StartMin = 50;
int StopHour = 20;
int StopMin = 49;
int DayTimeIntervalStart = 6;
int DayTimeIntervalStop = 17;
int NightTimeIntervalLateStart = 18;
int NightTimeIntervalLateStop = 23;
int NightTimeIntervalEarlyStart = 0;
int NightTimeIntervalEarlyStop = 5;
int DayHoursTotal = 0;
int NightHoursTotal = 0;
int DayTimePricePerHour = Integer.parseInt(NappaliOraDij.getText());
int NightTimePricePerHour = Integer.parseInt(EjszakaiOraDij.getText());
int StartDay = Integer.parseInt((DatumStart.getText()).replace(".", ""));
int StopDay = Integer.parseInt((DatumStart.getText()).replace(".", ""));
//1 started hour
if( (StartDay == StopDay) && ( ( (StartHour == StopHour) && (StartMin < StopMin) ) || ( ((StartHour + 1) == StopHour) && (StartMin >= StopMin) ) ) ) {
if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
DayHoursTotal++;
}
if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
NightHoursTotal++;
}
} else/*More hours*/if( (StartDay == StopDay) && ( ( (StartHour < StopHour) && (StartMin <= StopMin) ) || ( (StartHour < StopHour) && (StartMin > StopMin) ) ) ) {
if( (StartHour < StopHour) && (StartMin < StopMin) ) {
if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
DayHoursTotal = DayHoursTotal + (StopHour - StartHour);
DayHoursTotal++;
}
if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
NightHoursTotal = NightHoursTotal + (StopHour - StartHour);
NightHoursTotal++;
}
}else if(( (StartHour < StopHour) && (StartMin >= StopMin) )) {
if((DayTimeIntervalStart <= StartHour) && (StopHour <= DayTimeIntervalStop)) {
DayHoursTotal = DayHoursTotal + (StopHour - StartHour);
if(StartMin != StopMin) {
DayHoursTotal--;
}
}
if((NightTimeIntervalLateStart <= StartHour) && (StopHour <= NightTimeIntervalLateStop)) {
NightHoursTotal = NightHoursTotal + (StopHour - StartHour);
if(StartMin != StopMin) {
NightHoursTotal--;
}
}
}
}
NappaliOrak.setText(Integer.toString(DayHoursTotal));
EjszakaiOrak.setText(Integer.toString(NightHoursTotal));
OrakOsszesen.setText(Integer.toString(DayHoursTotal + NightHoursTotal));
NappaliOsszeg.setText(Integer.toString(DayHoursTotal * DayTimePricePerHour));
EjszakaiOsszeg.setText(Integer.toString(NightHoursTotal * NightTimePricePerHour));
VegOsszeg.setText(Integer.toString((DayHoursTotal * DayTimePricePerHour) + (NightHoursTotal * NightTimePricePerHour)));
}
});
So, the problem in a nutshell is.
I've tried to create a parking fee calculator for my colleague at work.
The main idea is, that it needs to calculate how many Daytime and how many Nighttime hours the client started, and it needs to calculate the price of those hours. I've changed the StartHour/Min-StopHour/Min fields to straight integers to be more understanable. I don't know if there is a module for this, but I started doing this with a lot of If statements, where I just got tangled up. In the included pastebin, there is starting time 18:50 and stop time 20:49. If we input this data, the output should be 2 started day hours. Now if the minute is the same, it does not count as a started hour. But if we change the input to 20:51, then it started an another hour, so the DayHoursTotal should be equal to 3.
Thank you in advance, for any help. If you have more questions about my code or idea, just ask.
It seems that you are trying to calculate the started hours not just between 2 times, but also between different dates.
For this it is best to use the java.time package and more specifically the LocalDateTime class.
LocalDateTime.of(startYear, startMonth, startDay, startHour, startMinute)
LocalDateTimes in conjuction with the between() method from the Java 8 ChronoUnit class gets exactly what you need.
ChronoUnit.MINUTES.between(Temporal t1, Temporal t2)
PS: You don't need that many 'interval' variables.
Just the start hour of the day (dayTimeIntervalStart) and night (nightTimeIntervalLateStart) rate is enough.
The hours rates before and after can be derived from those two intervals.
Spoiler!! look away if you want to investigate further yourself! ;)
Here is a runnable code sample that shows the parking logic for >1 day:
(I have omitted the user input parsing/logic, because that depends on your implementation)
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class ParkingFee {
private static long hoursDifference(LocalDateTime ldt1, LocalDateTime ldt2) {
long minutesDiff = ChronoUnit.MINUTES.between(ldt1, ldt2);
long hoursDiff = Math.round(Math.ceil(minutesDiff/60.0));
return hoursDiff;
}
public static long hoursDifference(
int startDay, int startMonth, int startYear, int startHour, int startMinute,
int endDay, int endMonth, int endYear, int endHour, int endMinute) {
return hoursDifference(
LocalDateTime.of(startYear, startMonth, startDay, startHour, startMinute),
LocalDateTime.of(endYear, endMonth, endDay, endHour, endMinute));
}
public static int determineDayCycle(int dayTimeIntervalStart, int nightTimeIntervalLateStart) {
return nightTimeIntervalLateStart - dayTimeIntervalStart;
}
public static void main(String[] args) {
// Hourly rates
int dayTimePricePerHour = 5;
int nightTimePricePerHour = 10;
// Rate intervals
int dayTimeIntervalStart = 6;
int nightTimeIntervalLateStart = 18;
// Counted hours per rate
int dayHoursTotal = 0;
int nightHoursTotal = 0;
// Start date and time
int startYear = 2019;
int startMonth = 1;
int startDay = 1;
int startHour = 20;
int startMinute = 50;
// End date and time
int endYear = 2019;
int endMonth = 1;
int endDay = 3;
int endHour = 2;
int endMinute = 49;
// Calculate the hours difference
long hourDiff = hoursDifference(
startDay, startMonth, startYear, startHour, startMinute,
endDay, endMonth, endYear, endHour, endMinute);
System.out.println("Hour difference found: "+ hourDiff);
// Handle parking for full days
if (hourDiff > 24) {
int dayCycle = determineDayCycle(dayTimeIntervalStart, nightTimeIntervalLateStart);
long fullDays = hourDiff / 24;
nightHoursTotal += (24-dayCycle)*fullDays;
dayHoursTotal += dayCycle*fullDays;
hourDiff = hourDiff % 24;
}
// Handle the parking for less than full day
while (hourDiff > 0) {
if (startHour < dayTimeIntervalStart) { // Before the day interval -> night
nightHoursTotal++;
} else if(startHour < nightTimeIntervalLateStart) { // Before the night interval -> day
dayHoursTotal++;
} else { // After the day interval -> night
nightHoursTotal++;
}
startHour++;
if (startHour > 23) // At midnight reset the hour to 0
startHour = 0;
hourDiff--;
}
System.out.println("Day hours: "+ dayHoursTotal);
System.out.println("Night hours: "+ nightHoursTotal);
System.out.println("Total hours: "+ (dayHoursTotal + nightHoursTotal));
System.out.println("Day rate charged at "+ dayTimePricePerHour +": "+ (dayHoursTotal * dayTimePricePerHour));
System.out.println("Night rate charged at "+ nightTimePricePerHour +": "+ (nightHoursTotal * nightTimePricePerHour));
System.out.println("Total rate charged: "+ ((dayHoursTotal * dayTimePricePerHour) + (nightHoursTotal * nightTimePricePerHour)));
}
}
This outputs:
Hour difference found: 30
Day hours: 12
Night hours: 18
Total hours: 30
Day rate charged at 5: 60
Night rate charged at 10: 180
Total rate charged: 240
First, you need to parse the Integers differently. Your method is dangerous, e.g. loses information. Plus you need to make the code failsafe in case somebody tries to put in values that won't work. Refer to this question: How do I convert a String to an int in Java?
Apart from that, working with just minutes and hours is always difficult. I suggest using the absolute times in milliseconds which makes it far easier to do calculations. Refer to this question: Difference in hours of two Calendar objects
Time Zone
Your code and the other Answers fail to account for time zone anomalies. If you are tracking actual moments, when people actually parked, as opposed to theoretical 24-hour long days, then you must account for anomalies such as Daylight Saving Time (DST). Politicians around the world have shown a penchant for redefining the time zone(s) in their jurisdiction. So days can be any length, such as 25-hours long, 23-hours, 23.5 hours, 24.25, or others.
A time zone is a history of the past, present, and future changes to the offset-from-UTC used by the people of a particular region.
The LocalDateTime class is exactly the wrong class to use for this purpose. That class intentionally has no concept of time zone or offset-from-UTC. You can use it as a building block piece in your code, but it must be assigned a ZoneId to determine an actual moment via the ZonedDateTime class.
ZoneId
Specify your time zone.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument. If critical, confirm the zone with your user.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Assemble date, time, & zone to determine a moment
Assemble your date and time-of-day.
LocalDate startDate = LocalDate.of( 2019 , 1 , 23 ) ; // 23rd of January in 2019.
LocalTime startTime = LocalTime.of( 18 , 50 ) ; // 6:50 PM.
ZonedDateTime startMoment = ZonedDateTime.of( startDate , startTime , z ) ;
LocalDate stopDate = LocalDate.of( 2019 , 1 , 23 ) ; // 23rd of January in 2019.
LocalTime stopTime = LocalTime.of( 20 , 50 ) ; // Two hours later, exactly — maybe! Depends on any anomalies at that time in that zone.
ZonedDateTime stopMoment = ZonedDateTime.of( stopDate , stopTime , z ) ;
➥ Note that in this example, we may have a span of time of exactly 2 hours, but maybe not. It might be 3 hours or some other length of time, depending on anomalies scheduled for that date at that time in that zone.
Elapsed time
To calculate elapsed time it terms of days (24-hour chunks of time, unrelated to the calendar), hours, minutes, and seconds, use Duration. (For year-months-days, use Period.)
Duration d = Duration.between( startMoment , stopMoment ) ;
Interrogate for entire span-of-time in terms of whole hours.
long hours = d.toHours() ; // Entire duration as count of whole hours.
Half-Open
In the included pastebin, there is starting time 18:50 and stop time 20:49. If we input this data, the output should be 2 started day hours. Now if the minute is the same, it does not count as a started hour. But if we change the input to 20:51, then it started an another hour, so the DayHoursTotal should be equal to 3.
This approach is know as Half-Open, when the beginning is inclusive, while the ending is exclusive. This is commonly used in date-time handling. The Duration and Period classes apply this approach.
But be careful about matching the minute number alone. Your date-time objects might be holding seconds and/or a fractional second, which would throw off your algorithm. As a habit, truncate your date-time objects explicitly if there is any possibility of smaller granularity than you want. For example, ZonedDateTime.truncatedTo.
Rate changes
Obviously, rate changes complicate matters. The other Answers seem to have covered this, so I'll not repeat. But I can add a big tip: See the ThreeTen-Extra for its classes Interval and LocalDateRange that may be of help to you. They include handy comparison methods for overlaps, contains, abuts, and so on.
divide et impera
Cutting down the big logic in small blocks make it easier to achieve
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
class Scratch {
static int StartHour = 18;
static int StartMin = 50;
static int StopHour = 20;
static int StopMin = 48;
static int DayTimeIntervalStart = 6;
static int DayTimeIntervalStop = 17;
static int NightTimeIntervalLateStart = 18;
static int NightTimeIntervalLateStop = 23;
static int NightTimeIntervalEarlyStart = 0;
static int NightTimeIntervalEarlyStop = 5;
static int DayTimePricePerHour = 10;
static int NightTimePricePerHour = 5;
static LocalTime dayStart = LocalTime.of(DayTimeIntervalStart, 0);
static LocalTime dayStop = LocalTime.of(DayTimeIntervalStop, 0);
static LocalTime nightEarlyStart = LocalTime.of(NightTimeIntervalEarlyStart, 0);
static LocalTime nightEarlyStop = LocalTime.of(NightTimeIntervalEarlyStop, 0);
static LocalTime nightLateStart = LocalTime.of(NightTimeIntervalLateStart, 0);
static LocalTime nightLateStop = LocalTime.of(NightTimeIntervalLateStop, 0);
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2019, 1, 1, StartHour, StartMin);
LocalDateTime stop = LocalDateTime.of(2019, 1, 1, StopHour, StopMin);
for(int i = 0; i < 3; i++){
stop = stop.plusMinutes(1L);
System.out.println(process(start, stop));
System.out.println("******");
}
stop = stop.plusDays(1L);
System.out.println(process(start, stop));
System.out.println("******");
}
public static int process(LocalDateTime start, LocalDateTime stop){
System.out.println(String.format("checking between %s and %s", start, stop));
if(stop.toLocalDate().isAfter(start.toLocalDate())){
// start and stop not on the same date
// split the computation, first currentDay then the rest
LocalDateTime endOfDay = LocalDateTime.of(start.toLocalDate(), LocalTime.MAX);
int resultForCurrentDay = process(start, endOfDay);
// not for the rest
LocalDateTime startOfNextDay = LocalDateTime.of(start.toLocalDate().plusDays(1L), LocalTime.MIN);
int resultForRest = process(startOfNextDay, stop);
return resultForCurrentDay + resultForRest;
}else{
// start and stop on the same date
return processIntraDay(start, stop);
}
}
private static int processIntraDay(LocalDateTime start, LocalDateTime stop) {
int result = 0;
LocalTime startTime = start.toLocalTime();
LocalTime stopTime = stop.toLocalTime();
// step 1: check early morning
result += checkBoundaries(startTime, stopTime, nightEarlyStart, nightEarlyStop, NightTimePricePerHour);
// step 2: check day time
result += checkBoundaries(startTime, stopTime, dayStart, dayStop, DayTimePricePerHour);
// step 3: check late night
result += checkBoundaries(startTime, stopTime, nightLateStart, nightLateStop, NightTimePricePerHour);
return result;
}
private static int checkBoundaries(LocalTime startTime, LocalTime stopTime, LocalTime lowerBoundary, LocalTime upperBoundary, int priceRatePerHour) {
// check if the period [start;stop] is crossing the period [lowerBoundary;upperBoundary]
if(stopTime.isAfter(lowerBoundary) && startTime.isBefore(upperBoundary)){
// truncate start time to not be before lowerBoundary
LocalTime actualStart = (startTime.isBefore(lowerBoundary))?lowerBoundary:startTime;
// symetrically, truncate stop to not be after upperBounday
LocalTime actualStop = (stopTime.isAfter(upperBoundary))?upperBoundary:stopTime;
// now that we have the proper start and stop of the period, let's compute the price of it
return compute(actualStart, actualStop, priceRatePerHour);
}else{
return 0;
}
}
private static int compute(LocalTime startTime, LocalTime stopTime, int pricePerHour) {
Duration duration = Duration.between(startTime, stopTime);
int hours = (int) duration.toHours();
long minutes = duration.toMinutes();
if(minutes % 60 > 0L){
// hour started, increasing the number
hours++;
}
int result = hours * pricePerHour;
System.out.println(String.format("%d hours at %d price/h => %d", hours, pricePerHour, result));
return result;
}
}
Went directly for the calculation of the final price. Updating to store total number of day hours and night hours should be much of a challenge
Result of my exemple:
checking between 2019-01-01T18:50 and 2019-01-01T20:49
2 hours at 5 price/h => 10
10
******
checking between 2019-01-01T18:50 and 2019-01-01T20:50
2 hours at 5 price/h => 10
10
******
checking between 2019-01-01T18:50 and 2019-01-01T20:51
3 hours at 5 price/h => 15
15
******
checking between 2019-01-01T18:50 and 2019-01-02T20:51
checking between 2019-01-01T18:50 and 2019-01-01T23:59:59.999999999
5 hours at 5 price/h => 25
checking between 2019-01-02T00:00 and 2019-01-02T20:51
5 hours at 5 price/h => 25
11 hours at 10 price/h => 110
3 hours at 5 price/h => 15
175
******
Might need more tests to ensure it's good in all conditions but should be a usefull starting point for you

How should the moveForward(lostTime) give the correct output when the hour and minute variables go below zero?

I knew the method of delaying by minutes, for instance, from 22:50 to 2:10. I inserted 200 in the parameter of delay method, I am concerned that the method of moving the time forward is not working as I attempted by setting the time 1:20 and moving 100 minutes (1 hour and 40 minutes) forward to 23:40. As I tried to run the code, the output displayed 1:40 after moving the time forward. Which line was wrong in the method of moveForward(int lostMinute)?
class Time
{
private int hour; // between 0 - 23
private int minute; // between 0 - 59
public Time()
{
this(0, 0);
}
public Time(int hr, int min)
{
hour = (hr >= 0 && hr < 24) ? hr : 0;
minute = (min >= 0 && min < 60) ? min : 0;
}
public int getHour()
{
return hour;
}
public int getMinute()
{
return minute;
}
public void setHour(int hour)
{
this.hour = (hour >= 0 && hour < 24) ? hour : 0;
public void setMinute(int minute)
{
this.minute = (minute >= 0 && minute < 60) ? minute : 0;
}
public String toString()
{
return String.format("%02d:%02d", hour, minute);
}
public void delay(int newMinute)
{
minute = minute + newMinute;
if(minute >= 60)
{
// (minute / 60) is an integer division and truncates the remainder, which refers to (minute % 60)
hour = hour + (minute / 60);
minute = minute % 60;
if(hour >= 24)
{
hour = hour % 24;
}
}
}
public void moveForward(int lostMinute)
{
if(minute < lostMinute)
{
hour = hour - ((60 + minute) / 60);
minute = (minute + 60) % 60;
if(hour < 0)
{
hour = (24 + hour) % 24;
}
}
else
{
minute = minute - lostMinute;
}
}
}
I saw that delay() is working correctly while moveForward() is not. To make the time notation clearer for sorting, I used String.format("%02d:%02d") to indicate the time between 00:00 and 23:59. Please note that I am not using import java.util.Calender; or 'import java.util.Date; because part of my project consists of sorting an array by just hours and then minutes. For instance, if we are trying to create the bus terminal project, we assume that the date and calendar do not matter in schedule.
public class MainTime
{
public static void main(String[] args)
{
Time t1 = new Time(23:50);
Time t2 = new Time(1:20);
Time t3 = new Time(4:50);
Time t4 = new Time(18:30);
Time t5 = new Time(14:15);
t1.delay(200);
t2.moveForward(100);
t3.delay(100);
t4.moveForward(20);
t5.moveForward(160);
System.out.println(t1.toString());
System.out.println(t2.toString());
System.out.println(t3.toString());
System.out.println(t4.toString());
System.out.println(t5.toString());
}
}
The constraints are when the change in time is greater than the minute in parameter and when the hour is going to zero. When I ran the code in NetBeans, t1 had 2:10 when I added 200 into 23:50 in delay(newMinute) method; t2 had 1:40 when I subtracted 100 from 1:20 in moveForward(lostMinute) method; t3 had 6:30 when I added 100 into 4:50 in delay(newMinute); t4 had 18:10 when I subtracted 20 from 18:30 in moveForward(lostMinute); t5 had 14:-25 when I subtracted 160 from 14:15 in moveForward(lostMinute). The variables t2 and t5 after execution should actually be 23:40 and 11:35, respectively.
Please determine which lines in public void moveForward(int lostMinute) make the improper output after subtracting the minutes from given time.
In case the minute goes to zero, 60 and modulo notation % could be useful; in case the hour goes to zero, 24 and modulo notation % could be useful. I hope for the moveForward(lostMinute) to work well in the cases when minute < 0 and when hour < 0.
java.time
LocalTime t1 = LocalTime.of(23, 50);
t1 = t1.plusMinutes(200);
System.out.println(t1.toString()); // 03:10
LocalTime t2 = LocalTime.of(1, 20);
t2 = t2.minusMinutes(100);
System.out.println(t2.toString()); // 23:40
LocalTime t3 = LocalTime.of(4, 50);
t3 = t3.plusMinutes(100);
System.out.println(t3.toString()); // 06:30
LocalTime t4 = LocalTime.of(18, 30);
t4 = t4.minusMinutes(20);
System.out.println(t4.toString()); // 18:10
LocalTime t5 = LocalTime.of(14, 15);
t5 = t5.minusMinutes(160);
System.out.println(t5.toString()); // 11:35
Output is given as comments. I think it is what you wanted. So don’t reinvent the wheel. Instead of rolling your own Time class, use LocalTime. It’s there for you to use, it has been developed and tested for you. LocalTime is a time of day in the interval from 00:00 to 23:59:59.999999999. Except that it include seconds and fraction of second it coincides with your interval. If you never set the seconds to something other than 0, they won’t be printed through the toString method. Also LocalTime implements Comparable, so sorting is straightforward.
Be aware that a LocalTime object is immutable, so instead of mutator methods it has methods that return a new LocalTime object with the new value. This is already demonstrated with plusMinutes and minusMinutes above. Also instead of myLocalTime.setHour(17); you need myLocalTime = myLocalTime.withHour(17);, etc.
What went wrong in your code?
Your moveForward method seems to be handling the hour correctly in the case where it is to be moved back to the previous hour, for example from 14:05 to 13:55 or from 14:55 to 13:05. In this case you are never subtracting lostMinutes, which I think you should somehow. When minute is 0–59, then ((60 + minute) / 60) will always be 1, so you are always subtracting exactly 1 hour, never 2 or more.
Genrally the expected ranges of the arguments to both delay and moveForward are unclear. I think they should have been documented and the arguments validated against the documented limits.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Calculate age in java considering leap years

I would like to calculate exact age in days considering leap years. I researched on the web, found some tutorials, but with leap years that exactly calculates difference of dates in days seems to be the one in [1]: https://answers.yahoo.com/question/index?qid=20110629162003AAof4mT this link, which is "best answer" . I analyzed code but have two questions:
1) Why it writes "days = days + leapYears" below "Calculate days lives" section and
2) Finally, how can I input birthday date with day,month and year and current day,month,year and find difference of these two dates in days within this code in the main method? I really appreciate your help. Thanks in advance !
PS: For convenience, I have included the code from the link I showed above:
public class Days {
static int leapYear(int year) {
int leap;
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
leap = 1;
}
else {
leap = 0;
}
return leap;
}
static int daysBefore(int month, int day, int year){
int days = 0;
int monthDays[] = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (leapYear(year) == 1){
monthDays[1] = 29;
}
for (int b = 0; b < month - 1; b++){
days = days + monthDays[b];
}
days = days + day;
return days;
}
public static void main(String[] args) {
//Birth date
int birthMonth = 0;
int birthDay = 0;
int birthYear = 0;
//Due date
int dueMonth = 0;
int dueDay = 0;
int dueYear = 0;
//(1) Calculate years lived
int yearsLived = dueYear - birthYear + 1;
//(2) Calculate leap years
int leapYears = 0;
for (int year = birthYear; year < dueYear+1; year++)
{
leapYears = leapYears + leapYear(year);
}
//(3) Calculate the number of days in your birth year before birth
int daysBeforeBirth = daysBefore(birthMonth, birthDay, birthYear);
//(4) Calculate the number of days remaining in the current year after the due date
int daysRemaining = 365 - daysBefore(dueMonth, dueDay, dueYear);
//Calculate days lived
int days = 0;
days = days + (365 * yearsLived);
days = days + leapYears;
days = days - daysBeforeBirth;
days = days - daysRemaining;
}
}
The correct way to do this is with the Period and LocalDate classes in the java.time package. However, it seems that you're trying to reinvent the calculation for yourself.
The way that I would recommend doing this is to write a class that lets you calculate a "day number" for a given date - that is, the number of days between the specified date, and some arbitrary date in the past. Then when you want to find the number of days between two specified dates, you can just use calculate the "day number" for both dates, and subtract them.
I have done that here, for a purely Gregorian calendar. This class is no good before the Gregorian cutover - I haven't tried to build a historically accurate Julian/Gregorian hybrid calendar, such as the JDK provides. And the arbitrary date in the past that it calculates day numbers from is 31 December, 2BC. This date, of course, isn't really part of the Gregorian calendar; but for our purposes here, it doesn't matter.
Since you're unlikely to encounter any dates before the Gregorian cutover, this class should be more than adequate for your purposes. I still recommend using the Period and LocalDate classes instead of this one, for production code. This is just here so you can see how to do the calculations.
public class GregorianDate {
private final int day;
private final int month;
private final int year;
private static final int[] DAYS_PER_MONTH = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public GregorianDate(int day, int month, int year) {
this.day = day;
this.month = month;
this.year = year;
}
public boolean isValid() {
return month >= 1 && month <= 12 && day >= 1 && day <= daysThisMonth();
}
public static int daysBetween(GregorianDate from, GregorianDate to) {
return to.dayNumber() - from.dayNumber();
}
public static int daysBetween(int fromDay, int fromMonth, int fromYear, int toDay, int toMonth, int toYear) {
return daysBetween(new GregorianDate(fromDay, fromMonth, fromYear), new GregorianDate(toDay, toMonth, toYear));
}
private int daysThisMonth() {
return (isLeapYear() && month == 2) ? 29 : DAYS_PER_MONTH[month];
}
private int dayNumber() {
return year * 365 + leapYearsBefore() + daysInMonthsBefore() + day;
}
private boolean isLeapYear() {
return ( year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0;
}
private int leapYearsBefore() {
return year / 4 - year / 100 + year / 400;
}
private int daysInMonthsBefore() {
switch(month) {
case 1:
return 0;
case 2:
return 31;
default:
// Start with the number in January and February combined
int toReturn = isLeapYear() ? 60 : 59;
for (int monthToConsider = 3; monthToConsider < month; monthToConsider++) {
toReturn += DAYS_PER_MONTH[monthToConsider];
}
return toReturn;
}
}
}
To answer question 1.
every leapyear you add 1 day to the year. The writer uses this knowledge by first calculating how many days have been lived if all years were normal:
days = days + (365 * yearsLived);
and then adds the number of leapyears(remember 1 leapyear = 1 extra day).
For the second question:
the code seeks the difference between birthDate(read: startDate) and dueDate(read endDate). So to calculate the difference between start and end you have to give these integers the the date input and the code will do the rest.
tl;dr
long ageInDays =
ChronoUnit.DAYS.between(
LocalDate.of( 1960 , 1 , 2 ) ,
LocalDate.now( ZoneId.of( "America/Montreal" ) )
);
Using java.time
If you are exploring the algorithm, see the apparently correct Answer by David Wallace.
If you are doing this for productive work, then do not roll your own date-time classes. Avoid the old date-time classes (.Date, .Calendar, etc.) and use the java.time classes.
The ChronoUnit enum has a surprising amount of utility including calculating elapsed time. Pass a couple of Temporal objects, in our case LocalDate objects.
LocalDate start = LocalDate.of( 1960 , 1 , 2 ) ;
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
long ageInDays = ChronoUnit.DAYS.between( start , today ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
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.

Getting wrong time after calculating difference between two Dates

I want to calculate the difference between a certain date and the current time.
int month = 9;
int day = 17;
int year = 2013;
Calendar date = new GregorianCalendar(year, month, day);
int miliseconds= (int) (System.currentTimeMillis() - calendar.getTimeInMillis());
System.out.println(msToString(second));
String msToString(int ms) {
return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")).format(new Date(ms));
}
the output is
13091-13091/? D/GTA: 1970-01-08 15:00:20.287
I want to get the amount of days, hours,minutes and seconds remaining.
What do I wrong?
you could try something like the following method
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TimeToGoCalculator {
/**
* #param args
*/
public static void main(String[] args) {
int month = 8;
int day = 19;
int year = 2013;
Calendar calendar = new GregorianCalendar(year, month, day);
int timeToGo = (int) (calendar.getTimeInMillis() - System.currentTimeMillis())/1000;
System.out.println(secondsToString(timeToGo));
}
private static String secondsToString(int seconds) {
int days = seconds / 24 / 3600;
int hours = (seconds - (days * 24 * 3600 )) / 3600;
int minutes = (seconds - (days * 24 * 3600 + hours * 3600)) / 60;
seconds = (seconds - (days * 24 * 3600 + hours * 3600 + minutes * 60));
return "The remaining time is "+days+" days, "+hours+" hours, "+minutes+
" minutes, and "+seconds+" seconds.";
}
}
That should give you the output you're looking for.
Notice that, when creating the GregorianCalendar object, the month is 0-indexed, so September would be = 8.
Use Joda Time library
Period class can help.
int month = 9;
int day = 17;
int year = 2013;
int hour= 0;
int minute =0;
int second =0;
int millisecond = 0;
DateTime dt1 = new DateTime(); //now
DateTime dt2 = new DateTime(year, month, day, hour, minute, second, millisecond);
//assuming dt1 is before dt2:
Period period = new Period(dt1, dt2, PeriodType.dayTime());
/*
periodType.dayTime()):
Gets a type that defines all standard fields from days downwards.
days
hours
minutes
seconds
milliseconds
*/
PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
.printZeroAlways()
.minimumPrintedDigits(2)
.appendDays().appendSuffix("days ")
.appendHours().appendSuffix("hours ")
.appendMinutes().appendSuffix("minutes ")
.appendSeconds().appendSuffix("seconds ");
.toFormatter();
System.out.println(periodFormatter.print(period));
Are you able to use external libraries? Then Joda Time can help you, especially the Period class.
It has a constructor for two time instants and gives you the difference between the time instants in years/months/days/hours/seconds/milliseconds.
Your second variable holds an amount of milliseconds between the two dates, not a new date. You need to do some calculation using these milliseconds to get an amount of days, for instance.
You could do something like this:
int minutes = second/1000/60; // millis to seconds, seconds to minutes
to get an amount of minutes, then convert to hours, and so on.

java calculate pregnancy algorithm [duplicate]

This question already has answers here:
Calculating the difference between two Java date instances
(45 answers)
Closed 9 years ago.
hello I am trying to calculate how many days are left in a pregnancy term but I think my algorithm is incorrect
public int getDaysPregnantRemainder_new() {
GregorianCalendar calendar = new GregorianCalendar();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
long diffDays = 280 - ((getDueDate().getTime() - calendar.getTime()
.getTime()) / (24 * 60 * 60 * 1000));
return (int) Math.abs((diffDays) % 7);
}
I am basing it off of a 280 day term, getDueDate() is a Date object and getTime() returns millisecond unix time
On some real world days the number reported is off by one, sometimes, and I am starting to think my algorithm is just wrong, or the millisecond time get gradually further and further off, or the millisecond time is not precise enough, or the gregorian calendar function rounds weird.
All in all I'm not sure, any insight appreciated
I don't know about your algorithm, but this (is basically) the one I used while tracking my wife's pregency...nerds...
Save yourself a lot of "guess" work and get hold of Joda-Time
public class TestDueDate {
public static final int WEEKS_IN_PREGNANCY = 40;
public static final int DAYS_IN_PREGNANCY = WEEKS_IN_PREGNANCY * 7;
public static void main(String[] args) {
DateTime dueDate = new DateTime();
dueDate = dueDate.plusDays(DAYS_IN_PREGNANCY);
System.out.println("dueDate = " + dueDate);
DateTime today = DateTime.now();
Days d = Days.daysBetween(today, dueDate);
int daysRemaining = d.getDays();
int daysIn = DAYS_IN_PREGNANCY - daysRemaining;
int weekValue = daysIn / 7;
int weekPart = daysIn % 7;
String week = weekValue + "." + weekPart;
System.out.println("Days remaining = " + daysRemaining);
System.out.println("Days In = " + daysIn);
System.out.println("Week = " + week);
}
}
This will output...
dueDate = 2014-02-25T14:14:31.159+11:00
Days remaining = 279
Days In = 1
Week = 0.1

Categories