12 hour to 24 hour time converter

27

2

Amazingly, this simple task doesn't seem to exist already, so...

Your task is to write a program that takes as input a 12 hour time, and converts it into "military time", or 24-hour time format.

Input will be in the form:

HH:MM am/pm

Although slight variations are allowed:

  • The space separating the am/pm from the rest of the time is optional.

  • The last part can either be "am"/"pm", or "a"/"p".

  • Any capitalization is fine.

Output will be the inputted time, transformed into 24-hour format. It can be a number, or a string.

For both the input and output:

  • 0s in the first place are optional. 0s in the last 3 places are mandatory.

  • the delimiter separating hours and minutes can be a ":", " " (a space), or nothing.

Other notes:

  • Midnight can be expressed either as 0000, or 2400.

  • Midnight will be considered "am", while noon will be considered "pm".

Your program can be a function, or a full program, and should either return the result, or output it to the stdout. Trailing whitespace is ok.

Examples (you aren't required to support every format):

12:00am -> 0000
1200 pm -> 1200
1234Am  -> 00:34
134a    -> 134
01:34PM -> 13 34
1234pm  -> 1234  

This is code golf, so the smallest number of bytes wins. Since this is so trivial to solve using a built-in, it would be nice to see some code that manually solves this (but use of built-ins are fine).

Just to clarify, you aren't required to support every possible format. Supporting only a single input and a single output format (of your choice) is fine. I would however like to limit the format as outlined above (which is already quite free). {1134,'pm'}, for example, would be unacceptable.

Carcigenicate

Posted 2017-01-06T14:12:44.147

Reputation: 3 295

What formats are we required to support? Just one? – redstarcoder – 2017-01-06T14:33:57.167

@redstarcoder Yes. Any format that conforms to the requirements above is ok, but as noted above the example cases, you aren't required to support every format. A single format of input and a single format of output are fine. – Carcigenicate – 2017-01-06T14:36:11.880

are our formats allowed to require leading zeroes? For example, 01:54pm would work, but 1:54pm wouldn't? – FlipTack – 2017-01-06T20:41:48.057

Yes. You can pick the required input format. – Carcigenicate – 2017-01-06T20:47:52.413

Are we allowed to include seconds in our input and output? – 12Me21 – 2017-01-26T13:26:20.427

@12Me21 No, sorry. The output should be exactly as outlined above. Maybe if this was asked write after I posted it, but this far down the road, I don't want to start making exceptions to allowed output. – Carcigenicate – 2017-01-26T14:29:38.060

Downvoter, care to comment? – Carcigenicate – 2017-05-05T22:34:52.733

Answers

8

V, 21 17 bytes

Thanks @DJMcMayhem for 4 bytes!

í12:/0:
çp/12
$x

Try it online! This takes the format HH:MMx where x is either a or p, and returns it in the format HH:MM

Hexdump:

00000000: ed31 323a 2f30 3a0a e770 2f31 3201 2478  .12:/0:..p/12.$x
00000010: 0ae7 612f 2478                           ..a/$x

Explanation:

í12:/0:   | find and replace 12: with 0: (to avoid replacing HH:12)
ç         | on every line
 p/       | that contains a p
   12^A   | increment 12 times (the first number, hours)
$x        | delete the character at the end of the line

nmjcman101

Posted 2017-01-06T14:12:44.147

Reputation: 3 274

The input will always be in [1-12] right? In that case, I think you could do ó^12/0 instead of cw^R=^R"%12 – James – 2017-01-06T19:04:01.470

1Also, you could use the "global command" to apply a command to lines matching a regex, which is shorter than breaking a macro. çp/12^A which is equivalent to :g/p/norm 12<C-a> in vim – James – 2017-01-06T19:09:50.497

I accepted this because it was the lowest scoring answer that made it clear it wasn't using a built in (even though I didn't forbid using them). If anyone has a problem with this choice, I can change my answer to be fair. I think this answer is the most deserving though. – Carcigenicate – 2017-01-29T00:25:23.653

12

MATL, 4 bytes

15XO

Try it online!

Explanation

Built-in function: date string conversion with automatic detection of input format and with output format 15, which corresponds to 'HH:MM'. This is equivalent to @StewieGriffin's Octave answer.

Luis Mendo

Posted 2017-01-06T14:12:44.147

Reputation: 87 464

10

Octave, 21 17 bytes

Saved 4 bytes thanks to Luis Mendo. I could specify format number 15 instead of 'HHMM'.

@(c)datestr(c,15)

Explanation:

