[Question]
  [
I'm a time traveler, and I'm obsessed with the passage of time. I particularly love the moments when the clock hands pass 12, or when I get to flip to the next page of my calendar, or when everyone yells "Happy New Year!"
Please write for me a program to show me how far I am from the last such moment to the next, in the form of a progress bar. For example, if I tell it the time is 09:12, it should print this:
```
09:00 ####---------------- 10:00
```
If I tell it the month is May, 1982, it should print this:
```
1982-01 #######------------- 1983-01
```
Did I mention I'm a time traveler? I travel to anywhere from the first millisecond of 0 A.D. to the last millisecond of 9999 A.D., so the program needs to handle any date and time in that range.
# Input
* Input will be in one of the following formats:
	+ `YYYY-MM-DDThh:mm:ss.sss`
	+ `YYYY-MM-DDThh:mm:ss`
	+ `YYYY-MM-DDThh:mm`
	+ `YYYY-MM-DDThh`
	+ `YYYY-MM-DD`
	+ `YYYY-MM`These are the only formats that need be handled. Each part will have exactly the number of digits shown, which means fractional seconds may have trailing zeroes (e.g. `.120`, never `.12`). The `T` is a literal letter "T" delimiting the date from the time. Hours are on a 24-hour clock.
* Months and days are 1-based (more on this below).
* Invalid and out-of-range inputs need not be handled.
* At the programmer's discretion, input may have a single trailing newline.
# Progress bar math
The program is concerned with the least- and second-least-significant units in the given input. For example, if the input has day-level precision (e.g. `2016-12-14`), the progress bar will indicate what proportion of the days in the input month have elapsed versus what remains.
The progress bar will have 20 units (characters) and the proportion represented will be rounded to the nearest increment of 1⁄20. For example, given `2016-12-14T12:28`, the progress bar will show **Round(28⁄60 × 20) = 9** of 20 units "filled."
### 1-based months and days
Although the day of December 1 (for example) is `01` in `2016-12-01`, for the purpose of calculation it is the 0th day of the month, because the truncated units imply the 0th millisecond of the 0th minute of the 0th hour of the day. In other words, `2016-12-01` is 0⁄31 of the way through December and `2016-12-02` is 1⁄31, and so on.
Likewise, `2016-01` is the 0th millisecond of the 0th day of January, so in calculations it is 0⁄12, which means `2016-12` is 11⁄12.
Yes, that means months and days will never completely fill the progress bar.
### Differing month durations and leap years
Different months have different numbers of days and the output must reflect this—including leap years. The progress bar for February 6, 2017 will be different from the progress bar for February 6, 2016 (or January 6 of both years).
### Miscellaneous
* Time travelers use the [proleptic Gregorian calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar). TL;DR: No special cases like [missing days in 1752](http://mentalfloss.com/article/51370/why-our-calendars-skipped-11-days-1752). Input will include dates in the year 0 A.D.
* Time travelers ignore daylight savings.
* The program is not required to account for leap seconds, but it may.
# Output
The program (or function) must print (or return as a string) a horizontally-oriented 20-character progress bar that is "filled in" for time that has elapsed and "open" for time that remains. It must "fill in" from left to right.
The progress bar must have a label to its left showing the beginning of the period being counted and another to its right showing the beginning of the next period, in the same format as the input (but showing only two units of precision). For our example `2016-12-14` valid output would be:
```
12-01 #########----------- 01-01
```
Here are the valid label formats for each of the possible periods:
* Months: `YYYY-MM`
* Days: `MM-DD`
* Hours: `DDThh`
* Minutes: `hh:mm`
* Seconds: `mm:ss`
* Milliseconds: `ss.sss`
No additional units may be included in the labels, and none may be omitted.
### Output notes
* The progress bar's "filled in" units will be represented by a `#` character. "Open" units will be represented by `-`.
* There must be exactly one space between the progress bar and each label.
* Leading or trailing spaces and/or a single trailing newline are allowed.
# Winning
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"). Shortest code in bytes wins. Standard rules apply. Standard loopholes forbidden.
# Examples
```
Input                      Output
-----------------------    -------------------------------------
2016-12-12T12:17           12:00 ######-------------- 13:00
2016-12-12                 12-01 #######------------- 01-01
0000-01-01T00:00:00.000    00.000 -------------------- 01.000
0000-01-01T00:00           00:00 -------------------- 01:00
1899-12-31T23              31T00 ###################- 01T00
1899-12-31                 12-01 ###################- 01-01
1899-12                    1899-01 ##################-- 1900-01
1982-05-15T17:15           17:00 #####--------------- 18:00
1982-05-15T17              15T00 ##############------ 16T00
1982-05                    1982-01 #######------------- 1983-01
9999-12-31T23:59:59.999    59.000 #################### 00.000
9999-12                    9999-01 ##################-- 10000-01
2000-01-06                 01-01 ###----------------- 02-01
2000-02-06                 02-01 ###----------------- 03-01
2001-02-06                 02-01 ####---------------- 03-01
1742-09-10                 09-01 ######-------------- 10-01
```
  
[Answer]
# JavaScript, 282 bytes
```
(x,v=x.split(/\D/g),l=v.length-2,[a,b,c,d]=("10e5,01,-,12,01,-,"+new Date(v[0],v[1],0).getDate()+",00,T,24,00,:,60,00,:,60,000,.,1000").split`,`.slice(l*3,l*3+4),t=(v[l+1]-b)/d*20+.5|0,n=v[l],o=((n|0)+1)%a,r=l?('0'+o).slice(-2):o)=>n+c+b+' '+'#'.repeat(t)+'-'.repeat(20-t)+' '+r+c+b
```
Passes all the tests
```
(
x,
v=x.split(/\D/g),
l=v.length-2,
[a,b,c,d]=("10e5,01,-,12,01,-,"+new Date(v[0],v[1],0).getDate()+",00,T,24,00,:,60,00,:,60,000,.,1000").split`,`.slice(l*3,l*3+4),
t=(v[l+1]-b)/d*20+.5|0,
n=v[l],
o=((n|0)+1)%a,
r=l?('0'+o).slice(-2):o
) =>n+c+b+' '+'#'.repeat(t)+'-'.repeat(20-t)+' '+r+c+b
```
Test function prints nothing for pass, values for fail.
```
function test(value,expected){
    if (f(value)!=expected)
    {
        console.log(value);
        console.log(f(value));
        console.log(expected);
     }
}
```
The test cases:
```
test('2016-12-12T12:17','12:00 ######-------------- 13:00')                 ;
test('2016-12-12','12-01 #######------------- 01-01')                       ;
test('0000-01-01T00:00:00.000','00.000 -------------------- 01.000')        ;
test('0000-01-01T00:00','00:00 -------------------- 01:00')                 ;
test('1899-12-31T23','31T00 ###################- 01T00')                    ;
test('1899-12-31','12-01 ###################- 01-01')                       ;
test('1899-12','1899-01 ##################-- 1900-01')                      ;
test('1982-05-15T17:15','17:00 #####--------------- 18:00')                 ;
test('1982-05-15T17','15T00 ##############------ 16T00')                    ;
test('1982-05','1982-01 #######------------- 1983-01')                      ;
test('9999-12-31T23:59:59.999','59.000 #################### 00.000')        ;
test('9999-12','9999-01 ##################-- 10000-01')                     ;
test('2000-01-06','01-01 ###----------------- 02-01')                       ;
test('2000-02-06','02-01 ###----------------- 03-01')                       ;
test('2001-02-06','02-01 ####---------------- 03-01')                       ;
test('1742-09-10','09-01 ######-------------- 10-01')                       ;
```
[Answer]
# Pyth, 213 bytes
My first code in pyth! Behold:
```
+%h=N:[d"%.4d"\-=Z"%.2d"\-Z\TZ\:Z\:Z\."%.3d")-*2lKr:w"[-T:.]"d7 3*2lKJ@K_2+@N1+%eN=b<lK4+d+*\#=Gs+*20c-eKb@=H[0^9T12?q2=k@K1+28+q0%=YhK4-q0%Y400q0%Y100+30%+k/k8 2 24 60 60 999)lK.5+*\--20G+d+%hN%+J1@H-lK1+@N1%eNb
```
My pyth code is closely based off of my previous python answer. Here is the ungolfed version with comments:
```
"K is the input, as a list of numbers"
Kr:w"[-T:.]"d7
"Y=year"
=YhK
"k=month"
=k@K1
"H = a list of denominators"
=H[0 ^9T 12 ?q2k+28+q0%Y4-q0%Y400q0%Y100 +30%+k/k8 2 24 60 60 999)
"J is the second-to-last number of the input"
J@K_2
"b is the +1 starting point for months and days"
=b<lK4
"G is the number of hashtags in the statusbar"
=Gs+*[[email protected]](/cdn-cgi/l/email-protection)
"N is the formatted string"
=N:[d"%.4d"\-=Z"%.2d"\-Z\TZ\:Z\:Z\."%.3d")-*2lK3 *2lK
+%hNJ+@N1+%eNb+d+*\#G+*\--20G+d+%hN%+J1@H-lK1+@N1%eNb
```
Testing multiple values is easily accomplished by making the code loop, and adding a newline print to the end:
```
Wp+%h=N:[d"%.4d"\-=Z"%.2d"\-Z\TZ\:Z\:Z\."%.3d")-*2lKr:w"[-T:.]"d7 3*2lKJ@K_2+@N1+%eN=b<lK4+d+*\#=Gs+*20c-eKb@=H[0^9T12?q2=k@K1+28+q0%=YhK4-q0%Y400q0%Y100+30%+k/k8 2 24 60 60 999)lK.5+*\--20G+d+%hN%+J1@H-lK1+@N1+%eNb"\n"
```
Then I ran `cat testinput | pyth code.pyth > output` and `diff output testoutput` Or [try it online](https://pyth.herokuapp.com/).
[Answer]
# Python 2, 371 bytes
This challenge was surprisingly difficult! It seemed like I was going to be just under 300 until I worked out the output string formatting.
The kind of cool part is that my answer does not use any date package:
```
import re
s=raw_input()
S=[int(i)for i in re.sub('[-T:.]',' ',s).split()]
l=len(S)
y,m=S[:2]
d=[0,20<<9,12,28+(y%4==0!=y%100)+(y%400==0)if m==2else 30+(m+m/8)%2,24,60,60,999]
a,n=S[-2:]
b=1-(1if l>3else 0)
h=int(20.*(n-b)/d[l]+.5)
x,y,z='- %.4d - %.2d - %.2d T %.2d : %.2d : %.2d . %.3d'.split()[l*2-3:l*2]
print x%a+y+z%b+' '+'#'*h+'-'*(20-h)+' '+x%((a+1)%d[l-1])+y+z%b
```
]