Java Parking fee calculations - java

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

Related

Military Time Difference in 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.

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.

Java How to get Month from milliseconds WITHOUT using external Libraries

I am using System.currentTimeMillis() to get number of milliseconds since 1970, I am able to get current Hour, Minute, seconds and year. For example I am getting Year using following formula and it returns 2015:
((((currTimeInMilliSec / 1000) / 3600) / 24) / 365) + 1970
But how can I calculate Month from milliseconds keeping in considering Leap Year and different number of days in different months like 28,29,30,31.
Note: For some reason, I need to use only currentTimeMillis function to calculate and I don't want to use other functions or external libraries. Also I have gone through related posts but didn't find exact answer.
Use GregorianCalendar.
GregorianCalendar c = new GregorianCalendar();
c.setTimeInMillis(1l);
int month = c.get(Calendar.MONTH);
This returns 0, that is January. Imagine an array with the 12 months of the year.
Yes, this is possible.
There are astronomical algorithms that enable the numerical translation between a Julian Day Number and a date-time stamp. The algorithm with which I am familiar was published by J. Meeus in his Astronomical Algorithms, 2nd Ed. This algorithm will convert a Julian Day Number to a vector of integers representing the corresponding:
YEAR
MONTH_IN_YEAR (1-12)
DAY_IN_MONTH (1-28,29,30,31 as appropriate)
HOUR_IN_DAY (0-23)
MINUTE_IN_HOUR (0-59)
SECOND_IN_MINUTE (0-59)
MILLISECOND_IN_SECOND (0-999)
Because both POSIX time and Julian Day Numbers are date serials (counts of consecutive time units) they are trivial to interconvert. Thus, the 1st step for using this algorithm would be to convert POSIX time (millis since midnight Jan 1, 1970) to a Julian Day Number (count of days since November 24, 4714 BC, in the proleptic Gregorian calendar). This is trivial to do since you simply convert from millis to days and adjust the epoch.
Here are the constants:
/** Accessor index for year field from a date/time vector of ints. */
public static final int YEAR = 0;
/** Accessor index for month-in-year field from a date/time vector of ints */
public static final int MONTH = 1;
/** Accessor index for day-in-month field from a date/time vector of ints */
public static final int DAY = 2;
/** Accessor index for hour-in-day field from a date/time vector of ints */
public static final int HOURS = 3;
/** Accessor index for minute-in-hour field from a date/time vector of ints */
public static final int MINUTES = 4;
/** Accessor index for second-in-minute field from a date/time vector of ints */
public static final int SECONDS = 5;
/** Accessor index for millis-in-second field from a date/time vector of ints */
public static final int MILLIS = 6;
/** The POSIX Epoch represented as a modified Julian Day number */
public static final double POSIX_EPOCH_AS_MJD = 40587.0d;
And here is the method for the algorithm that converts a Julian Day Number (supplied as a double) to a vector of integers. In the code below, you can substitute the trunc() function with Math.floor() and retain the correct behavior:
public static int[] toVectorFromDayNumber(double julianDay) {
int[] ymd_hmsm = {YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLIS};
int a, b, c, d, e, z;
double f, x;
double jd = julianDay + 0.5;
z = (int) trunc(jd);
f = (jd - z) + (0.5 / (86400.0 * 1000.0));
if (z >= 2299161) {
int alpha = (int) trunc((z - 1867216.25) / 36524.25);
a = z + 1 + alpha - (alpha / 4);
} else {
a = z;
}
b = a + 1524;
c = (int) trunc((b - 122.1) / 365.25);
d = (int) trunc(365.25 * c);
e = (int) trunc((b - d) / 30.6001);
ymd_hmsm[DAY] = b - d - (int) trunc(30.6001 * e);
ymd_hmsm[MONTH] = (e < 14)
? (e - 1)
: (e - 13);
ymd_hmsm[YEAR] = (ymd_hmsm[MONTH] > 2)
? (c - 4716)
: (c - 4715);
for (int i = HOURS; i <= MILLIS; i++) {
switch (i) {
case HOURS:
f = f * 24.0;
break;
case MINUTES: case SECONDS:
f = f * 60.0;
break;
case MILLIS:
f = f * 1000.0;
break;
}
x = trunc(f);
ymd_hmsm[i] = (int) x;
f = f - x;
}
return ymd_hmsm;
}
For example, if the function is called with the Julian Day Number 2457272.5, it would return the following vector of integers representing midnight, Sept 7, 2015 (Labor Day) in UTC:
[ 2015, 9, 7, 0, 0, 0, 0 ]
Edit: A remarkable thing about the Meeus algorithm is that it correctly accounts for both Leap Years and century days (including the century day exception). It uses only integer and floating point arithmetic and is very likely to be more performant than solutions which require object instantiations from the Java Calendar or Date-Time APIs.
My variant:
public class Main {
public static class MyDate {
int month;
int day;
public MyDate(int month, int day) {
this.month = month;
this.day = day;
}
}
public static final int[] daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public static void main(String[] args) {
long millis = System.currentTimeMillis();
long days = millis / 86400000;
long millisToday = millis % 86400000;
int yearsPassedApprox = (int) days / 365;
int daysPassedThisYear = (int) (days - (yearsPassedApprox * 365 + leapYearsCount(yearsPassedApprox)));
int year = yearsPassedApprox + 1970;
MyDate myDate = getMonthAndDay(year, daysPassedThisYear);
int hours = (int) (millisToday / 3600000);
int minutes = (int) ((millisToday % 3600000) / 60000);
int seconds = (int) ((millisToday % 60000) / 1000);
System.out.println("Year: " + year);
System.out.println("Month: " + myDate.month);
System.out.println("Day: " + myDate.day);
System.out.println("Hour: " + hours);
System.out.println("Minutes: " + minutes);
System.out.println("Seconds: " + seconds);
}
public static MyDate getMonthAndDay(int year, int daysPassedThisYear) {
int i;
int daysLeft = daysPassedThisYear;
boolean leapYear = isLeapYear(year);
for (i = 0; i < daysInMonth.length; i++) {
int days = daysInMonth[i];
if (leapYear && i == 1) {
days++;
}
if (days <= daysLeft) {
daysLeft -= days;
} else {
break;
}
}
return new MyDate(i + 1, daysLeft + 1);
}
public static int leapYearsCount(long yearsPassed) {
int count = 0;
for (int i = 1970; i < 1970 + yearsPassed ; i++) {
if (isLeapYear(i)) {
count++;
}
}
return count;
}
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && !(year % 100 == 0)) || year % 400 == 0;
}
}

