Convert string to time
Ruby, 653 597 Bytes
P=/ past | to /;T=%w{q twen thirty fourty fifty sixty el twe thi fourte fifte sixt sevent eighte ninet o tw th fo fi si s e n t}.zip([15,*(2..6).map{|i|i*10},*11..19,*1..10]).to_h;D={'middnight'=&gt;0,'midday'=&gt;12,'noon'=&gt;12};n=-&gt;s{s.split('-').reduce(0){|p,v|(Array(T.find{|k,_|v.start_with? k}).last||0)+p}};i=-&gt;s{m=0;s=s.gsub(/^\s+|\s+$/,'');c=s.split(P);(c.reverse! if s.match(P));h=D[c[0]]||n.(c[0].gsub(/ o\'clock (A|P)m/,''));h+=(s.end_with?('PM') ? 12 : 0);m=n.(c[1]||c[0].split(' ')[1]) if c[1]||c[0].match(/^\w+ (?!o'clock)/);(m=60-m;h=(h-1)%24)if s.match(/ to /);(sprintf '%02d:%02d',h,m)}

Ungolfed:
P=/ past | to /
# configuration for translating english words to numbers
T=%w{q twen thirty fourty fifty sixty el twe thi fourte fifte sixt sevent eighte ninet o tw th fo fi si s e n t}.zip([15,*(2..6).map{|i|i*10},*11..19,*1..10]).to_h
D={'middnight'=&gt;0,'midday'=&gt;12,'noon'=&gt;12}

# proc for translating english word groups to a number
n=-&gt; s {
  s.split('-').reduce(0) { |p,v|
    (Array(T.find {|k,_| v.start_with? k}).last || 0) + p
  }
}

i=-&gt; s {
  m=0
  s=s.gsub(/^\s+|\s+$/,'')
  c=s.split(P)
  (c.reverse! if s.match(P))

  # set the hour
  h=D[c[0]]||n.(c[0].gsub(/ o\'clock (A|P)m/,''))
  h+=(s.end_with?('PM') ? 12 : 0)

  # set the minute
  m=n.(c[1]||c[0].split(' ')[1]) if c[1]||c[0].match(/^\w+ (?!o'clock)/)

  # adjust for 'past'
  (m=60-m;h=(h-1)%24)if s.match(/ to /)

  sprintf '%02d:%02d',h,m
}

Verification script used:
examples = &lt;&lt;EXAMPLES
midnight                                  -&gt;   00:00
midday                                    -&gt;   12:00
twelve o'clock                            -&gt;   12:00
quarter to midnight                       -&gt;   23:45
twenty-two minutes past eight o'clock PM  -&gt;   20:22
thirty-four minutes to fifteen o'clock    -&gt;   14:26
six o'clock AM                            -&gt;   06:00
one minute to twenty-one o'clock          -&gt;   20:59
seven thirteen AM                         -&gt;   07:13
nine fourteen PM                          -&gt;   21:14
EXAMPLES

examples.split(&quot;\n&quot;).each do |example|
  text, expected = example.split(/\s+-&gt;\s+/)
  r = i.(text)
  raise &quot;Unexpected result for \&quot;#{text}\&quot;. Got \&quot;#{r}\&quot;, expected \&quot;#{expected}\&quot;&quot; unless r == expected
  print &quot;.&quot;
end

Thank you to Kevin Lau for 47 bytes of optimization