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.

  • \$\begingroup\$ What formats are we required to support? Just one? \$\endgroup\$ – redstarcoder Jan 6 '17 at 14:33
  • \$\begingroup\$ @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. \$\endgroup\$ – Carcigenicate Jan 6 '17 at 14:36
  • \$\begingroup\$ are our formats allowed to require leading zeroes? For example, 01:54pm would work, but 1:54pm wouldn't? \$\endgroup\$ – FlipTack Jan 6 '17 at 20:41
  • \$\begingroup\$ Yes. You can pick the required input format. \$\endgroup\$ – Carcigenicate Jan 6 '17 at 20:47
  • \$\begingroup\$ Are we allowed to include seconds in our input and output? \$\endgroup\$ – 12Me21 Jan 26 '17 at 13:26

39 Answers 39


V, 21 17 bytes

Thanks @DJMcMayhem for 4 bytes!


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


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


í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
  • \$\begingroup\$ 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 \$\endgroup\$ – DJMcMayhem Jan 6 '17 at 19:04
  • 1
    \$\begingroup\$ Also, 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 \$\endgroup\$ – DJMcMayhem Jan 6 '17 at 19:09
  • \$\begingroup\$ 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. \$\endgroup\$ – Carcigenicate Jan 29 '17 at 0:25

MATL, 4 bytes


Try it online!


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.


Octave, 21 17 bytes

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



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



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:


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)

  • \$\begingroup\$ 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... \$\endgroup\$ – admalledd Jan 6 '17 at 22:29
  • \$\begingroup\$ @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! \$\endgroup\$ – AdmBorkBork Jan 6 '17 at 23:36

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


Pyth, 21 20 bytes


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!


PHP, 35 32 bytes

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


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.

  • 4
    \$\begingroup\$ Why the downvote? \$\endgroup\$ – Titus Jan 7 '17 at 11:58
  • \$\begingroup\$ I'm just speculating but maybe it's because you used PHP and the downvoter does not like PHP? :p \$\endgroup\$ – bash0r Jan 7 '17 at 18:12

JavaScript (ES6), 40 bytes

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

Input should be formatted like: 12:32 am


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
⇒ sh time24 1:45 pm
0145 # Wrong answer, “pm” ignored because of space


To allow whitespace in the input,

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

C#, 46 bytes


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:


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


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

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

  • \$\begingroup\$ Bout as short as it gets for Java, 20% of the code being package qualifiers. \$\endgroup\$ – Magic Octopus Urn Jan 9 '17 at 18:54
  • \$\begingroup\$ 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. \$\endgroup\$ – Kevin Cruijssen May 4 '17 at 12:00
  • \$\begingroup\$ @KevinCruijssen nice catch! \$\endgroup\$ – Poke May 4 '17 at 13:11

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!


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


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

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.



⇒ echo 0145p | perl -p time24
⇒ echo 1222a | perl -p time24
⇒ echo 1234p | perl -p time24
  • \$\begingroup\$ 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. \$\endgroup\$ – Dada Jan 6 '17 at 18:55
  • \$\begingroup\$ Thanks. Couldn't find that FAQ, wonder if Stack Exchange team could pin it on the answer page or something? \$\endgroup\$ – BRPocock Jan 6 '17 at 19:23
  • \$\begingroup\$ 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. ☺ \$\endgroup\$ – BRPocock Jan 6 '17 at 19:24
  • \$\begingroup\$ I think that should cover it now? \$\endgroup\$ – BRPocock Jan 6 '17 at 19:34
  • \$\begingroup\$ 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) \$\endgroup\$ – Dada Jan 7 '17 at 23:18

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$
  • \$\begingroup\$ 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. \$\endgroup\$ – Shaun Bebbers Mar 20 '17 at 17:02

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]));
  • \$\begingroup\$ I hadn't seen enum used to hold the main. Nice :) \$\endgroup\$ – Robert Benson May 3 '17 at 18:59
  • \$\begingroup\$ You can omit a space in the main method signature: public static void main(String[]a){... \$\endgroup\$ – staticmethod May 5 '17 at 22:58

REXX, 33 bytes

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


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.

  • \$\begingroup\$ Colon delimiter is optional. \$\endgroup\$ – Carcigenicate Mar 21 '17 at 10:27
  • \$\begingroup\$ Yes, but it doesn't look good. \$\endgroup\$ – idrougge Mar 22 '17 at 9:03
  • \$\begingroup\$ 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. \$\endgroup\$ – Carcigenicate Mar 22 '17 at 10:48

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!

  • \$\begingroup\$ 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); \$\endgroup\$ – Johan du Toit May 4 '17 at 11:59
  • 1
    \$\begingroup\$ @JohanduToit What i input is 6:00pc ? :) \$\endgroup\$ – Abel Tom May 4 '17 at 15:54
  • 1
    \$\begingroup\$ That will cause irreparable harm to the space-time continuum. \$\endgroup\$ – Johan du Toit May 4 '17 at 16:57
  • 1
    \$\begingroup\$ 75 bytes \$\endgroup\$ – ceilingcat Oct 11 '18 at 7:06

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.


Try it on ideone.

  • \$\begingroup\$ 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;} \$\endgroup\$ – Johan du Toit May 4 '17 at 12:18
  • \$\begingroup\$ Suggest (p[5]!=97)*12; instead of (p[5]^97?12:0); \$\endgroup\$ – ceilingcat Oct 11 '18 at 7:38

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


SmileBASIC, 67 bytes

TMREAD"00:"+T$OUT,H,M?H MOD 12+12*P,T$[3];T$[4]

Input: HH:MMa/p

Output: HH MM


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).

  • \$\begingroup\$ I really wanted to find a shorter way with lubridate, but the name of the package is too long (among other problems). \$\endgroup\$ – BLT May 4 '17 at 19:47

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


Pyke, 15 bytes


Try it here!


Mathematica, 33 bytes


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


JavaScript, 67 bytes


Input is like in the example

  • \$\begingroup\$ Does not work for 12:00 am or 12:00 pm \$\endgroup\$ – Herman L Nov 4 '17 at 16:30

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.


> c "1200p"
> c "1200a"

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

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


        (M (SUBSEQ X 2 4)))
            (+ (MOD H 12) (IF (FIND #\p X) 12 0))

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


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

pprint the function definition:

  (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)


(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))

Retina, 61 60 bytes



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!


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


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


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

For any other hour:


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


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.


Batch, 40 bytes

@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.)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.