Convert int to time Java

I have an int counter that starts at 600 and in a Runnable and is increased by 1.
600 represents 6 am, and 2400 represents midnight.
This int is compared to a int received from an API in the same format.
I need to compare them both; however, the problem is my int has 100 mins in an hour at the moment, so as time goes on it gets more and more out of time.
Is there a way to convert the int counter to a time format? (The Java format of 18000000 = 6am doesn't work)
Cheers Phil
Dave Newton is right by saying its just math. Your integer time is composed by two components, hours and minutes (which is easy to read but difficult to calculate).
int time = 600;
int hours = time / 100;
int minutes = (time - hours * 100) % 60;
So you can't just increment your time (time++), because you end up with a houndred minutes per hour as you wrote. Use this method instead:
int incrementTime(int time) {
time++;
int hours = time / 100;
int minutes = (time - hours * 100) % 60;
if (minutes == 0) hours++;
return hours * 100 + minutes;
}
You can try it out:
time = 600;
for (int i=0; i < 120; i++) {
time = incrementTime(time);
System.out.println(time);
}
If you do really need to transform your 0 --> 2400 to a "time format", you might use:
hour = uTime/100
uMinutes = uTime - hour*100
normalMinutes = (60*uMinutes)/100
Then go about changing to "long" and milliseconds for use elsewhere.
Java already has a way to convert a datetime to a number and vice versa.
//Get integer representation of time
Calendar rightNow = Calendar.getInstance();
long integerRepresentation = rightNow.getTimeInMillis();
//Set time to integer reprsentation
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(integerRepresentation);

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.

Categories