0

Note : I looked as much as I could for 2 days to check if this is a duplicate. If I missed something, I apologize. This question is to find what the issue is with my attempt at a solution, not one of the existing solutions out there.

My Question

I was trying to solve some problems on hackerrank in Java 7 and I came across the time conversion problem where the problem statement is:

Problem: "Given a time in -hour AM/PM format, convert it to military (24-hour) time."

Sample Input 07:05:45PM

Sample Output 19:05:45

I looked at solutions involving libraries (such as java.text.SimpleDateFormat, Calendar etc.) but I am trying to do it on my own without them. The issue that I am facing here is that my solution is failing on some test cases but is working on others. In short, it is not the correct solution. I see other solutions but I want to know why mine fails as the correct answer. Could you please help me by telling me where this would fail and how I can go about correcting it?

Some of the solutions that I looked at are:

Conversion from 12 hours time to 24 hours time in java

Convert 12 hours to 24 hours

My code is here:

import java.io.*;
import java.math.*;
import java.text.*;
import java.util.*;
import java.util.regex.*;

public class Solution {

    static String timeConversion(String s) {

        //get the string into an array using : as a separator
        String[] time_array = s.split(":");

        //military_time variable to be returned
        String military_time = new String();

        //final HH part
        String hh_final = new String();
        //Rest after HH to be concatenated to get military_time
        String rest = new String();


        StringBuilder REST_mil_builder = new StringBuilder();
        for (int i = 2; i < 8; i++) {
            REST_mil_builder.append(s.charAt(i));
        }
        //"rest" basically gets everything after HH excluding AM/PM, so 01:03:40PM would have a "rest" value of ":03:40"
        rest = REST_mil_builder.toString();

        int hh = Integer.parseInt(time_array[0]);
        String AMPM_contains = time_array[2];

        //converting if the last piece after the split contains "PM"
        if (AMPM_contains.contains("PM")) {
            hh = hh + 12;
            hh = hh == 24 ? 0 : hh;
        }

        //converting hh to have a 0 before it because when it is an integer 01 will be just 1 which we don't want
        StringBuilder hh_build = new StringBuilder();
        if (hh >= 0 && hh <= 9) {
            hh_build.append("0");
            hh_build.append(hh);
            hh_final = hh_build.toString();
        } else {
            hh_build.append(hh);
            hh_final = hh_build.toString();
        }

        //military time concatenation
        military_time = hh_final + rest;
        //Midnight is 12:00:00AM on a 12-hour clock, and 00:00:00 on a 24-hour clock
        military_time = s == "12:00:00AM" ? "00:00:00" : military_time;
        //Noon is 12:00:00PM on a 12-hour clock, and 12:00:00 on a 24-hour clock.
        military_time = s == "12:00:00PM" ? "12:00:00" : military_time;

        return military_time;

    }

    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args)  {

        //tried several 12 hour time formats here
        String result = timeConversion("01:30:59PM");
        System.out.println(result);
    }
}
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Rahul P
  • 2,493
  • 2
  • 17
  • 31
  • Time to learn how to use a debugger. Step through the program, look at the variables and how they change. – Robert May 26 '18 at 19:27

9 Answers9

6

Your code fails because it doesn't correctly handle hour 12, i.e. 12:xx:xxAM should map to 00:xx:xx, and 12:xx:xxPM should map to 12:xx:xx, as pointed out in answer by Ole V.V.

Rather than trying to fix the overly complicated code you have, here is a different approach, without using SimpleDateFormat.

Parse the first 2 digits to a number. If the number is 12, set it to 0. A trick way to do that is to use modulo 12. If input ends with PM, add 12. Now rebuild string, replacing first 2 digits with new number, and removing AM/PM suffix.

Like this:

public static String timeConversion(String s) {
    int hour = Integer.parseInt(s.substring(0, 2)) % 12;
    if (s.endsWith("PM"))
        hour += 12;
    return String.format("%02d", hour) + s.substring(2, 8);
}

Using tests by Ole V.V.

System.out.println(timeConversion("12:30:59AM"));
System.out.println(timeConversion("11:30:59AM"));
System.out.println(timeConversion("12:30:59PM"));
System.out.println(timeConversion("11:30:59PM"));

