String split with parseInt in Java - java

We are asked to build a constructor for a Stopwatch that takes a string in the format of "##:##:###" and updates minutes, seconds and milliseconds (private instance variables) accordingly. For example, "1:21:300" indicates 1 minute 21 seconds 300 milliseconds.
So I am trying to use string.split() paired with parseInt to update values. However, the program will not compile. My constructor has the correct syntax according to eclipse, but there is something wrong with what I am doing. I have never actually used split nor parseInt, so I could be using these 100% wrong. Thank you.
public StopWatch(String startTime){
String [] timeArray = startTime.split(":");
if(timeArray.length == 2){
this.minutes = Integer.parseInt(timeArray[0]);
this.seconds = Integer.parseInt(timeArray[1]);
this.milliseconds = Integer.parseInt(timeArray[2]);
}
else if(timeArray.length == 1){
this.minutes = 0;
this.seconds = Integer.parseInt(timeArray[1]);
this.milliseconds = Integer.parseInt(timeArray[2]);
}
else if(timeArray.length == 0){
this.minutes = 0;
this.seconds = 0;
this.milliseconds = Integer.parseInt(timeArray[2]);
}
else{
this.minutes = 0;
this.seconds = 0;
this.milliseconds = 0;
}
}
P.S. Junit test says "ComparisonFailue: expected 0:00:000 but was 20:10:008" when trying to do:
s = new StopWatch("20:10:8");
assertEquals(s.toString(),"20:10:008");

As mentioned in other answers, the lengths are off by 1 each each, but the index's you are using in if block are also off; eg. if the length is 1, the only index available is 0, if the length is 2, the index's available are 0 and 1.
Thus you get a constructor that looks like:
class StopWatch {
int minutes;
int seconds;
int milliseconds;
public StopWatch(String startTime) {
String[] timeArray = startTime.split(":");
if (timeArray.length == 3) {
this.minutes = Integer.parseInt(timeArray[0]);
this.seconds = Integer.parseInt(timeArray[1]);
this.milliseconds = Integer.parseInt(timeArray[2]);
} else if (timeArray.length == 2) {
this.minutes = 0;
this.seconds = Integer.parseInt(timeArray[0]);
this.milliseconds = Integer.parseInt(timeArray[1]);
} else if (timeArray.length == 1) {
this.minutes = 0;
this.seconds = 0;
this.milliseconds = Integer.parseInt(timeArray[0]);
} else {
this.minutes = 0;
this.seconds = 0;
this.milliseconds = 0;
}
}
}

Replace your toString() method with:
public String toString() {
String paddedMinutes = String.format("%02d", this.minutes);
String paddedSeconds = String.format("%02d", this.seconds);
String paddedMilliseconds = String.format("%03d", this.milliseconds);
return paddedMinutes + ":" + paddedSeconds + ":" + paddedMilliseconds;
}

Though Java arrays are zero-based, their lengths simply count the number of elements.
So, {1,2,3}.length will return 3.
As your code is written now you will be getting ArrayOutOfBounds exceptions left and right.

if(timeArray.length == 2){
should be:
if(timeArray.length == 3){
and so on.
20:10:8 split by : will give you a length of 3 ;)

Related

Converting String time format of HH:MM:SS (AM/PM) into Seconds

So I have this assignment that is asking us to take in a String format of time in the order of HH:MM:SSAM or HH:SS:MMPM. The constraint is that it cannot run if it is in wrong format, let it be missing any form of the AM or PM, missing a number, or if it is in 24 Hour Format.
I have the whole idea down, however for my statements, it is giving me the error of:
bad operand types for binary operator '>'
incomparable types: String and int
Did I convert them improperly or am I doing something else wrong?
public static void main(String args[]) {
//Test Methods
String fullTime1 = "03:21:36AM";
secondsAfterMidnight(fullTime1);
}
public static int secondsAfterMidnight(String time) {
String[] units = time.split(":");
int hours = Integer.parseInt(units[0]);
int minutes = Integer.parseInt(units[1]);
int seconds = Integer.parseInt(units[2]);
int totalSeconds = 0;
if (units[0] > 12 || units[1] > 59 || units[2] > 59) { //1st Error applies to these three, units[0] > 12 units[1] > 59 units[2] > 59
return -1;
} else if (time.equalsIgnoreCase("AM") || time.equalsIgnoreCase("PM")) {
totalSeconds = (hours * 3600) + (minutes * 60) + (seconds);
} else if (time.equalsIgnoreCase("AM") && units[0] == 12) { //2nd Error applies to this units[0] == 12
totalSeconds = (minutes * 60) + (seconds);
} else {
return -1;
}
return totalSeconds;
}
You have already parsed the String values and saved them in the variables hours , minutes, seconds. Then you can use those for the check in the if.
Also the presence of AM?PM in the Integer.parseInt() will cause NumberFormatException to avoid it remove the String part from the number by using regex.
Also for checking the presence of AM/PM you can use String.contains.
Please check the reformatted code below:
public static int secondsAfterMidnight(String time) {
String[] units = time.split(":");
int hours = Integer.parseInt(units[0]);
int minutes = Integer.parseInt(units[1]);
int seconds = Integer.parseInt(units[2].replaceAll("[^0-9]", ""));
int totalSeconds = 0;
if (hours > 12 || minutes > 59 || seconds > 59) {
return -1;
} else if (time.contains("AM") || time.contains("PM")) {
totalSeconds = (hours * 3600) + (minutes * 60) + (seconds);
} else if (time.contains("AM") && hours == 12) {
totalSeconds = (minutes * 60) + (seconds);
} else {
return -1;
}
return totalSeconds;
}
Please note that even though you have converted the String to int, you are still comparing String with int. There would also be a RuntimeException when you do this:
int seconds = Integer.parseInt(units[2]);
As units[2] will contain 36AM. So you should be using substring() to remove the "AM/PM" part.
units is of type String and you are trying to compare it with an int hence the compile time error.
You need to convert the String to an int and then compare it, as shown below :
Integer.parseInt(units[0]) > 12
so on and so forth.
Also rather than re-inventing the wheel, you can make use of the already existing java-8's LocalTime to find the number of seconds for a particular time:
public static int secondsAfterMidnight(String time) {
LocalTime localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("hh:mm:ss a"));
return localTime.toSecondOfDay();
}
I haven't verified your logic to calculate the seconds, but this code has corrections:
public static int secondsAfterMidnight(String time) {
String[] units = time.split(":");
int hours = Integer.parseInt(units[0]);
int minutes = Integer.parseInt(units[1]);
int seconds = 0;
String amPm = "";
if ( units[2].contains("AM") || units[2].contains("PM") ||
units[2].contains("am") || units[2].contains("pm") ) {
seconds = Integer.parseInt(units[2].substring(0, 2));
amPm = units[2].substring(2);
}
else {
seconds = Integer.parseInt(units[2]);
}
int totalSeconds = 0;
if (hours > 12 || minutes > 59 || seconds > 59) {
return -1;
} else if (amPm.equalsIgnoreCase("AM") || amPm.equalsIgnoreCase("PM")) {
totalSeconds = (hours * 3600) + (minutes * 60) + (seconds);
} else if (amPm.equalsIgnoreCase("AM") && hours == 12) {
totalSeconds = (minutes * 60) + (seconds);
} else {
return -1;
}
return totalSeconds;
}
java.time
static DateTimeFormatter timeFormatter
= DateTimeFormatter.ofPattern("HH:mm:ssa", Locale.ENGLISH);
public static int secondsAfterMidnight(String time) {
try {
return LocalTime.parse(time, timeFormatter).get(ChronoField.SECOND_OF_DAY);
} catch (DateTimeParseException dtpe) {
return -1;
}
}
Let’s try it out using the test code from your question:
String fullTime1 = "03:21:36AM";
System.out.println(secondsAfterMidnight(fullTime1));
12096
This is the recommended way for production code.
Only if you are doing an exercise training string manipulation, you should use one of the other answers.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Java Clock Program

I am trying to make a clock program using Java, and I got everything to work properly except I cannot get the program to change the negative values to 0. I also cannot get the program to set the values of hours, minutes, and seconds to 0 if they are out of range. I have a tester program that I have to use and the T1 and T2 clock values are incorrect in my code. T1 should be 0:0:0 and T2 should be 0:0:0 as well. However, when I output my code it comes out as T1 being -3:-21:-30 and T2 is 24:60:60. I know there is something wrong with my code, but I can't find the issue, if anyone would be able to help me that would be greatly appreciated. Below is my code and then the second section is the tester code that I have to use.
public class Clock
{
// instance variables
private int hours;
private int minutes;
private int seconds;
public void setHours(int newHours) {
hours = newHours;
if (hours<0 || hours > 24) {
hours = 0;
}
}
public void setMinutes(int newMinutes) {
minutes = newMinutes;
if (minutes<0 || minutes > 60) {
minutes = 0;
}
}
public void setSeconds(int newSeconds) {
seconds = newSeconds;
if(seconds<0 || seconds > 60) {
seconds = 0;
}
}
/**
* Constructor for objects of class Clock
*/
public Clock(int newHour, int newMinute, int newSecond)
{
if (newHour > -1 || newHour < 24) {
this.hours = newHour;
}
else {
setHours(hours);
}
if (newMinute > -1 || newMinute < 60) {
this.minutes = newMinute;
}
else {
setMinutes(minutes);
}
if (newSecond > -1 || newSecond < 60) {
this.seconds = newSecond;
}
else {
setSeconds(seconds);
}
}
public int getHours() {
return hours;
}
public int getMinutes() {
return minutes;
}
public int getSeconds() {
return seconds;
}
public String toString() {
return hours + ":"+minutes+":"+seconds;
}
public void tick() {
seconds = seconds +1;
if(seconds >= 60)
{
minutes ++;
seconds = 0;
}
if(minutes >= 60)
{
hours++;
minutes = 0;
}
if(hours >=24)
{
hours = 0;
}
}
}
The next piece is the tester code.
public class ClockTest {
public static void main(String [] args){
//Create some clocks and print their times
Clock c1 = new Clock(-3,-21,-30);
System.out.println("T1: "+ c1);
c1 = new Clock(24,60,60);
System.out.println("T2: "+ c1);
c1 = new Clock(3,21,30);
System.out.println("T3: "+ c1);
//Tick the clock twice and print its time
c1.tick();
c1.tick();
System.out.println("T4: "+ c1);
c1 = new Clock(3,30,59);
c1.tick();
System.out.println("T5: "+ c1);
c1 = new Clock(3,59,59);
c1.tick();
System.out.println("T6: "+ c1);
c1 = new Clock(23,59,59);
c1.tick();
System.out.println("T7: "+ c1);
c1 = new Clock(0,0,1);
c1.tick();
System.out.println("T8: "+ c1);
c1 = new Clock(1,1,1);
c1.setHours(22);
c1.setMinutes(30);
c1.setSeconds(35);
System.out.println("T9: "+ c1);
System.out.println("T10: " + c1.getHours() + ":"
+c1.getMinutes() + ":" + c1.getSeconds());
}
}
Your condition is wrong.
When you write this:
if (newHour > -1 || newHour < 24) {
You really mean this:
if (newHour > -1 && newHour < 24) {
#nicomp is correct and you should also be using >= 24 and 60 instead of >. You might consider changing the constructor for Clock to
public Clock(int newHour, int newMinute, int newSecond) {
setHours(newHour);
setMinutes(newMinute);
setSeconds(newSecond);
}
and then do all of your validation in the set methods, instead of having some validation in the set methods and some in the constructor.

Simple Junit testing with OOP java

Below is a class that represents time using hours and minutes (seconds are not represented).
public class ClassTime {
public static int hour;
public static int minute;
public static String amPm;
//Initializes the object using specified parameter values.
public ClassTime(int hour, int minute, String amPm){
//hour value between 1 and 12, both inclusive.
boolean validHour = false;
if (hour >= 1 && hour <= 12){
validHour = true;
this.hour = hour;
} else {
throw new IllegalArgumentException("Invalid hour value");
}
//minute value between 0 and 59, both inclusive.
boolean validMinute = false;
if (minute >= 0 && minute <= 59){
validMinute = true;
this.minute = minute;
} else {
throw new IllegalArgumentException("Invalid minutes value");
}
//amPm is either "am" or "pm".
if (amPm.equalsIgnoreCase("am")){
this.amPm = amPm;
} else if (amPm.equalsIgnoreCase("pm")){
this.amPm = amPm;
} else {
throw new IllegalArgumentException("Invalid am/pm value");
}
}
/*
* Returns a string using the format "hour:minutes am" or "hour:minutes pm".
* A single space is used in between minutes and am/pm. The minutes always
* appear with two digits (e.g., 0 minutes will be "00").
*/
public String toString(){
String toBeReturned = "hour:" + String.format("%02d", this.minute) +
" " + amPm;
return toBeReturned;
}
/*
* Compares two time objects. Two time objects are considered equal if
* they represent the same time.
*/
public boolean equals(ClassTime obj){
boolean equal = false;
if (obj.minute == this.minute && obj.hour == this.hour &&
obj.amPm.equalsIgnoreCase(this.amPm)){
equal = true;
}
return equal;
}
/*
* Compares two time objects. Returns -1 if the current object is a time
* that precedes the time parameter, 0 if the current object and the time
* parameter represent the same time, and 1 if the current object represents
* a time that is after the time parameter.
*/
public int compareTo(ClassTime obj){
int returnNum = 2;
if(this.amPm.equalsIgnoreCase("am") && obj.amPm.equalsIgnoreCase("pm")){
returnNum = -1;
} else if (this.amPm.equalsIgnoreCase("pm") &&
obj.amPm.equalsIgnoreCase("am")){
returnNum = 1;
} else if (this.amPm.equalsIgnoreCase(obj.amPm)){
if (this.hour < obj.hour){
returnNum = -1;
} else if (this.hour > obj.hour){
returnNum = 1;
} else if (this.hour == obj.hour){
if (this.minute < obj.minute){
returnNum = -1;
} else if (this.minute > obj.minute){
returnNum = 1;
} else if (this.minute == obj.minute){
returnNum = 0;
}
}
}
return returnNum;
}
/*
* Returns a new time object corresponding to the time we will have after
* increasing the time parameter by the specified number of minutes.
*/
public static ClassTime increaseByMinutes(ClassTime obj, int minutes){
//create variables that monitor changes in minutes, hours, and amPm.
int minValue = obj.minute + minutes;
int hourValue = obj.hour;
String amPmValue = obj.amPm;
/*
* increments hour and minutes if the total minutes is below two hours,
* but greater tan or equal to 1 hour.
*/
if(minValue > 59 && minValue < 120){
minValue = minValue % 60;
hourValue = hourValue + 1;
if (hourValue > 12){
hourValue = hourValue % 12;
} else if(hourValue == 12 && amPmValue.equalsIgnoreCase("am")){
amPmValue = "pm";
} else if (hourValue == 12 && amPmValue.equalsIgnoreCase("pm")){
amPmValue = "am";
}
/*
* Increment for when the total amount of minutes is greater
* or equal to 2 hours.
*/
} else if (minValue > 119){
for(int i = 0; i <= (minValue/60); i++){
hourValue++;
if(hourValue > 12){
hourValue = hourValue % 12;
} else if (hourValue == 12 && amPmValue.equalsIgnoreCase("am")){
amPmValue = "pm";
} else if (hourValue == 12 && amPmValue.equalsIgnoreCase("pm")){
amPmValue = "am";
}
}
}
/*
* Create a new ClassTime object with the found values of minutes, hours,
* and amPm Value. This is what will be returned.
*/
ClassTime newObject = new ClassTime(hour, minute, amPm);
newObject.minute = minValue;
newObject.hour = hourValue;
newObject.amPm = amPmValue;
return newObject;
}
public static void main(String[] args) {
}
}
I don't know how to test the constructor or the methods in a JUnit test case. So far the only thing I can come up with for the constructor is:
import static org.junit.Assert.*;
import org.junit.Test;
public class JunitTests {
#Test
public void testClassTime() {
ClassTime object1 = new ClassTime(3, 30, "pm");
}
}
How would I finish doing a test for the constructor and maybe just 1 method. Please don't do all of them.
I suggest you read up on unit testing, your question is a bit too broad.
Basically the idea is that given some situation, when a thing happens, then some conditions should be true. (I personally add comments to my tests to help me think in those terms.)
Here's an abstract example:
Given bread and a toaster
When I put the bread in the toaster and get it out when it's done
Then it should be toasted
Look up JUnit's assertion library to help find good ways to assert conditions. When looking up JUnit examples you'll usually see things like assertTrue(...) or assertNotNull(...), these are static methods from the Assert class, I mention this because you seem like a novice and I don't want you to get confused by examples. Usually all these methods are imported statically in the examples.
What you have in your test case currently is the given, a when could be doing toString() (String actual = object1.toString();). Your then clause would be asserting that the String returned equals what it should, which is probably "3:30 PM" (assertEquals("3:30 PM", actual);). I didn't design your code, so I don't know if that's correct, you may expect it to return `"Hello, World!" In any case, I'd run this one first ;)

How to check if a day lies between a range?

I have a job which runs from a given day to a certain day of week . For eg (Monday to Saturday).
I was able to cover the case when stopday > starday for eg-startday->Monday stopDay->Saturday
but when the range changes to something like Wednesday to Monday , I am not able to cover this case.
private boolean isNotWindow(DateTime todayDate) {
final int hr = 3600;
final int min = 60;
int stopDay =
Integer.parseInt(ShipmentTrackingEmailProperties.getInstance().getProperty(
ShipmentTrackingEmailProperties.SHIPMENT_EMAIL_STOP_DAY));
int startDay =
Integer.parseInt(ShipmentTrackingEmailProperties.getInstance().getProperty(
ShipmentTrackingEmailProperties.SHIPMENT_EMAIL_START_DAY));
if(stopDay<startDay)
{
//Not able to figure out??????
}
if (todayDate.getDayOfWeek() >= stopDay) {
String stopTime =
ShipmentTrackingEmailProperties.getInstance().getProperty(ShipmentTrackingEmailProperties.SHIPMENT_EMAIL_STOP_TIME);
String[] array = stopTime.split(":");
System.out.println(array[0] + " " + array[1] + " " + array[2]);
int hh = Integer.parseInt(array[0]);
int mm = Integer.parseInt(array[1]);
int ss = Integer.parseInt(array[2]);
int tSec = todayDate.getHourOfDay() * hr + todayDate.getMinuteOfDay() * min + todayDate.getSecondOfDay();
int sSec = hh * hr + mm * min + ss;
if (tSec > sSec) {
return true;
}
}
if (todayDate.getDayOfWeek() <= startDay) {
String startTime =
ShipmentTrackingEmailProperties.getInstance().getProperty(ShipmentTrackingEmailProperties.SHIPMENT_EMAIL_START_TIME);
String[] array = startTime.split(":");
int hh = Integer.parseInt(array[0]);
int mm = Integer.parseInt(array[1]);
int ss = Integer.parseInt(array[2]);
int tSec = todayDate.getHourOfDay() * hr + todayDate.getMinuteOfDay() * min + todayDate.getSecondOfDay();
int sSec = hh * hr + mm * min + ss;
if (tSec <= sSec) {
LOG.info("Not a valid day to send mail ." + todayDate.getDayOfWeek());
return true;
}
}
LOG.info("Valid day to send mail ." + todayDate.getDayOfWeek());
return false;
}
This function returns true if the day does not fall in a range.So how to cover the case when
stopDay < startDay
You need:
if startday<stopday then
if the day is in the interval (startday,stopday) then OK
else NotOk
else
if the day is not in the interval (startday,stopday) then OK
else NotOk
It could be much easier done as:
If((day-startday)*(stopday-day)*(stopday-startday)>=0) then OK
else NotOk
You can use this function to check for the day in range
private static boolean inRange(int startDay, int stopDay, int checkMe) {
if(startDay==stopDay) {
if(startDay==checkMe){
return true;
} else {
return false;
}
}
while(startDay!=stopDay) {
if(startDay==checkMe || stopDay==checkMe) {
return true;
}
if(startDay==7) {
startDay =0;
}
startDay++;
}
return false;
}
Hope it helps.

How to sum minutes in array if their format is string?

I have an string array that includes some minutes like "00:05", "00:30", "00:25" etc. I want to sum the values as time format? Can anyone help me how do I do this?
Total time in minutes:
int sum = 0;
final String[] mins = new String[] { "00:05", "00:30", "00:25" };
for (String str : mins) {
String[] parts = str.split(":");
sum += Integer.parseInt(parts[1]);
}
System.out.println(sum);
You don't specify exactly how you want this output formatted.
If there may be hour elements as well, then replace the second line of the loop with this:
sum += (Integer.parseInt(parts[0]) * 60) + Integer.parseInt(parts[1]);
I'll go for quick and dirty
Split each String on the ":"
Convert both parts to integer
Multiply the first time by 60 to convert hours to minutes, and add the second part
Do this for each value in your array, and count them together
This results in the total time in minutes, which you can convert to whatever format you like
You could substring it, and then call Integer.parseInt on the result. For the hours part, do the same and multiply it by 60.
Split the strings on ':', pars the values as ints and add 'em up.
this is my suggestion. Neither compiled, ran, tested, nor guaranteed.
long seconds = 0;
for ( String min : minutes )
{
seconds += Integer.parseInt(min.substring(0,1))*60 + Integer.parseInt(min.substring(3,4));
}
return new Date ( seconds / 1000 ) ;
An object oriented approach:
public static TimeAcumm sum(final String[] times) {
final TimeAcumm c = new TimeAcumm();
for (final String time : times) {
c.incrementFromFormattedString(time);
}
return c;
}
public class TimeAcumm {
private int hours = 0;
private int minutes = 0;
private int seconds = 0;
public int getHours() {
return hours;
}
public int getMinutes() {
return minutes;
}
public int getSeconds() {
return seconds;
}
public void incrementFromFormattedString(final String time) {
final String[] parts = time.split(":");
this.minutes += Integer.parseInt(parts[0]);
this.seconds += Integer.parseInt(parts[1]);
validate();
}
private void validate() {
if (this.minutes > 59) {
this.hours++;
this.minutes -= 60;
}
if (this.seconds > 59) {
this.minutes++;
this.seconds -= 60;
}
}
#Override
public String toString() {
final String s = hours + "H:" + minutes + "M:" + seconds + "S";
return s;
}
}

Categories

Resources