A Fractional Year
JavaScript (ES6), 84 bytes
f=
s=>(Date.parse(1970+s.slice(4).replace(/ /,'T')+'Z')/31536e6+parseInt(s)).toFixed(5)
;
<input placeholder=Input oninput=o.value=f(this.value)><input placeholder=Output id=o>
Assuming no leap years or DST are required, I replace the year with 1970 which makes Date.parse
directly return the time offset in milliseconds, of which there were 31536000000
in 1970 (or indeed any other non-leap year). All I need do then is to add back the year and round to 5 decimal places. Edit: Bidirectional conversion in 183 178 bytes:
f=
s=>/:/.test(s,m=31536e6)?(Date.parse(1970+s.slice(4).replace(/ /,'T')+'Z')/m+parseInt(s)).toFixed(5):s.slice(0,4)+new Date(s.slice(4)*m+3e4).toJSON().slice(4,16).replace(/T/,' ')
;
<input placeholder=Input oninput=o.value=f(this.value)><input placeholder=Output id=o>
Assumes strings containing a :
are time format, handled as above, otherwise strips off the year, converts to milliseconds, adds half a minute for rounding purposes, converts to a date in 1970, extracts the month, day, hour and minute, and prefixes the original year.
Matlab, 132 115 bytes
d=input('');m=cumsum([-1 '# #"#"##"#"'-4]);year(d)+fix((((m(month(d))+day(d))*24+hour(d))*60+minute(d))/5.256)/10^5
Rounds towards 0.
Hmmm... That's quite long.
That's using some builtins, but not the really helpful ones - because of leap years.
Parsing the string directly gives 2 more byte solution:
d=sscanf(input(''),'%d%[- :]');m=cumsum([-1 '# #"#"##"#"'-4]);d(1)+fix((((m(d(3))+d(5))*24+d(7))*60+d(9))/5.256)/10^5
Newer Matlab versions probably have some better split function, but I'm running on 2012a.
Some bytes saved thanks to @Luis Mendo