Output

00:30:59
11:30:59
12:30:59
23:30:59
Andreas
  • 154,647
  • 11
  • 152
  • 247
2
    System.out.println(timeConversion("12:30:59AM"));
    System.out.println(timeConversion("11:30:59AM"));
    System.out.println(timeConversion("12:30:59PM"));
    System.out.println(timeConversion("11:30:59PM"));

Expected output:

00:30:59
11:30:59
12:30:59
23:30:59

Observed output:

12:30:59 (wrong)
11:30:59 (correct)
00:30:59 (wrong)
23:30:59 (correct)

Edit: In short it seems your code doesn’t take into account that hour 12 is different nn the 12 hour clock. You may say it’s used as hour 00. I don’t think it will be too hard to fix your program, so I will let you have the pleasure of the first shot. If you need a hint, please follow up in comments. We’re all happy to help.

As an aside, you are using new String() in three places in your code. I think it’s superfluous because you are never using the created empty strings for anything.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • This is only an answer to *"Could you please help me by telling me where this would fail?"*, but not to *"how I can go about correcting it?"* --- Still, it is *useful*, so +1 – Andreas May 26 '18 at 19:50
  • This is more or less what I was looking for. Thank you! – Rahul P May 26 '18 at 20:21
0

Please try this static String timeConversion(String s) function.I hope this will help you.

static String timeConversion(String s) {

        String[] time = s.split(":");

        String hours = time[0];
        String minutes = time[1];
        String seconds = time[2].substring(0, 2);
        String dayEve = time[2].substring(2, 4);
        if (dayEve.equals("AM")) {
            return ((hours.equals("12") ? "00" : hours) + ":" + minutes + ":" + seconds);
        } else {
            return ((hours.equals("12") ? hours : (Integer.parseInt(hours) + 12)) + ":" + minutes + ":" + seconds);
        }

    }

The prime logic is :-

If 'AM' and hours == 12 then hours set to 00 else do not change hours.

If 'PM' and hours == 12 then do not change hours else hours is set to hours = hours+12.

anoopknr
  • 3,177
  • 2
  • 23
  • 33
  • 2
    But why reinvent the wheel if the standard Java libraries already have what you need? – Robert May 26 '18 at 19:26
  • If you're going to hardcode `substring` offsets, why not just do that instead of using `split`, i.e. `hours = s.substring(0, 2), minutes = s.substring(3, 5), seconds = s.substring(6, 8), dayEve = s.substring(8)` – Andreas May 26 '18 at 19:40
  • Thank you Anoop and Andreas. This helped me understand things a little more. – Rahul P May 26 '18 at 20:23
0

Do use SimpleDateFormat:

public static String to24Time(String str) throws ParseException {
    DateFormat df12 = new SimpleDateFormat("hh:mm:ssa", Locale.US);
    DateFormat df24 = new SimpleDateFormat("HH:mm:ss", Locale.US);
    return df24.format(df12.parse(str));
}

P.S. This is task from Hackerrank: Algorithms/Warmup/Time Conversion.

  1. There is not any notes that it is forbidden to use java internal classes for time parsing and you have to do it manually.
  2. Provided answer gives 100% test pass for this task.

P.P.S In case you do not want to use SimpleDateTime, this is example how to use Regular Expression. Note, that I do not provide full validation of input sting; in some cases (e.g. for illegal 12h time format like 21:17:17PM) it returns illega result instead of exception:

public static String to24Time(String str) throws ParseException {
    final Pattern TIME_12 = Pattern.compile("(?<hour>\\d{2}):(?<minute>\\d{2}):(?<second>\\d{2})(?<part>am|pm)");
    Matcher matcher = TIME_12.matcher(str.toLowerCase());

    if (matcher.matches()) {
        int hour = Integer.parseInt(matcher.group("hour"));
        return ("pm".equals(matcher.group("part")) ? hour + 12 : hour) + ":" + matcher.group("minute") + ':' + matcher.group("second");
    }

    return null;
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • @OleV.V. Do not agree. It works perferctly for years for it's job and it is not deprecated. Yes, I know there're other time libraty with ZonedDateTime etc. You're free to use what you like. I use SimpleDateTime sometime - and I HAVE NEVER FACED WITH PROBLEM using it. – Oleg Cherednik May 26 '18 at 19:38
  • @OleV.V. Downloading a 3rd-party library, just for such a small task, is overkill. Besides, this is for hackerrank (question says so), so you can't add 3rd-party library. Your arguments are invalid. So, constrained to Java 7 and no libraries, please present a valid argument for not using `SimpleDateFormat`. – Andreas May 26 '18 at 19:41
  • @OleV.V. If that's your argument for not using `SimpleDateFormat`, then you should have made that argument to begin with. But, you're right, that *is* a valid argument. – Andreas May 26 '18 at 19:53
  • The asker was explicit about trying to solve the problem without `SimpleDateFormat`, so your answer isn’t helpful. For real-world/production code one should of course use a library class, namely `DateTimeFormatter` from [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/), and should shun `SimpleDateFormat`. The latter is long outdated and notoriously troublesome. Yes, I too have used it in the past without problems, but such an observation subtracts nothing from the trouble that very many programmers have had with that class. – Ole V.V. May 26 '18 at 20:31
0

Here is how I solved it using JavaScript:

function timeConversion(s) {


    var res;

    var pos = s.substring(-2, 8);

    var split = pos.split(':');

    if (split[0] == 12 && s.endsWith('AM')) {
        res = '00' + ':' + split[1] + ':' + split[2];

    } else if (split[0] == 12 && s.endsWith('PM')) {
        res = '12' + ':' + split[1] + ':' + split[2];

    } else if (split[0] < 12 && s.endsWith('AM')) {
        res = split[0] + ':' + split[1] + ':' + split[2];

    } else if (split[0] < 12 && s.endsWith('PM')) {
        var add = Number(split[0]) + 12;
        res = add + ':' + split[1] + ':' + split[2];
    }
    return res;
}
Jasoya
  • 66
  • 4
0
static String timeConversion(String s) {
    int hrs = 12;
    String[] split = s.split(":");
    String originalAMPM = split[2].substring(2,4);
    String hours = split[0]; String minutes = split[1]; String seconds = split[2].substring(0,2);
    if(originalAMPM.equals("PM")) {
        if(!hours.equals("12"))
            hrs = Integer.parseInt(hours) + 12;
        return hrs + ":" + minutes + ":" + seconds;
    }
    else {
        if(hours.equals("12"))
            hours = "00";
        return hours + ":" + minutes + ":" + seconds;
    }
}
   
0

#!/bin/python3

import os
import sys
import re
#
# Complete the timeConversion function below.

def timeConversion(s):

    if s[len(s)-2:]=='PM':
        
        if s[0] == '0':
            s1=s.strip('0')
            sn = s1.strip('PM')
            return sn.replace(sn[0],str(int(sn[0])+12))

        elif s[0:2]=='12':
            
            return s.strip('PM')
        else:
            sn = s.strip('PM')
            return sn.replace(sn[0:2],str(int(sn[0:2])+12)) 

    else: #s[len(s)-2:]=='AM':

        if s[0:2]=='12':
            s1=s.strip('AM')
            return s1.replace(s[0:2],'00')
        else:
            return s.strip('AM') 
                     
        

    
if __name__ == '__main__':
    f = open(os.environ['OUTPUT_PATH'], 'w')

    s = input()

    result = timeConversion(s)

    f.write(result + '\n')

    f.close()
0

Here is how I solved it using JavaScript:

function timeConversion(s) {
    let time = [];
    let mid = s.slice(0,2);
    if(s.includes('PM')){        
        if( mid === '12' ){
            time = s;
        } else{
          let mid1 = Number(mid)+12;
          time = s.replace(mid, mid1.toString());   
        }             
    } else if(mid === '12'){ 
       time = s.replace(mid, '00');        
    } else time = s;    
   return time.slice(0,-2);
};
0
SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss aa");
StringBuilder std = new StringBuilder(s);
if(std.toString().contains("P"))
{
   std.insert(std.indexOf("P"), " ");
}else{
   std.insert(std.indexOf("A"), " ");
}
   
String.format("%tT",df.parse(std.toString())));
Saleh
  • 57
  • 1
  • 3