This is an anonymous function taking a string c as input on the format: '11:34 AM'. datestr recognizes the format automatically as one of the standard date formats, and outputs it in the specified format number 15, which is HH:MM.

Since the specified output format doesn't have AM or PM Octave automatically converts it to what you refer to as Military time.

Try it online.


A version not using datestr using 35 bytes

@(c)[c(1:4)+[1,2,0,0]*(c(5)>97),'']

Explanation:

Takes an input string c on the format 1134am.

@(c)                              % Anonymous function
[c(1:4)                           % First 4 elements of the string
       +[1,2,0,0]                 % Add 1 and 2 to the first to the ASCII-value of the 
                                    first two characters
                 *)c(5)>97)       % if the fifth element is larger than 97 
                                    (the ASCII code for `a`).
                            ,'']  % Implicitly convert to string

Or, a different approach for 37 bytes:

@(c)[c(1:4)+('1200'-48)*(c(5)>97),'']

Stewie Griffin

Posted 2017-01-06T14:12:44.147

Reputation: 43 471

7

PowerShell, 23 20 19 bytes

date "$args"-f HHmm

Try it online!

(If you're on Windows, you can omit the get-, to get down to 19 bytes. On TIO, it apparently requires the full Get-Date name.)

Takes input as a string $args[0], uses that as the input to the Get-Date cmdlet, which parses it into a .NET datetime object. That's passed with the -format parameter of HHmm to convert it to military time (the capital HH specifies 24-hour time). Output is implicit.

The parsing engine is pretty robust, so additional inputs like 12am or 12:00am are allowed as well. Play around with the input on TIO and see what else works.

(Saved 3 bytes thanks to @admalledd ... saved another byte thanks to @briantist)

AdmBorkBork

Posted 2017-01-06T14:12:44.147

Reputation: 41 581

Should be able to remove the space between $args[0] and -f, as well as remove the single quotes around the format str: date $args[0]-f HHmm. At least this works on my powershell... – admalledd – 2017-01-06T22:29:15.057

@admalledd For crying out loud, I always forget those quotes. Seriously, I think every single time I've used Get-Date with -f, someone has reminded me that you don't need the quotes. And good call with removing the space, too, since the parser treats the ] as the end of a token. Thanks! – AdmBorkBork – 2017-01-06T23:36:09.280

5

Pyth, 21 20 bytes

Aczd++*12}\pH%sG12PH

Takes input of the form 01 23a as "01:23 am". Initial 0 is optional.
Output is of the form 123, with the initial 0 omitted.

In pseudocode:

                         z = input()
A                        G, H =
 czd                         z.split(" ")       # splits into the form ["1","23p"]
                         (
     +*12}\pH            12*('p' in H) +        # add 12 if 'p' is in the string
             %sG12         int(G) % 12
    +             PH     ) + H[:-1]             # prepend hour to minutes, with a/p removed

Try it online!

busukxuan

Posted 2017-01-06T14:12:44.147

Reputation: 2 728

5

Python 2, 44 bytes

lambda s:`int(s[:2])%12+12*("p"in s)`+s[3:5]

Input format: 01:23am, optional m and spaces after minutes
Output format: 123

busukxuan

Posted 2017-01-06T14:12:44.147

Reputation: 2 728

4

PHP, 35 32 bytes

input format: case insensitive, requires colon and the m, output format hhmm. uses built-ins:

<?=date(Hi,strtotime($argv[1]));

takes input from first command line argument.

PHP, 45 bytes, no built-ins

input format (h)h:mm a(m) lowercase, output format (h)hmm.

<?=($s=$argv[1])%12+12*($s[6]>a).$s[3].$s[4];

Titus

Posted 2017-01-06T14:12:44.147

Reputation: 13 814

4Why the downvote? – Titus – 2017-01-07T11:58:37.687

I'm just speculating but maybe it's because you used PHP and the downvoter does not like PHP? :p – bash0r – 2017-01-07T18:12:21.477

3

Java 7, 138 106 105 104 bytes

String a(String a){return new java.text.SimpleDateFormat("Hmm").format(new java.util.Date("Ja1,0,"+a));}

Try it online!

Input is colon delimited and has a space between the time and the am/pm. Output is not colon delimited.

-1 byte thanks to Kevin Cruijssen

Poke

Posted 2017-01-06T14:12:44.147

Reputation: 3 075

Bout as short as it gets for Java, 20% of the code being package qualifiers. – Magic Octopus Urn – 2017-01-09T18:54:22.017

