Skip to content

Instantly share code, notes, and snippets.

@ameron32
Last active December 18, 2015 16:09
Show Gist options
  • Save ameron32/5809822 to your computer and use it in GitHub Desktop.
Save ameron32/5809822 to your computer and use it in GitHub Desktop.
For [doggxyo]. His spreadsheet converted into a console-based java program.
package com.YOURPACKAGE.CHANGEMEBEFOREUSINGME;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;
public class Test {
// these are the placeholders reserved for storing date information to use repeatedly
static Date start, end;
static Date startOfDay, endOfDay;
static List<Date> holidays = new ArrayList<Date>();
// this is the conversion formula reserved for use throughout the program
static int mSecInOneHour = (1000 * 60 * 60); // to convert milliseconds to hours
static long mSecInOneDay = mSecInOneHour * 24; // to convert milliseconds to days
// re-calculates during interaction
static int hoursPerBusinessDay;
// this is the text input for the console
static Scanner scan;
// more detailed logging in the console if isLogging is set to true
static boolean isLogging = false;
// formats to be used throughout the program
// references to display to the user (change these to change what the user
// sees)
static String timeFormatRef = "24Hour:Minute";
static String dateFormatRef = "Month/day/year";
static String dateAndTimeFormatRef = dateFormatRef + " " + timeFormatRef;
// format to give to conversion tools in java (change these to change what
// to give the java utilities, only if you know what you are trying to do
// and how to do it)
static String timeFormatCalc = "h:mm";
static String dateFormatCalc = "M/d/yyyy";
static String dateMiniFormatCalc = "M/d";
static String dateAndTimeFormatCalc = dateFormatCalc + " " + timeFormatCalc;
/**
* Where it all begins...
*
* @param Not needed.
*/
public static void main(String[] args) {
prepare();
displayInstructions();
showData();
askForCommand();
}
/**
* Performs all initialization activities, including setting defaults
*/
private static void prepare() {
scan = new Scanner(System.in);
// set default start and stop times here
start = convertStringToDate("07/02/2013 09:00");
end = convertStringToDate("07/05/2013 17:00");
// set default business day here
startOfDay = convertStringToDate("09:00");
endOfDay = convertStringToDate("17:00");
hoursPerBusinessDay = 8;
// load default holidays 2013 into a list of holidays to review later
holidays.add(convertStringToDate("1/1/2013")); // New Years
holidays.add(convertStringToDate("1/21/2013")); // MLK day
holidays.add(convertStringToDate("2/18/2013")); // Washington's Birthday
holidays.add(convertStringToDate("5/27/2013")); // Memorial day
holidays.add(convertStringToDate("7/4/2013")); // Independence day
holidays.add(convertStringToDate("9/2/2013")); // Labor day
holidays.add(convertStringToDate("10/14/2013")); // Columbus day
holidays.add(convertStringToDate("11/11/2013")); // Veterans day
holidays.add(convertStringToDate("11/28/2013")); // Thanksgiving
holidays.add(convertStringToDate("12/25/2013")); // Christmas
// load default holidays 2014
holidays.add(convertStringToDate("1/1/2014")); // New Years
holidays.add(convertStringToDate("1/21/2014")); // MLK day
holidays.add(convertStringToDate("2/18/2014")); // Washington's Birthday
holidays.add(convertStringToDate("5/27/2014")); // Memorial day
holidays.add(convertStringToDate("7/4/2014")); // Independence day
holidays.add(convertStringToDate("9/2/2014")); // Labor day
holidays.add(convertStringToDate("10/14/2014")); // Columbus day
holidays.add(convertStringToDate("11/11/2014")); // Veterans day
holidays.add(convertStringToDate("11/28/2014")); // Thanksgiving
holidays.add(convertStringToDate("12/25/2014")); // Christmas
}
/**
* Displays the list of commands to the user.
*/
private static void displayInstructions() {
// displays the instructions to the user
display("Put your opening comments here.");
display("Commands: hours, start, end, holidaylist, show, go, help, quit");
display("---hours: set the business hours each day");
display("---start: set the start date and time");
display("---end: set the end date and time");
display("---holidaylist: set the yearly holidays [not yet implemented]");
display("---show: show the current settings");
display("---log: toggles logging");
display("---go: display the result");
display("---help: show these commands");
display("---quit: quit, of course");
}
/**
* Displays the current settings to the user.
*/
private static void showData() {
// convert the dates into formatted strings
String formattedStartOfDay = convertDateToFormattedString(startOfDay, timeFormatCalc);
String formattedEndOfDay = convertDateToFormattedString(endOfDay, timeFormatCalc);
String formattedStartDay = convertDateToFormattedString(start, dateAndTimeFormatCalc);
String formattedEndDay = convertDateToFormattedString(end, dateAndTimeFormatCalc);
// display the formatted information on screen
display("Business Day: " + formattedStartOfDay + " to " + formattedEndOfDay);
display("Business Hours: " + hoursPerBusinessDay);
display("DayStart: " + formattedStartDay);
display("DayEnd: " + formattedEndDay);
}
/**
* Handles requesting a user input and then performing the appropriate action based on that input
*/
private static void askForCommand() {
String command = requestCommandInput();
processCommandInputs(command);
}
/**
* Prompts user to enter a command and silently checks to see if the user
* entered a "quit" command, handling the command accordingly.
*
* @return The user input string.
*/
private static String requestCommandInput() {
display("Enter Command:");
String s = scan.nextLine();
checkForProgramQuit(s);
return s;
}
/**
* Chooses which action to take based on the command entered by the user and then performs that action.
*
* @param A string generally expected to be a user-input command string.
*/
private static void processCommandInputs(String s) {
// compare the command string against the list of pre-programmed commands to determine the action to take
if (s.equalsIgnoreCase("hours")) {
// request from user DayStart and DayEnd times
display("Please enter the time of Start of Business.");
display("Format: " + timeFormatRef);
startOfDay = requestDate();
display("Please enter the time of End of Business.");
display("Format: " + timeFormatRef);
endOfDay = requestDate();
recalcBusinessHours();
} else if (s.equalsIgnoreCase("start")) {
// request from user start date
display("Please enter the start date and time to calculate.");
display("Format: " + dateAndTimeFormatRef);
start = requestDate();
} else if (s.equalsIgnoreCase("end")) {
// request from user end date
display("Please enter the end date and time to calculate.");
display("Format: " + dateAndTimeFormatRef);
end = requestDate();
} else if (s.equalsIgnoreCase("show")) {
showData();
} else if (s.equalsIgnoreCase("holidaylist")) {
// TODO add code to change holidaylist
;
} else if (s.equalsIgnoreCase("go")) {
go();
} else if (s.equalsIgnoreCase("?") ||
s.equalsIgnoreCase("help") ||
s.equalsIgnoreCase("command") ||
s.equalsIgnoreCase("commands")) {
displayInstructions();
} else if (s.equalsIgnoreCase("log")) {
// toggles logging
display("Logging is now " + ((isLogging) ? "on" : "off") + ".");
isLogging = !isLogging;
} else {
// tell the user the command was invalid and allow the user to try again
display("Unknown Command");
}
// no matter what the command was, ask for the next command
askForCommand();
}
/**
* When called, recalculates the total hours of a business day based on the startOfDay and endOfDay times input by user or by default.
*/
private static void recalcBusinessHours() {
hoursPerBusinessDay = (int) Math.floor((endOfDay.getTime() - startOfDay.getTime()) / mSecInOneHour);
}
/**
* Prompts user to enter a date and/or time and silently checks to see if
* the user entered a "quit" command, handling the command accordingly.
*
* @return A date converted from the user entered string.
*/
private static Date requestDate() {
display("Enter Date and/or Time: ");
String s = scan.nextLine();
checkForProgramQuit(s);
Date date = convertStringToDate(s);
return date;
}
/**
* Attempts to convert the string parameter into a date. If the conversion
* fails, prompts the user to enter a valid input again. This method loops
* until a valid string is provided or the user enters a "quit" command.
*
* @param A string which is formatted correctly to be converted into a date.
* @return A date equal to the string entered, if possible.
*/
private static Date convertStringToDate(String string) {
Date date;
date = convertStringToDateFormat(string, dateAndTimeFormatCalc);
if (date == null)
date = convertStringToDateFormat(string, dateFormatCalc);
if (date == null)
date = convertStringToDateFormat(string, dateMiniFormatCalc);
if (date == null)
date = convertStringToDateFormat(string, timeFormatCalc);
if (date == null) {
// the date could not convert, notify user then allow them to try again
display("Your input: [" + string + "] does not convert. ");
display("If all else fails, please try '" + dateAndTimeFormatRef + "' format.");
display("An example looks like: " + "07/01/2013 17:00");
// request user input again
date = requestDate();
}
return date;
}
/**
* Helper method for convertStringToDate(string)
*
* @param String to convert
* @param String of date/time template to compare against.
* @return A date from the string
*/
private static Date convertStringToDateFormat(String string, String format) {
try {
return new SimpleDateFormat(format, Locale.ENGLISH).parse(string.trim());
} catch (ParseException e) {
// do not display failed attempts to convert
}
return null;
}
/**
* Helper method to convert a date back into a string for displaying to the user.
*
* @param A date to convert to a string
* @param String of date/time format to convert into.
* @return A string formatted like the format string from the date parameter.
*/
private static String convertDateToFormattedString(Date date, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ENGLISH);
return sdf.format(date);
}
/**
* Main method to perform the logic of the calculation. This method compares
* the start and end date/times to determine the working hours between them.
* In short, this method loops through each day between the start date and
* the end date and checks for holidays, weekends, and actual business hours
* each day. The primary loop used is
* calculateBusinessHoursInTheDay(calendar).
*/
private static void go() {
// calculate hours
int hours = 0;
// find the difference in the time between End and Start (End - Start) in Days
int numberOf24HourDays = (int) Math.floor((end.getTime()
- start.getTime())
/ mSecInOneDay);
// if the difference in days is not perfectly even, assume one more day
// [for example: midnight to midnight = 3.0 days, but midnight to noon = 3.5 days. this would make it 4 days to check]
if (((end.getTime() - start.getTime()) % mSecInOneDay) != 0) {
numberOf24HourDays += 1;
}
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(start);
log("C: " + cal.getTime().toString());
// daily loop, which checks how many working hours in the given day.
for (int i = 0; i < numberOf24HourDays; i++) {
hours += calculateBusinessHoursInTheDay(cal);
cal.add(GregorianCalendar.DATE, 1);
}
// convert the final total business working hours to days & hours
int resultDays = (int) Math.floor(hours / hoursPerBusinessDay); // TODO is this 8 hour days or calculated business days?
int resultHours = (hours % hoursPerBusinessDay);
// display results
showData();
display(hours + " total hours");
display(resultDays + " days, " + resultHours + " hours");
askForCommand();
}
/**
* The complex logic of the program. Determine if a given day is (a) a
* holiday, (b) a weekend, (c) the first of the last day of the calculation,
* which could be a partial day, or (d) a standard, full day.
*
* @param dateIn
* @return
*/
private static int calculateBusinessHoursInTheDay(GregorianCalendar dateIn) {
// prepare for heavy math
Date date = trimTimeOffDate(dateIn.getTime());
log("[Date] " + date.toString());
GregorianCalendar calendarDate = new GregorianCalendar(Locale.ENGLISH);
calendarDate.setTime(date);
GregorianCalendar startCalendarDate = new GregorianCalendar(Locale.ENGLISH);
startCalendarDate.setTime(start);
GregorianCalendar endCalendarDate = new GregorianCalendar(Locale.ENGLISH);
endCalendarDate.setTime(end);
// compare this date against every holiday, return 0 working hours
// if this date matches a holiday
for (Date holiday : holidays) {
if (date.equals(holiday)) {
log("Holiday " + 0 + " hours");
return 0;
}
}
// if this date is the weekend, return 0 working hours
if (calendarDate.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SUNDAY ||
calendarDate.get(GregorianCalendar.DAY_OF_WEEK) == GregorianCalendar.SATURDAY) {
log("Weekend " + 0 + " hours");
return 0;
}
long totalMillis = 0l;
// if start and end occur in the same day
if ((endCalendarDate.getTimeInMillis() - startCalendarDate.getTimeInMillis()) < mSecInOneDay) {
long mSecStart = startCalendarDate.getTimeInMillis() % mSecInOneDay;
long mSecEnd = endCalendarDate.getTimeInMillis() % mSecInOneDay;
totalMillis += (mSecEnd - mSecStart);
log((totalMillis / mSecInOneDay) + "/" + (mSecStart / mSecInOneDay)
+ "/" + (mSecEnd / mSecInOneDay));
// if start is before beginning of business day, subtract the time before business day starts
if (mSecStart < startOfDay.getTime()) {
log("Starts Before Business Day");
totalMillis -= startOfDay.getTime() - mSecStart;
}
// if end is after end of business day, subtract the time after business day ends
if (mSecEnd > endOfDay.getTime()) {
log("Ends After Business Day");
totalMillis -= endOfDay.getTime() - mSecEnd;
}
int sameDay = ((int) Math.floor(totalMillis / mSecInOneHour));
log("Same Day " + sameDay + " hours");
return sameDay;
}
// if this date is less than 24 hours from start date/time, ...
else if (((startCalendarDate.getTimeInMillis() - calendarDate.getTimeInMillis()) >= 0) &&
((calendarDate.getTimeInMillis() - startCalendarDate.getTimeInMillis()) < mSecInOneDay)) {
// calculate and convert the hours from this day
totalMillis += (calendarDate.getTimeInMillis() + mSecInOneDay) - startCalendarDate.getTimeInMillis();
// subtract the post-business evening hours
long businessTotalMillis = totalMillis - (endOfDay.getTime() - mSecInOneDay);
// if there is no time remaining (the start time was after end of business), return 0 hours
if (businessTotalMillis <= 0) {
return 0;
} else {
// if the time remaining in the business day is more than the hours in a business day
// (the start time was before start of business)
// return the number of hours in a full business day
int mSecInOneBusinessDay = (int)(endOfDay.getTime() - startOfDay.getTime());
if (businessTotalMillis > mSecInOneBusinessDay) {
log(((int)Math.floor(mSecInOneBusinessDay / mSecInOneHour)) + "");
int startDay = ((int)Math.floor(mSecInOneBusinessDay / mSecInOneHour));
log("Start Day " + startDay + " hours");
return startDay;
}
}
}
// if this date is less than 24 hours from the end date/time, ...
else if (((endCalendarDate.getTimeInMillis() - calendarDate.getTimeInMillis()) >= 0) &&
((endCalendarDate.getTimeInMillis() - calendarDate.getTimeInMillis()) < mSecInOneDay)) {
// calculate and convert the hours from this day
totalMillis += endCalendarDate.getTimeInMillis() - calendarDate.getTimeInMillis();
// subtract the pre-business morning hours
long businessTotalMillis = totalMillis - startOfDay.getTime();
// if there is no time remaining (the end time was before start of business), return 0 hours
if (businessTotalMillis <= 0) {
return 0;
} else {
// if the time remaining in the business day is more than the hours in a business day
// (the end time was after close of business)
// return the number of hours in a full business day
int mSecInOneBusinessDay = (int)(endOfDay.getTime() - startOfDay.getTime());
if (businessTotalMillis > mSecInOneBusinessDay) {
log(((int)Math.floor(mSecInOneBusinessDay / mSecInOneHour)) + "");
int endDay = ((int)Math.floor(mSecInOneBusinessDay / mSecInOneHour));
log("End Day " + endDay + " hours");
return endDay;
}
}
}
// otherwise, it must be a full working day
else {
int mSecInOneBusinessDay = (int)(endOfDay.getTime() - startOfDay.getTime());
int fullDay = ((int)Math.floor(mSecInOneBusinessDay / mSecInOneHour));
log("Full Day " + fullDay + " hours");
return fullDay;
}
return 0;
}
/**
* Helper method to reset the time on a date to 00:00 or midnight.
*
* @param Date to reset time on.
* @return Adjusted date with time set to 00:00
*/
private static Date trimTimeOffDate(Date date) {
GregorianCalendar oneDate = new GregorianCalendar();
oneDate.setTime(date);
oneDate.set(GregorianCalendar.HOUR_OF_DAY, 0);
return oneDate.getTime();
}
/**
* Helper method to quit program if command was "quit"
*
* @param Command string to compare with "quit"
*/
private static void checkForProgramQuit(String s) {
// check for a "quit" command
if (s.equalsIgnoreCase("quit") ||
s.equalsIgnoreCase("q") ||
s.equalsIgnoreCase("exit")) {
scan.close();
System.exit(0);
}
// next, check for a "help" command, just in case
if (s.equalsIgnoreCase("?") ||
s.equalsIgnoreCase("help") ||
s.equalsIgnoreCase("command") ||
s.equalsIgnoreCase("commands")) {
displayInstructions();
}
}
/**
* Simple log helper.
*
* @param String to display if isLogging is true.
*/
private static void log(String s) {
if (isLogging) display("Log: " + s);
}
/**
* Simple display helper.
*
* @param String to display to console.
*/
private static void display(String s) {
System.out.println(s);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment