5 Replies
      Latest reply: Feb 4, 2017 11:06 PM by iPad_dev RSS
      pacient Level 1 Level 1 (0 points)

        I found this algorithmic question in HackerRank and I wondered how could it be improved. The algorithmic question asks you "Given a time in -hour AM/PM format, convert it to military (-hour) time."

         

        It accepts a string in the format e.g "07:05:45PM" and you are supposed to return "19:05:45"

         

        And here is my solution

         

        var str = "07:05:45PM"

        func convertToMilitary(fromTime time : String) -> String {

         

            var array = Array(time.characters.dropLast())

            var strr = "\(array[0])\(array[1])"

            if array[array.endIndex - 1] == "P"{

                if strr != "12" {

                    strr = "\(Int(strr)!+12)"

                }

            } else if array[array.endIndex - 1] == "A" {

                if strr == "12" {

                    strr = "00"

                }

            }

            array.remove(at: 0)

            array.remove(at: 0)

            array.removeLast()

            return "\(strr)\(String(array))"

        }

        convertToMilitary(fromTime: str)

         

         

        How could I improve this solution?

         

        Thanks in advance

        • Re: How could you improve this Swift algorithm?
          Claude31 Level 5 Level 5 (1,060 points)

          What's the purpose to improve ? Just fun of it ? Or is it cauising problem to your software ?

          • Re: How could you improve this Swift algorithm?
            zach.m Level 1 Level 1 (0 points)

            How about this?

             

            enum TimeError : Error {
                case invalidTimeString
            }
               
            func convertToMilitatyTime(fromTime time: String) throws -> String {
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "hh:mm:ssaa"
                let date = dateFormatter.date(from: time)
                guard date != nil else { throw TimeError.invalidTimeString }
                dateFormatter.dateFormat = "HH:mm:ss"
                return dateFormatter.string(from: date!)
            }
            
              • Re: How could you improve this Swift algorithm?
                eskimo Apple Staff Apple Staff (6,665 points)

                How about this?

                That won’t work in all circumstances.  Three things:

                • If you work with fixed-format date strings, you need to work in the en_US_POSIX locale.  See QA1480 NSDateFormatter and Internet Dates.

                • In situations like this, where you don’t need the actual date but rather just want a clean round trip conversion, it’s best to work in the GMT time zone.  If you work in the user’s time zone you’ll run into problems if the time in question doesn’t exist in that time zone (for example, you do this calculation on a daylight savings time transition day).

                • When working with date format strings, it’s a good idea to quote any literal components (like the colons).

                • Date formatters are relatively expensive, so you should statically allocates ones that can’t change.

                With these changes in place the code looks more complex:

                enum TimeError : Error { 
                    case invalidTimeString 
                }
                
                private var fromFormatter: DateFormatter = {
                    let df = DateFormatter()
                    df.locale = Locale(identifier: "en_US_POSIX")
                    df.timeZone = TimeZone(secondsFromGMT: 0)
                    df.dateFormat = "hh':'mm':'ssaa" 
                    return df
                }()
                
                private var toFormatter: DateFormatter = {
                    let df = DateFormatter()
                    df.locale = Locale(identifier: "en_US_POSIX")
                    df.timeZone = TimeZone(secondsFromGMT: 0)
                    df.dateFormat = "HH':'mm':'ss" 
                    return df
                }()
                
                func convertToMilitatyTime(fromTime time: String) throws -> String {
                    let date = fromFormatter.date(from: time) 
                    guard date != nil else { throw TimeError.invalidTimeString } 
                    return toFormatter.string(from: date!) 
                }
                

                Honestly, I’m not sure if DateFormatter is the right way to go here.  It’s a complex piece of code and it’s not clear whether the problem requirements justifies that complexity.  Specifically, if the input string is very tightly constrained, you could do something hackish like this.

                func convertToMilitatyTime(fromTime time: String) -> String {
                    let timeChars = Array(time.characters)
                    let hours = String(timeChars[0..<2])
                    let prefix: String
                    switch (timeChars[8], hours) {
                        case ("A", "12"):
                            prefix = "00"
                        case ("P", "12"):
                            prefix = "12"
                        case ("A", _):
                            prefix = hours
                        case ("P", _):
                            prefix = String(Int(hours)! + 12)
                        default:
                            fatalError()
                    }
                    return "\(prefix)\(String(timeChars[2..<8]))"
                }
                

                Of course, this will trap if the input doesn’t exactly match the standard format.

                Share and Enjoy

                Quinn “The Eskimo!”
                Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                let myEmail = "eskimo" + "1" + "@apple.com"

              • Re: How could you improve this Swift algorithm?
                iPad_dev Level 1 Level 1 (5 points)

                **** that's a lot of code for a simple function, throw this into a function, return newTime and done.  regex and perl are your friends

                 

                import Foundation
                let AA = "07:05:45PM"
                let a:[String] = AA.components(separatedBy: "AM")
                var newTime:String = ""
                if a[0] != AA
                { newTime = a[0] }
                else
                {
                  let b:[String] = AA.components(separatedBy: "PM")
                  let c:[String] = b[0].components(separatedBy: ":")
                  newTime = String("\(Int(c[0])! + 12 ):\(c[1]):\(c[2])")
                }