The rules state this "For both the input and output: - 0s in the first place are optional. 0s in the last 3 places are mandatory.", which means you can change HHmm to Hmm. – Kevin Cruijssen – 2017-05-04T12:00:27.777

@KevinCruijssen nice catch! – Poke – 2017-05-04T13:11:40.453

3

GNU Coreutils (18 16 bytes)

From a shell script:

Does not accept whitespace in the input

At which point, may as well use $1 and ignore additional args.

date -d$1 +%H%M

⇒ echo 'date -d$1 +%H%M' > time24
⇒ sh time24 1:45pm
1345
⇒ sh time24 1:45 pm
0145 # Wrong answer, “pm” ignored because of space

Original

To allow whitespace in the input,

date -d"$@" +%H%M

BRPocock

Posted 2017-01-06T14:12:44.147

Reputation: 161

3

JavaScript (ES6), 40 bytes

a=>(new Date('1/1/1/'+a)+a).slice(16,21)

Input should be formatted like: 12:32 am

Mwr247

Posted 2017-01-06T14:12:44.147

Reputation: 3 494

3

C#, 46 bytes

s=>System.DateTime.Parse(s).ToString("HH:mm");

Strings are taken in input like 12:00 AM

Doing the same thing but substringing on the output from the default call to ToString (Assuming a culture of en-GB) is 3 bytes longer for 49 bytes:

s=>(System.DateTime.Parse(s)+"").Substring(11,5);

TheLethalCoder

Posted 2017-01-06T14:12:44.147

Reputation: 6 930

3

date, 0 + 8 = 8 bytes

On the subject of using the right tool for the job…

Takes input as a command line argument. Run with +%H%M -d (8 byte penalty). There's no actual program here; the entire work is done by the command-line arguments. (This is a pretty good demonstration of why there's a penalty for command-line arguments!)

Example:

$ date +%H%M -d "12:05 am"
0005

user62131

Posted 2017-01-06T14:12:44.147

Reputation:

2

Perl, 45 28 37 bytes

28 37 bytes

(c/o @Dada)

(36 bytes code, 1 byte for compiler -p switch)

Accepts 0145pm type formats, with am/pm or a/p. Leading zeroes on inputs required.

s/(..)(.)$//;$_=$_%12+12*(p eq$2).$1

Test:

⇒ echo 0145pm | perl -p time24
1345
⇒ echo 0245pm | perl -p time24
1445
⇒ echo 1245pm | perl -p time24
1245
⇒ echo 1245am | perl -p time24
045

My original answer

(also gently revised)

(39 bytes code, 1 byte for compiler -p switch.)

Accepts only the form like 0145p or 0145a, and no other, and requires perl -p mode to work.

s/(..)(..)([ap])/$1%12+12*($3eq"p").$2/e

test:

⇒ echo 0145p | perl -p time24
1345
⇒ echo 1222a | perl -p time24
022
⇒ echo 1234p | perl -p time24
1234

BRPocock

Posted 2017-01-06T14:12:44.147

Reputation: 161

Welcome on PPCG. Nice first answer. You can use switches, but they count in your bytecount (as explained here). In your case, that would be +1 byte (because only -p is needed) if you change the single quotes for double quotes.

– Dada – 2017-01-06T18:55:41.377

Thanks. Couldn't find that FAQ, wonder if Stack Exchange team could pin it on the answer page or something? – BRPocock – 2017-01-06T19:23:13.753

OK, I've been Perling since the 4 series and that makes my head hurt, you should take the credit and post yourself with that one. ☺ – BRPocock – 2017-01-06T19:24:25.137

I think that should cover it now? – BRPocock – 2017-01-06T19:34:15.957

I made a mistake, this solution won't work when the minutes are between 0 and 9. This code works then: s/(..)(.)$//;$_=$_%12+12*(p eq$2).$1 (37 bytes). And by the way, your first solution can be golfed down a little bit: s/(..)(..)([ap])/$1%12+12*($3eq"p").$2/e (40 bytes) – Dada – 2017-01-07T23:18:17.757

2

Japt, 14 bytes

Ð"1/"+U s sG21

Try it online!

This only works on Chrome. Here's a version that works in all browsers:

Ð"1/"³+U s sG21

Thanks again to ETHproductions for the help!

Oliver

Posted 2017-01-06T14:12:44.147

Reputation: 7 160

2

C, 87 72 bytes

Saved 15 bytes thanks to @Johan du Toit

Call f() with a mutable string as an argument, the input is the output.

The format is HH:MMa/p, where a/p is either lowercase a or lowercase p. No space between the time and the meridian specifier is allowed.

