Stepping Through Time

JavaScript (ES7),  136  132 bytes

Takes a single integer as input and returns a string.

s=>(V=g=(d,t=s,k=0)=>k>V?R:[...S=([1e3]+t).slice(-4)].some(p=c=>(p-(p=c))**2-1)?g(d,t=(t-~d)%2400,k+=t%100<60):(V=k,R=S))()&&g(2398)

Try it online!

How?

The only valid hour prefixes are 01, 10, 12, 21 and 23. It means that any invalid minute count starting with a digit greater than 5 will be rejected by the test on the absolute difference between two consecutive digits.

So there's no need to explicitly handle the wrapping of minutes modulo 60. Instead, we can just make sure that the distance k is not incremented on invalid minutes:

k += t % 100 < 60

JavaScript (Node.js),  148  146 bytes

Takes a single integer as input and returns a string.

This version picks the answer from a hardcoded table.

t=>0x60553BCD48A3CE4F56D818FDC473FC726398E907D3A9n.toString(6).substr([22,85,9,423,462,x=98,x,9,9,413,461,9,x,x,9,9].findIndex(d=>(t-=d+2)<0)*4,4)

Try it online!

How?

Once converted to base-6, the integer 0x60553BCD48A3CE4F56D818FDC473FC726398E907D3A9n is turned into the following string, which holds all possible valid answers:

"23450101012101231010101212101212123212342101212121232321232323432345"

The correct answer is selected according to the interval in which the input time falls:

 answer | input interval
--------+----------------
 "2345" | 00:00 - 00:23
 "0101" | 00:24 - 01:10
 "0121" | 01:11 - 01:21
 "0123" | 01:22 - 05:46
 "1010" | 05:47 - 10:10
 "1012" | 10:11 - 11:10
 "1210" | 11:11 - 12:10
 "1212" | 12:11 - 12:21
 "1232" | 12:22 - 12:32
 "1234" | 12:33 - 16:47
 "2101" | 16:48 - 21:10
 "2121" | 21:11 - 21:21
 "2123" | 21:22 - 22:21
 "2321" | 22:22 - 23:21
 "2323" | 23:22 - 23:32
 "2343" | 23:33 - 23:43
 "2345" | 23:44 - 23:59

The lengths of the intervals in minutes (minus 2) are stored in an array.


Python 2, 136 138 133 126 125 122 151 124 108 106 103 101 bytes

f=lambda h,m,i=0:(h,m)*all(j%11%9==1for j in(h,m/10-h%10,m))or f((h+(m+i)/60)%24,(m+i)%60,~i+2*(i<1))

Try it online!

Input is hour,minute parameters result is (hour,minute) tuple

Using recursion

i moves through [0,-1,+2,-3,+4,...] the sum of the initial terms therefore moves through [0,-1,1,-2,2,...]

(h,m) are offset by i minutes moving alternately through nearest above and below time not yet checked.

Check for result by considering h, m and h%10*10+m/10, which is low hour digit and top minute digit.

To check two digit number n in form d (d+1) or (d+1) d, observe n%11 is either 1 or 10 in exactly these cases, and checking for 1 or 10 using %9==1. i.e. n%11%9==1

As this two digit test reduces modulo 11, h%10*10+m/10 is equivalently m/10-h%10.

Previous approach:

def f(h,m,i=0):t=m+i;s='%02d'*2%((h+t/60)%24,t%60);return s*all(a+b in'4321012345'for a,b in zip(s,s[1:]))or f(h,m,-i+(i<1))

Try it online!

Input in integer output is 4 character string.

Formats number as string, taking pairs checks against string table, otherwise recurse with alternating offsets (i=0,1,-1,2,-2,...)

Originally:

Offsets n by [0,1,-1,2,-2,...], formats as four digit string, then taking pairs of characters checks they differ by one by looking up as substring in compressed string table.

+2 bytes Fixed by adding '43' to table.

-5 bytes Removed unnecessary +2400, which was to avoid mod of negative number -- Python's % works properly in that case.

-7 bytes string table improved, and by using / instead of // due to Surculose Sputum.

-1 byte reduce range of search.

-3 bytes Surculose Sputum: remove unecessary [] in all() and compress expression i%2*2-1 to i%-2|1.

+29 bytes code was broken, added correction term for wrapping minutes (n%100+i)/60*40

-27 bytes Surculose Sputum: rewritten using recursion

-16 bytes reworked using new approach

-2 bytes remove introduced variable which was false saving.

-3 bytes simplification for middle digits test.

-2 bytes Surculose Sputum: using lambda instead of def


Python 2, 142 bytes

lambda*t:'%02d'*2%max(g(-720,*t))[1:]
g=lambda w,h,m,t=10:w/720*[0]or[(w*w,h,m)]*({h/t-h%t,h%t-m/t,m/t-m%t}<={1,-1})+g(w+1,(h+m/59)%24,-~m%60)

Try it online!

without the strict output:

Python 2, 160 148 144 138 133 bytes

-6 11 bytes thanks to Surculose Sputum!

Input and output is hours, minutes.

lambda*t:max(g(-720,*t))[1:]
g=lambda w,h,m,t=10:w/720*[0]or[(w*w,h,m)]*({h/t-h%t,h%t-m/t,m/t-m%t}<={1,-1})+g(w+1,(h+m/59)%24,-~m%60)

Try it online!