0
votes

Before I had asked a question about subtracting time and I thought I had it. However as I was debugging, several bugs appeared. Basically what I am asking is to create a punch clock, but I can't use the Java Calendar API.

Users will input start times and the time they punched out and it will calculate the difference between the times.

Mine is not working very well and I don't know why. For example, If 4:00am is the start and 12:00am is the end, 8 hrs 00 min is returned. That is incorrect. I thought I created an if statement for the possibilities.

Here is my code:

     public static void elapsedTime()
    {
        Scanner reader = new Scanner (System.in);

        System.out.print("Enter the beginning hour: ");
        int startingHour = reader.nextInt();

        System.out.print("Enter the beginning minute(s): ");
        int startingMin = reader.nextInt();


        System.out.print("Enter AM/PM: ");
        reader.nextLine();
        String startingTOD = reader.nextLine();


        System.out.print("Enter the ending hour: ");
        int endingHour = reader.nextInt();

        System.out.print("Enter the ending minute(s): ");
        int endingMin = reader.nextInt();

        System.out.print("Enter AM/PM:  ");
        reader.nextLine();
        String endingTOD = reader.nextLine();

        System.out.println();

        int hours;
        int minutes = endingMin - startingMin;
        String Am = "am" ;
        String Pm = "pm" ;

       if (endingTOD.equalsIgnoreCase(startingTOD) &&  minutes <  0  )
       {
           hours = (endingHour - startingHour) -1 ;
           minutes = minutes + 60 ;
           System.out.println(hours +  " "  + minutes);

        }
     else  if (endingHour > startingHour&& endingTOD.equalsIgnoreCase(startingTOD) &  minutes > 0  )
       {
           hours = endingHour - startingHour;
           System.out.println(hours + " " + minutes);
        }
      else  if (endingHour > startingHour && endingTOD.equalsIgnoreCase(startingTOD) && minutes == 0  )
     {
         hours = (endingHour-startingHour);
         minutes = 0;
         System.out.println(hours + " " + minutes);
     }
   else  if (endingHour < startingHour && endingTOD.equalsIgnoreCase(startingTOD) && minutes == 0  )
     {
         hours = (endingHour-startingHour) + 12;
         minutes = 0;
         System.out.println(hours + " " + minutes);
     }
   else if ( endingHour==startingHour && minutes == 0)
   {
        hours = 12;
        minutes = 0;
        System.out.println(hours + " " + minutes);
    }
    else if (( endingTOD.equalsIgnoreCase(Pm) && startingTOD.equalsIgnoreCase(Am)) && minutes > 0)
    {
        hours = (endingHour - startingHour) + 12;
        System.out.println(hours + " " + minutes);
    }

 else if  (( endingTOD.equalsIgnoreCase(Pm) && startingTOD.equalsIgnoreCase(Am)) && minutes < 0)
       {
           hours = (endingHour - startingHour) -1 ;
           minutes = minutes + 60 ;
           System.out.println(hours +  " "  + minutes);

        }
 else if (endingHour > startingHour && ( endingTOD.equalsIgnoreCase(Pm) && startingTOD.equalsIgnoreCase(Am)) && minutes == 0)
    {
        hours = (endingHour-startingHour) + 12;
        minutes = 0;
       System.out.println(hours +  " "  + minutes);
    }
    else if (endingHour < startingHour &&( endingTOD.equalsIgnoreCase(Pm) && startingTOD.equalsIgnoreCase(Am)) && minutes == 0)
    {
        hours = (endingHour - startingHour) +24;
        minutes = 0;
       System.out.println(hours +  " "  + minutes);
    }
   else if (endingHour < startingHour &&( endingTOD.equalsIgnoreCase(Pm) && startingTOD.equalsIgnoreCase(Am)) && minutes > 0)
    {
        hours = (endingHour - startingHour) + 2;
        System.out.println(hours + " " + minutes);
    }
        }
2
Define not working very well; what is the problem(s) you're having?Paul Richter
Huh? From 8 14 am to 2 47 pm it's 6 hours and 33 minutes... Your program is working correctly.m0skit0
Is the assumption here that you can't use the Java Calendar API?user1531971
@DaBom, time to bust out your fingers and countredFIVE
for time difference calculations I would suggest using the new Time-API of java 8 since all previous implementations had serious bugsmschenk74