i;f(char*p){i=atoi(p)%12+(p[5]^97?12:0);*p=i/10+48;p[1]=i%10+48;p[5]=0;}

Try it on ideone.

owacoder

Posted 2017-01-06T14:12:44.147

Reputation: 1 556

you can save a couple of bytes by using the following: i;f(char*p){i=atoi(p)%12+(p[5]^97?12:0);*p=i/10+48;p[1]=i%10+48;p[5]=0;} – Johan du Toit – 2017-05-04T12:18:59.883

Suggest (p[5]!=97)*12; instead of (p[5]^97?12:0); – ceilingcat – 2018-10-11T07:38:46.017

2

C (clang), 94 bytes

h,m;f(){char a,b;scanf("%d:%d%c%c",&h,&m,&a,&b);printf("%02d%02d",a=='a'?(h%12):(12+h%12),m);}

Try it online!

I'm here to learn, so any tips on how i can optimize the code are welcome.

@ Johan du Toit Thanks, for saving a few bytes!

Abel Tom

Posted 2017-01-06T14:12:44.147

Reputation: 1 150

You do not have to test if b == 'm' and you can make it much shorter by using inline if statements: printf("%02d:%02d", (a=='p' ? 12 : 0) + (h %12), m); – Johan du Toit – 2017-05-04T11:59:14.800

1@JohanduToit What i input is 6:00pc ? :) – Abel Tom – 2017-05-04T15:54:18.107

1That will cause irreparable harm to the space-time continuum. – Johan du Toit – 2017-05-04T16:57:38.660

175 bytes – ceilingcat – 2018-10-11T07:06:28.520

2

tcl, 45 47

Now using a built-in:

puts [clock f [clock sc $s -f %I:%M%p] -f %R]

Testable on http://rextester.com/TSRXI8802 where there is a script that runs it from 0100am to 1259pm

sergiol

Posted 2017-01-06T14:12:44.147

Reputation: 3 055

2

Commodore 64 BASIC, 301 bytes before running, 321 bytes used once run

0 A$="12:34AM":A=VAL(LEFT$(A$,2)+MID$(A$,4,2)):ON-(RIGHT$(A$,2)="AM")+1GOSUB1,2:TI$=A$:PRINTTI$:END
1 ON-(A=>1200ANDA<=1259)GOTO3:A=A+1200:GOTO3
2 ON-(A=>1200ANDA<=1259)GOTO4:ON-(A<=959)GOTO7:RETURN
3 A$=RIGHT$(STR$(A)+"00",6):RETURN
4 A=A-1200:IFA=0THENA$="000000":RETURN
5 IFA<10THENA$="000"+RIGHT$(STR$(A),1)+"00":RETURN
6 A$="00"+RIGHT$(STR$(A),2)+"00":RETURN
7 A$="0"+RIGHT$(STR$(A),3)+"00":RETURN

In order to enter this on a real Commodore 64, you will need to use BASIC keyword abbreviations, such as LE[shift]F for LEFT$, M[shift]I for MID$ etc... or you could try CBM PRG STUDIO.

The TI$ variable in Commodore BASIC presents the time in 24 hour clock format as HHMMSS when printed. Taking the space out after the line number does not save any memory as Commodore BASIC adds in the space automatically anyway when you list the program after entering it.

When converting a number to a string with STR$, Commodore BASIC will add in the space (so if you PRINT A you will see a space before the number is shown), I've removed the opening space on the number to string conversion with the RIGHT$ command. You could save a few bytes by amending line zero to:

0 A=VAL(LEFT$(A$,2)+MID$(A$,4,2)):ON-(RIGHT$(A$,2)="AM")+1GOSUB1,2:TI$=A$:PRINTTI$:END

so you will need to declare your time to convert before running the program, as follows:

A$="01:22AM":GOTO 0

At any moment thereafter, you can see the current time with:

? TI$

Shaun Bebbers

Posted 2017-01-06T14:12:44.147

Reputation: 1 814

Playing code golf on 8-bit machines is really interesting as it shows how much is done for a modern-days programmer without even needing to think about it. – Shaun Bebbers – 2017-03-20T17:02:24.640

2

SmileBASIC, 67 bytes

INPUT T$P=POP(T$)>"a
TMREAD"00:"+T$OUT,H,M?H MOD 12+12*P,T$[3];T$[4]

Input: HH:MMa/p

Output: HH MM

12Me21

Posted 2017-01-06T14:12:44.147

Reputation: 6 110

2

Java, 171 bytes

