Сколько недель?

13

Ваша задача - вывести одно число; количество недель ISO, в которые пересекается данный диапазон дат. Процитирую Википедию:, An average year is exactly 52.1775 weeks longно это не о среднем.

Ввод состоит из двух разделенных пробелами дат ISO:

0047-12-24 2013-06-01

Дата окончания никогда не предшествует дате начала. Мы будем использовать экстраполированный григорианский календарь для простоты.

Тестовые случаи:

Format: input -> output
2015-12-31 2016-01-01 -> 1    (both are within week 53 of 2015)
2016-01-03 2016-01-04 -> 2    (the 3rd is within week 53, and the 4th is in week 1)
2015-12-24 2015-12-24 -> 1    (this single day is of course within a single week)

Ваше решение должно обрабатывать даты между 0001-01-01и 9999-12-31.

Филип Хаглунд
источник
2
Может ли ввод быть массивом строк вместо одной строки, разделенной пробелом? Или же две даты могут быть двумя аргументами функции?
Дверная ручка
Я полагаю, вы имеете в виду Григорианский календарь Proleptic .
Брэд Гилберт b2gills
Кроме того, недели начинаются в воскресенье или понедельник? Согласно вашему второму тестовому случаю, это понедельник, но я просто уверен.
Дверная ручка
@Doorknob quote Цитата из Википедии: «Дата указывается в году нумерации недели ISO в формате YYYY, номер недели в формате ww с префиксом буквы« W », а номер дня недели - цифрой d от 1 до 7 начиная с понедельника и заканчивая воскресеньем "Итак, начиная с понедельника согласно ISO 8601
Tensibai
2
Согласно стандарту ISO, Weeks start with Monday.
Филип Хаглунд

Ответы:

2

Рубин, 89 88 86 байт

->s{a,b=s.split.map{|x|Time.gm *x.split(?-)}
n=1
(a+=86400).wday==1&&n+=1until a==b
n}

Очень примитивное решение: учитывая первую дату aи вторую дату b, приращение a, проверьте, не понедельник ли это (если так, мы «перенесли» на новую неделю), и остановитесь один раз a,b .

Принимает данные в точном формате, указанном в вопросе: одна строка через пробел. (То, как он анализирует входные данные, является причудливым: он использует оператор "splat" в Ruby *. Этот оператор "расширяет" массив или перечисляет его, поэтому Time.gm *[2013, 06, 01]становится Time.gm 2013, 06, 01.)

Импортировано из комментария обсуждения:

Нас не волнуют "недели в году"; мы заботимся только о «неделях в целом». Так что, имеет ли год 52 или 53 недели, не имеет значения.

Просто чтобы избежать путаницы в будущем с правильной обработкой границ года - согласно Википедии , все недели всегда начинаются в понедельник и заканчиваются в воскресенье.

Для некоторых более причудливых уловок все они эквивалентны:

until a==b;a+=86400;n+=a.wday==1?1:0;end
[a+=86400,n+=a.wday==1?1:0]until a==b
n+=(a+=86400).wday==1?1:0 until a==b
(a+=86400).wday==1&&n+=1 until a==b
(a+=86400).wday==1&&n+=1until a==b
Дверная ручка
источник
Не можете ли вы сохранить 1 символ, заменяя a==bна a<b?
Тенсибай
1

VBA, 125 байт

Ожидается 2 входа функции в виде строк

Function u(k,j)
f=DateValue(k)
For i=0 To (DateValue(j)-f)
q=DatePart("ww",f+i,2,2)
If q<>j Then u=u+1
j=q
Next
End Function

Уверен, это можно сыграть в гольф. Это происходит циклически, хотя каждый день между двумя датами и увеличивает счетчик каждый раз, когда изменяется дата ISO.

DatePart("ww",f+i,2,2)это номер недели ISO в VBA, означает первые 2 Monday (complies with ISO standard 8601, section 3.17). тогда второе 2 означаетWeek that has at least four days in the new year (complies with ISO standard 8601, section 3.17)

140 байт с одним входом

Function g(k)
y=Split(k)
f=DateValue(y(0))
For i=0 To (DateValue(y(1))-f)
q=DatePart("ww",f+i,2,2)
If q<>j Then g=g+1
j=q
Next
End Function
JimmyJazzx
источник
1

R, 76 байт

d=as.Date(scan("","raw"));sum(strftime(seq(d[1],d[2],"day")[-1],"%w")==1)+1

После разговора с @Doorknob это, наконец, так же просто, как считать понедельники.

seq Позволяет создать вектор дат (каждого дня между двумя датами) и преобразовать strftime в «номер дня в неделе», теперь считает количество раз, равное 1, чтобы получить количество раз, которое вы изменили неделю, и добавить 1 к принять во внимание предыдущую неделю.

Другой подход зацикливания:

R 85 байт

n=1;d=as.Date(scan("","raw"));z=d[1];while(z<d[2]){n=n+(strftime(z<-z+1,"%w")==1)};n
Tensibai
источник
1
Что касается вашего второго подхода, вы должны только добавить 1 к общему количеству понедельников, если первая дата не выпадает на понедельник.
DavidC
@DavidCarraher Спасибо, чтение вашего ответа заставило меня думать, что я могу убрать первый день диапазона, таким образом,
решив
0

Mathematica 135 79 96 84 74 байта

В соответствии с предложением @ Doorknob, это

  • генерирует все даты в диапазоне

  • считает количество понедельников ( ISOWeekDay== "1") в DateRange(исключая d), и

  • добавляет 1к общему.


Count[DateString[#,"ISOWeekDay"]&/@Rest@(DateRange@@StringSplit@#),"1"]+1&

Count[DateString[#,"ISOWeekDay"]&/@Rest@(DateRange@@StringSplit@#),"1"]+1&
/@ {"2015-12-31 2016-01-01", "2016-01-04 2016-01-05","2016-01-03 2016-01-04", 
"2015-12-24 2015-12-24", "1876-12-24 2016-01-01"}

{1, 1, 2, 1, 7255}

DavidC
источник