Ми тоді ще?


22

Я мандрівник у часі, і я одержимий плином часу. Я особливо люблю моменти, коли руки годинника проходять 12, або коли я перехожу на наступну сторінку свого календаря, або коли всі кричать "З Новим роком!"

Будь ласка, напишіть для мене програму, яка покаже мені, наскільки я далеко від останнього такого моменту до наступного, у вигляді смужки прогресу. Наприклад, якщо я скажу, що це час 09:12, він повинен надрукувати це:

09:00 ####---------------- 10:00

Якщо я скажу, що місяць - травень 1982 року, він повинен надрукувати це:

1982-01 #######------------- 1983-01

Я згадав, що я мандрівник у часі? Я подорожую куди завгодно: від першої мілісекунди 0 н.е. до останньої мілісекунди 9999 р. Н.е., тому програмі потрібно обробляти будь-яку дату і час у цьому діапазоні.

Вхідні дані

  • Введення буде в одному з таких форматів:

    • YYYY-MM-DDThh:mm:ss.sss
    • YYYY-MM-DDThh:mm:ss
    • YYYY-MM-DDThh:mm
    • YYYY-MM-DDThh
    • YYYY-MM-DD
    • YYYY-MM

    Це єдині формати, з якими потрібно оброблятись. Кожна частина матиме рівно кількість показаних цифр, а це означає, що дробові секунди можуть мати нульові нулі (наприклад .120, ніколи .12). Це Tбуквальна літера "T", що відрізняє дату від часу. Години працюють цілодобово.

  • Місяці та дні базуються на 1 (детальніше про це нижче).

  • Неправильні та вихідні входи не повинні оброблятися.

  • На розсуд програміста, вхід може мати один зворотний новий рядок.

Барна математика прогресу

Програма стосується найменш та другого найменш значущих одиниць у даному вході. Наприклад, якщо вхід має точну добу (наприклад 2016-12-14), у рядку прогресу буде вказано, яка частка днів у вхідному місяці минула проти того, що залишилося.

У рядку прогресу буде 20 одиниць (символів), а представлена ​​пропорція буде округлена до найближчого збільшення 120 . Наприклад, якщо вказано 2016-12-14T12:28, на панелі прогресу буде показано раунд ( 2860 × 20) = 9 із 20 одиниць, "заповнених".

Місяці та дні на основі 1

Хоча день 1 грудня (наприклад) знаходиться 01в 2016-12-01, з метою розрахунку є 0 - й день місяця, тому що укорочені блоки означають 0 - й мілісекнду 0 - й хвилині 0 - а година дня. Іншими словами, 2016-12-01це 031 шляху до грудня і 2016-12-02становить 131 , і так далі.

Аналогічно, 2016-01це 0-а мілісекунда 0-го січня, тому в обчисленнях це 012 , а значить 2016-12, 1112 .

Так, це означає, що місяці та дні ніколи повністю не заповнять планку прогресу.

Різні тривалість місяця та високосні роки

Різні місяці мають різну кількість днів, і результат повинен відображати це, включаючи високосні роки. Рядок прогресу на 6 лютого 2017 року буде відрізнятися від рядка прогресу для 6 лютого 2016 року (або 6 січня обох років).

Різне

  • Мандрівники в часі використовують пролептичний григоріанський календар . TL; DR: Ніяких особливих випадків, як пропущені дні 1752 року . Вхідні дані включатимуть дати у році 0 н.е.
  • Мандрівники часу ігнорують економію денного світла.
  • Програмі не потрібно враховувати високосні секунди, але це може бути.

Вихідні дані

Програма (або функція) повинна надрукувати (або повернути як рядок) горизонтально орієнтовану 20-символьну смугу прогресу, яка "заповнюється" на час, що минув, і "відкрився" на час, що залишився. Він повинен "заповнюватися" зліва направо.

На панелі прогресу повинна бути мітка ліворуч із зазначенням початку відліченого періоду, а інша справа - із початком наступного періоду у тому ж форматі, що і введення (але показує лише дві одиниці точності). Для нашого прикладу 2016-12-14допустимим результатом буде:

12-01 #########----------- 01-01

Ось дійсні формати міток для кожного з можливих періодів:

  • Місяці: YYYY-MM
  • Дні: MM-DD
  • Години роботи: DDThh
  • Хвилини: hh:mm
  • Секунди: mm:ss
  • Мільсекунд: ss.sss

Ніякі додаткові одиниці не можуть бути включені до міток, і жодна не може бути опущена.

Вихідні примітки

  • "Заповнені" одиниці смуги прогресу будуть представлені #символом. "Відкриті" підрозділи будуть представлені -.
  • Між смужкою прогресу та кожною міткою має бути рівно один пробіл.
  • Доступні провідні чи кінцеві проміжки та / або одна провідна нова лінія.

Перемога

Це . Виграє найкоротший код у байтах. Діють стандартні правила. Стандартні лазівки заборонені.

Приклади

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

4
Чи потрібно турбуватися про високосні секунди?
Райлі

@Riley Добре запитання. №
Йорданія

2
Я припускаю, що літній режим ігнорується, оскільки немає жодної стандартизованої форми?
CAD97

3
@ CAD97 Добре запитання. Ви праві. DST дійсно ускладнює речі для подорожуючих часом, тому ми ігноруємо це.
Йорданія

Приклад "1899-12-31T23" недійсний відповідно до поданого списку вхідних форматів, той самий для "1982-05-15T17". Перевірте свої тестові дані.
zeppelin

Відповіді:


4

JavaScript, 282 байти

(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

Проходить усі тести

(
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

Тестова функція нічого не друкує за пропуск, значення для відмови.

function test(value,expected){
    if (f(value)!=expected)
    {
        console.log(value);
        console.log(f(value));
        console.log(expected);
     }
}

Тестові приклади:

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

2
Мені довелося вивчити нову мову, щоб оформити цю версію ... це дуже стисло!
rexroni

3

Pyth, 213 байт

Мій перший код у pyth! Ось:

+%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

Мій pyth-код тісно базується на моїй попередній відповіді python. Ось неперевершена версія з коментарями:

"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+*20c-eKb@HlK.5
"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

Тестування декількох значень легко здійснити шляхом створення циклу коду та додавання друку нового рядка до кінця:

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"

Тоді я побіг cat testinput | pyth code.pyth > outputі diff output testoutput Або спробуйте в Інтернеті .


2

Пітон 2, 371 байт

Цей виклик був напрочуд складним! Здавалося, мені буде трохи менше 300, поки я не опрацював форматування вихідних рядків.

Класна частина полягає в тому, що моя відповідь не використовує жодного пакета дат:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.