enum t{;public static void main(String[] a){a=a[0].split("[: ]");System.out.format("%02d%02d",(Long.parseLong(a[0])+(a[2].charAt(0)=='p'?12:0))%24,Long.parseLong(a[1]));}}

Input format is HH:MM a/p and output format is HHMM. Abusing the fact that main function has an array of strings to split the input into 3 sections: hour, minute and a/p indicator.

Example input and output:

Input: 01:02 a
Output: 0102

Input: 01:02 p
Output: 13:02

Input: 12:22 p
Output: 0022

Ungolfed version:

enum t {
    ;

    public static void main(String[] a) {
        a = a[0].split("[: ]");
        System.out.format("%02d%02d", (Long.parseLong(a[0]) + (a[2].charAt(0) == 'p' ? 12 : 0)) % 24, Long.parseLong(a[1]));
    }
}

cookie

Posted 2017-01-06T14:12:44.147

Reputation: 271

I hadn't seen enum used to hold the main. Nice :) – Robert Benson – 2017-05-03T18:59:55.680

You can omit a space in the main method signature: public static void main(String[]a){... – staticmethod – 2017-05-05T22:58:23.070

2

REXX, 33 bytes

arg h':'m a
say h+((a=pm)*12)':'m

Use:

12:34 pm -> 24:34
1:34 pm -> 13:34
1:34 am -> 1:34
0:34 AM -> 0:34

This could be shortened by a few bytes if a colon as delimiter was not used.

idrougge

Posted 2017-01-06T14:12:44.147

Reputation: 641

Colon delimiter is optional. – Carcigenicate – 2017-03-21T10:27:26.863

Yes, but it doesn't look good. – idrougge – 2017-03-22T09:03:29.550

Given this is a code-golfing challenge, if you have the option of a longer program with pretty output, or a shorter program with uglier output, choose the latter. No one will judge you. – Carcigenicate – 2017-03-22T10:48:30.060

1

R, 68 bytes

x=substr(strptime(scan(,""),"%I:%M %p"),12,16);`if`(x=="","00:00",x)

Reads input from stdin and it's assumed to be in one of the following formats:

  • 12:00 AM
  • 12:00 am
  • 12:00AM
  • 12:00am

and output is on the format: [1] "00:00"

In most instances strptime() output is on the format: "2017-01-06 12:00:00 CET" where the date is the local date. As such we need to use substr() to only return the time, however, if the input is midnight (e.g. 12:00am) the output is only "2017-01-06 CET" which is the reason for the if thing at the end (there must be some more clever workaround).

Billywob

Posted 2017-01-06T14:12:44.147

Reputation: 3 363

I really wanted to find a shorter way with lubridate, but the name of the package is too long (among other problems). – BLT – 2017-05-04T19:47:57.553

1

tcl, 88 102 107 110

Naïve attempt:

puts [format %03d [expr {[regsub p $s "" n]?([scan $n %d]+1200)%2400:[regsub a $s ""]}]]

testable on http://rextester.com/live/XUKJU62994 where there is a script that runs it from 0100a to 1259p

sergiol

Posted 2017-01-06T14:12:44.147

Reputation: 3 055

1

C, 159 152 bytes

#define C c[0]
main(i,c)char**c;{scanf("%s",C);i=atoi(C);if(C[5]-97){i+=i-12?12:0;sprintf(C,"%d",i);}else if(i==12)C[0]=C[1]=48;C[2]=58;C[5]=0;puts(C);}

Input format: 07:30am

Steadybox

Posted 2017-01-06T14:12:44.147

Reputation: 15 798

1

Pyke, 15 bytes

4<bwӐi%\pQ{i*+

Try it here!

Blue

Posted 2017-01-06T14:12:44.147

Reputation: 26 661

1

Mathematica, 33 bytes

#~DateString~{"Hour24","Minute"}&

Anonymous function. Takes a string as input and returns a string as output. Works with most formats, including hh:mm AM/PM.

LegionMammal978

Posted 2017-01-06T14:12:44.147

Reputation: 15 731

1

tcl, 66 67 68

scan $s %d%c t c;puts [format %03d [expr $c>97?($t+1200)%2400:$t]]

in http://rextester.com/live/VDSG70132 there is a script that runs it from 0100a to 1259p

sergiol

Posted 2017-01-06T14:12:44.147

Reputation: 3 055

1

JavaScript, 67 bytes

f=s=>!~s.indexOf`pm`?s.slice(0,5):((+s.slice(0,2)+12)+s.slice(2,5))

Input is like in the example

lhama butt

Posted 2017-01-06T14:12:44.147

Reputation: 11

Does not work for 12:00 am or 12:00 pm – Herman L – 2017-11-04T16:30:59.980

1

Common Lisp (151122 bytes)

OK, CL isn't meant to be “terse” but I'm just surprised that it isn't the most verbose for this one.

Here's the 122 byte version, which requires fixed-position input. 0145pm or 145p are acceptable (with the leading space in the first character-position).

(defun a(x)(let((h(parse-integer(subseq x 0 2)))(m(subseq x 2 4)))(format nil "~a~a" (+(mod h 12)(if(find #\p x)12 0))m)))

PPRINT:

(DEFUN A (X)
  (LET ((H (PARSE-INTEGER (SUBSEQ X 0 2)))
        (M (SUBSEQ X 2 4)))
    (FORMAT NIL
            "~a~a"
            (+ (MOD H 12) (IF (FIND #\p X) 12 0))
            M)))

Nicer but bigger

Using only the Common-Lisp package. Accepts (only) input in the form of integer hours (with or without leading 0), literal :, two-digit minutes, and optional trailing am or pm (in lower-case only). Permits whitespace around the time and around the AM/PM, but not directly after the :.

(defun a(x)(let*((c(position #\: x))(h(parse-integer(subseq x 0 c)))(m(subseq x(1+ c)(+ 3 c))))(format nil "~a~a" (+(mod h 12)(if(find #\p x)12 0))m)))

Test:

GOLF> (a "  1:45 am ")
"1:45"
GOLF> (a "  1:45 pm ")
"13:45"
GOLF> (a " 12:45 am ")
"0:45"
GOLF> (a "12:45p")
"12:45"

pprint the function definition:

(DEFUN A (X)
  (LET* ((C (POSITION #\: X))
         (H (PARSE-INTEGER (SUBSEQ X 0 C)))
         (M (SUBSEQ X (1+ C) (+ 3 C))))
    (FORMAT NIL "~a~a"
            (+ (MOD H 12)
               (IF (FIND #\p X)
                   12
                   0))
            M)))

De-obfuscated:

(defun 12->24-hour (timestring) 
  "Given a  TIMESTRING with  hours:minutes and a  trailing “am”  or “pm”
   \(lowercase-only), return the 24-hour time without a delimiter as
   a  string \(eg,  \"1:45am\" →  \"0145\"). Spaces  surrounding the
   time or  meridian markers are ignored  \(eg, \" 02:22 pm  \") but
   other junk in the string may cause incorrect behavior."
  (let ((colon (position #\: timestring)))
    (let ((hours (parse-integer (subseq timestring 0 colon)))
          (minutes (subseq timestring (+ 1 colon) (+ 3 colon))))
      (format nil "~a~a"
              (+ (mod hours 12) (if (find #\p timestring) 12 0))
              minutes))))

BRPocock

Posted 2017-01-06T14:12:44.147

Reputation: 161

1

Haskell, 61 characters

Short version:

c[a,b,c,d,e]=(mod(read[a,b]::Int)12+f e,[c,d])
f 'a'=0
f _=12

Input format: HHMM(a/p) where (a/p) is either 'a' or 'p' without parenthesis.

Output format: (hs, MM) – a tuple containing the hours as an integer and MM still as string.

Example:

> c "1200p"
(12,"00")
> c "1200a"
(0,"00")

Longer version (with more useful names and one substitution hs):

conv [h0,h1,m0,m1,ap] = (mod hs 12 + offset ap, [m0,m1])
    where hs = read [h0,h1] :: Int

offset 'a'=  0
offset  _ = 12

user3389669

Posted 2017-01-06T14:12:44.147

Reputation: 341

1

Retina, 61 60 bytes

^12(.*)a
00$1
^(12.*)p
$1
a

(\d\d)(.*)p
$1$*x12$*x$2
x+
$.&

Input is given without a separating colon, mandatory leading 0, and using only a or p instead of am or pm, eg 0134a is 01:34 am. Outputs in straight military time using 0000 as midnight. (I could save some bytes if I'm allowed to convert, for example, 12:30 am into 2430, but I doubt that's acceptable).

Try it online!

Explanation

The initial two cases deal with the "12" hours, since am/pm is reversed for 12:

^12(.*)a
00$1

If the time is between midnight (12 am) and 1 am, change it to 00 instead of 12, and remove the a.

^(12.*)p
$1

If the time is between noon (12 pm) and 1pm, remove the p to simply get the 24 hour time.

For any other hour:

a
 

If the time is am, simply remove the a to get the 24 hour time.

(\d\d)(.*)p
$1$*x12$*x$2
x+
$.&

If the time is pm, remove the p. Convert the hour component to unary, add 12, and convert back to decimal. Leave the minutes unchanged.

Business Cat

Posted 2017-01-06T14:12:44.147

Reputation: 8 927

1

Batch, 40 bytes

@set/aa=0,p=12,h=%1%%12+%3
@echo %h% %2

Takes input as three arguments. Assumes second argument has leading zero where necessary, third argument is either a or p. Works by treating the third argument as an indirect variable name therefore adding it on to the number of hours; the number of minutes is unaffected so is just output directly. If mixing different formats is OK then the last space can be deleted to save a byte.

(Rather annoyingly, this question didn't appear on the questions page when I originally loaded it, and I only stumbled across it because I was searching for another question.)

Neil

Posted 2017-01-06T14:12:44.147

Reputation: 95 035

1

AWK, 18 bytes

/p/{$1+=1200}$0=$1

Try it online!

Input is hhmm am/pm, i.e. the time as a 3 or 4 digit number with whitespace separating the am/pm designator.

Robert Benson

Posted 2017-01-06T14:12:44.147

Reputation: 1 339

1

T-SQL, 48 bytes

CREATE PROC t @ DATETIME AS PRINT FORMAT(@,'Hm')

Must be used in SQL Server 2012+. The input is converted to '1900-01-01 HH:mm:ss.sss' and the FORMAT function gets the hour and minute part.

Usage:

EXECUTE t @ = '10:45pm'

WORNG ALL

Posted 2017-01-06T14:12:44.147

Reputation: 61

1

Groovy, 49 50 bytes

+1 byte because of invalid output format :(

{t=it.split();(​​​t[0]​as int)+(t[2]=="pm"?12:0)+t[1]}​​​​​​​

Input is given in format HH MM am or HH MM pm. Output is in format HHMM.

Quick explaination:

it.split() splits the input in an array [hour, minute, am/pm ] Then it returns the hours concatenated with the minutes, but adds 12 to the hours before returning if the last item of the array is "pm"

Previous solution

 {t=it.split();t[2]=="pm"?(t[0]as int)+12+t[1]:it}

staticmethod

Posted 2017-01-06T14:12:44.147

Reputation: 191

What about "12 00 pm"? – 12Me21 – 2018-04-01T05:36:20.780

1

Retina, 46 bytes

.*p
12$0
\D

..(?=..)
$*!
!+
$.&
^12
00
^24
12

Try it online!

Input must supply at minimum 2 digits each for HH & MM and a "p" if applicable. Output only returns a leading 0 for the 12 AM hour (I'm unclear if the note on midnight should be interpreted literally, but if not, that would shave off 1 byte). Works on the example cases, provided you prepend 134a with a 0.

Non-digit characters (besides p) are stripped. Lines lacking a "p/pm" are treated as AM. PM times are shifted up by 12 hours, and 12/24 are simply swapped at the end.

Curated

Posted 2017-01-06T14:12:44.147

Reputation: 11

1

Tcl, 76 bytes

if [scan $s %dp%n n -]>1 {set n [expr ($n+1200)%2400]};puts [format %03d $n]

Try it online!

sergiol

Posted 2017-01-06T14:12:44.147

Reputation: 3 055

0

Clojure, 143 108 96 bytes

+54 bytes to fix a "noon/midnight bug" where times within the hour after noon/midnight would return wrong values.

-35 bytes by getting ideas from other answers. If the hour is == 12, I make it 0. This reduces the number of cases that need to be dealt with.

-12 bytes thanks to BRFennPocock.

I'm not sure if I'm allowed to compete. I can remove this or mark it as non-competing if necessary. It's not like I'm winning though :)

V3

#(let[[h m[i]](clojure.string/split % #" ")](str(+(if(= i\p)12 0)(mod(Integer/parseInt h)12))m))

Ungolfed:

(defn to-24h [time-str]
  ; Split the string on spaces, then deconstruct out the hour,
  ; minute, and whether it's am or pm
  (let [[hours minutes [ampm]] (clojure.string/split time-str #" ")
        pm? (= ampm \p)
        h (mod (Integer/parseInt hours) 12)]
    (str (+ (if pm? 12 0) h)
         minutes)))

V2

#(let[[h m[i]](clojure.string/split % #" ")h(Integer/parseInt h)h(if(= h 12)0 h)](str(if(= i\p)(+ h 12)h)m))

Ungolfed:

(defn to-24h [time-str]
  ; Split the string on spaces, then deconstruct out the hour,
  ; minute, and whether it's am or pm
  (let [[hours minutes [ampm]] (clojure.string/split time-str #" ")
        pm? (= ampm \p)
        h (Integer/parseInt hours)
        h (if (= h 12) 0 h)] ; 0-out the hours if they're equal to 12 to minimize cases
    (str (if pm?
           (+ h 12)
           h)
         minutes)))

V1

#(let[[h m[i]](clojure.string/split % #" ")p(= i\p)h(Integer/parseInt h)t(= h 12)](str(cond(and(not t)p)(+ h 12)(and t (not p))(- h 12):e h)m))

The Java-interop and library reference are killer, but I think they're probably the best options here. Thank God for restructuring though. Easiest parse ever.

Takes input in the format 12 34 am, and outputs as 034. Drops 0s in the first place.

Ungolfed:

(defn to-24h [time-str]
  ; Split the string on spaces, then deconstruct out the hour,
  ; minute, and whether it's am or pm
  (let [[hours minutes [ampm]] (clojure.string/split time-str #" ")
        pm? (= ampm \p)
        h (Integer/parseInt hours)
        twelve? (= h 12)]
    ; Dispatching to figure out how much needs to be added/subtracted.
    (str (cond (and (not twelve?) pm?) (+ h 12)
               (and twelve? (not pm?)) (- h 12)
               :e h)
         minutes)))

With Built-ins, 83 bytes

(fn[s](let[p #(java.text.SimpleDateFormat. %)](.format(p"km")(.parse(p"h m a")s))))
;                                                     Parse the 3 pieces ^
;                          Format into "squished" format ^

Basically the Java answer. Input must be in the format 12 34 pm

Carcigenicate

Posted 2017-01-06T14:12:44.147

Reputation: 3 295

You can shave it to 99 by using mod: #(let[[h m[i]](clojure.string/split % #" ")h(mod(Integer/parseInt h)12)](str(if(= i\p)(+ h 12)h)m)) — and shave another byte by moving if inside +: #(let[[h m[i]](clojure.string/split % #" ")h(mod(Integer/parseInt h)12)](str(+(if(= i\p)12 0)h)m)) – BRPocock – 2017-01-11T17:00:38.697

Oh, and then just inline h for 96B: #(let[[h m[i]](clojure.string/split % #" ")](str(+(if(= i\p)12 0)(mod(Integer/parseInt h)12))m)) – BRPocock – 2017-01-11T17:02:47.463

@BRFennPocock Cool, thanks. I'm about to start work, so I don't want to start fiddling with it now. I'll update it tonight. Thanks again. – Carcigenicate – 2017-01-11T17:06:45.543

0

Acc!!, 101 97 bytes

(N*10+N)%12*60+N*10+N-528+N/98*720
Write _/600+48
Write _/60%10+48
Write _%60/10+48
Write _%10+48

Expects input in the form 0123a (all digits mandatory, no separators, lowercase am/pm indicator). Gives output like 0123.

Try it online!

Explanation

Acc!! reads one character code at a time using the N special value. With a sufficiently strict input format, we can read five characters and do a little math to compute the number of minutes since midnight, and from there it's easy to print out the 24-hour time.

Deobfuscated, the first line is

((N-48)*10 + N-48)%12*60 + (N-48)*10 + N-48 + N/98*720
  • The first character is the tens digit of the hour, and the second character is the ones digit of the hour. We convert both from character codes to the associated digits (N-48) and combine them into a single number (...*10 + ...).
  • If the hour is 12, we want it to become 0; otherwise, it should stay the same. This is accomplished by a mod 12 operation (%12). (Note: in the golfed code, the %12 also takes care of the -48s here.)
  • Multiply by 60 in preparation to add the minutes (*60).
  • Process the next two characters as minutes digits, in the same way as the hours digits ((N-48)*10 + N-48).
  • Now we want to add 12 to the hour if the next character is p (ASCII 112), or add nothing if it's a (ASCII 97).
    • We can distinguish the two by int-dividing by 98: N/98 is 0 if N is 97 and 1 if N is 112.
    • Adding 12 hours is the same as adding 720 minutes: + ...*720

This value is stored in the accumulator, _.

Now for our output, we need:

  • Tens digit of the hour
  • Ones digit of the hour
  • Tens digit of the minute
  • Ones digit of the minute

The hour is _/60, and the minute is _%60. The tens digit of a number (less than 100) is .../10, and the ones digit is ...%10. Combining a few operations where possible gives the four expressions in the code (remembering that we need +48 to convert digits back to corresponding character codes).

DLosc

Posted 2017-01-06T14:12:44.147

Reputation: 21 213