How could you improve this Swift algorithm?

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 🙂

Replies

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

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!)
}

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"

Thanks, this is great information.

**** 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])")
}