# Challenge

You are given a time (12 hour / 24 hour).

Write a script to convert the given time from 12 hour format to 24 hour format and vice versa.

Ideally we expect a one-liner.

## Examples

### Example 1

```Input: 05:15 pm or 05:15pm
Output: 17:15
```

### Example 2

```Input: 19:15
Output: 07:15 pm or 07:15pm
```

# Overview

We have to do three things:

• Parse the input and extract the interesting parts (hours, minutes, `am`/`pm`/none).
• Calculate the result. Note that the minutes part stays as is, this doesn’t change whether the time is using am/pm or a 24 hour clock.
• Print the resulting time.

For the `am`/`pm` marker, note that if the input uses `am` or `pm`, then the output doesn’t. If the input doesn’t have `am` or `pm` (that is, it uses a 24 hour clock), then the output will have either `am` or `pm`. In particular, it will have `am` in the output if the input hour is less than `12`, else it will have `pm`.

For the hours, it’s important to realize that a time with `am` or `pm` doesn’t use the `0` hour — instead it uses `12`. So, beside adding/subtracting 12 (if going from/to `pm` time), we have to compensate for this. We do this as follows:

• We start off with taking the hour modulo 12. The effect of this is that if the start time uses `am` or `pm`, and the hour is `12`, the hour now is `0`. If the start time is in `24` hour format, we now have hours in range `0``11`.
• If the start time used `pm`, we add `12` to the hour.
• If the start time was in `24` hour format, and the hour is `0` (after the modulo `12`), set the hour to `12`.

# Solutions

For each of the languages, we assume the input is on standard input, one time per line. Output is written to standard output, one time per line.

## Perl

We will use a substitution regular expression to modify the time, with an executable replacement part:

```    say s {^\s* ([0-9]+) : ([0-9]+) \s* ([pa]?)m? \s*\n}
{sprintf "%02d:%02d%s",
\$3 ? (\$1 % 12) + (lc (\$3) eq "a" ? 0 : 12)
: (\$1 % 12) || 12,
\$2,
\$3 ? ""
: \$1 >= 12 ? "pm" : "am"}xeir
```

From the input, we parse the hours (the first `([0-9]+)`), the minutes (the second `([0-9]+)`) and the `am`/`pm` setting (if any) (`([pa]?)m?`). The result is that `\$1` contains the hours; `\$2` contains the minutes, and `\$3` is either `a` (for an `am` time), `p` (for a `pm` time) or the empty string (for a time using 24 hours).

In the replacement part, we use `sprintf` to do formatting: hours and minutes as two digit numbers (`0` padded) (`%02s`), followed by either `am`, `pm`, or none. The new hours and `am`/`pm` marker are calculated as explained in the overview section.

We’re using four regexp modifiers:

• `x` means we can freely have white space in the pattern, which won’t be matched.
• `e` means the replacement part is code which needs to be executed — the result is the replacement.
• `i` means we will be doing the matching case insensitive (so we accept both `am` and `AM`, and `pm` and `PM`).
• `r` means we don’t modify the original string, instead, we return the result. And this result is passed directly to `sprintf`.

Does this count as a one-liner? I say it does; the newlines are just there for readability.

Find the complete program on GitHub.