2 Answers

1
votes

Given that you cannot use the Java Calendar API, your approach, while not very modular, looks sound at first glance. The devil is in the details.

The trick with date-time calculations are all the corner-cases. This is why no one wants to write and maintain such things, and even Sun/Oracle got it wrong again and again.

Proving your code works for all conditions is going to be hard. You are better off reducing scope and lowering requirements. 12 or 24 hour clocks? If 24-hour, do we start at 0h or 1h? Are we spanning days? Will we be expected to cross midnight? etc.

But your tasks is to do compare hours in a modulo 12 or 24 manner (unless your requirements say you don't have to "roll-over" or cross 12 or 24 hour boundaries.) And the real trick is to think of hours as a series of fence posts and rails, and count the rails. one-off errors are going to be the bane of your existence here.

My advice is to use the Java Calendar API at least to double check your results.

0
votes

Instead of trying to reinvent the wheel and implement date subtraction logic yourself and then try to cover all the corner cases, you can leverage built in Java Date Arithmetic.

Something like this (copy this code into TimeDifference.java and run):

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Scanner;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

public class TimeDifference {

    public static void elapsedTime() {
        Scanner reader = new Scanner(System.in);

        System.out.print("Enter the beginning hour: ");
        int startingHour = reader.nextInt();

        System.out.print("Enter the beginning minute(s): ");
        int startingMin = reader.nextInt();

        System.out.print("Enter AM/PM: ");
        reader.nextLine();
        String startingTOD = reader.nextLine();



        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
        // if no ids were returned, something is wrong. get out.
        if (ids.length == 0)
            System.exit(0);

        // create a Pacific Standard Time time zone
        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);

        // set up rules for daylight savings time
        pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
        pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY,
                2 * 60 * 60 * 1000);

        // create a GregorianCalendar with the Pacific Daylight time zone
        // and the current date and time
        Calendar startingCalendar = new GregorianCalendar(pdt);
        Calendar endingCalendar = new GregorianCalendar(pdt);
        Date trialTime = new Date();
        startingCalendar.setTime(trialTime);
        endingCalendar.setTime(trialTime);

        startingCalendar.set(java.util.Calendar.HOUR, startingHour);
        startingCalendar.set(java.util.Calendar.MINUTE, startingMin);

        if (startingTOD.equalsIgnoreCase("AM")) {
            startingCalendar.set(java.util.Calendar.AM_PM, 0);
        } else if (startingTOD.equalsIgnoreCase("PM")) {
            startingCalendar.set(java.util.Calendar.AM_PM, 1);
        } else {
            System.out.println("invalid starting AM/PM. exiting..");
            System.exit(-1);
        }

        System.out.print("Enter the ending hour: ");
        int endingHour = reader.nextInt();

        System.out.print("Enter the ending minute(s): ");
        int endingMin = reader.nextInt();

        System.out.print("Enter AM/PM:  ");
        reader.nextLine();
        String endingTOD = reader.nextLine();

        System.out.println();

        // get the supported ids for GMT-08:00 (Pacific Standard Time)

        endingCalendar.set(java.util.Calendar.HOUR, endingHour);
        endingCalendar.set(java.util.Calendar.MINUTE, endingMin);

        if (endingTOD.equalsIgnoreCase("AM")) {
            endingCalendar.set(java.util.Calendar.AM_PM, 0);
        } else if (endingTOD.equalsIgnoreCase("PM")) {
            endingCalendar.set(java.util.Calendar.AM_PM, 1);
        } else {
            System.out.println("invalid ending AM/PM. exiting..");
            /* Exit program */
            System.exit(-1);
        }

        long startingTimeMillis = startingCalendar.getTimeInMillis();
        long endingTimeMillis = endingCalendar.getTimeInMillis();
        long timeDifferenceMillis = endingTimeMillis - startingTimeMillis;

        System.out.println(String.format("Time difference between starting and ending time (in minutes and hours): %d hours, %d minutes", 
                TimeUnit.MILLISECONDS.toHours(timeDifferenceMillis),
                TimeUnit.MILLISECONDS.toMinutes(timeDifferenceMillis) - 
                TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeDifferenceMillis))
            ));

        reader.close();
    }

    public static void main(String[] args) {
        elapsedTime();
    }

}