День недели следующего 29 февраля

14

Напишите функцию, которая принимает дату и возвращает день недели следующего 29 февраля после этой даты.

  • Входные данные представляют собой строку в расширенном формате ISO: YYYY-MM-DD (например, 27 мая 2010 г. будет «2010-05-27»).

  • Выводом является строка, которая является названием дня недели (например, «Понедельник»). Капитализация не имеет значения, но дайте полное имя на английском языке.

  • Если указанная дата 29 февраля, верните день недели следующего 29 февраля.

  • Используйте расчеты для Proleptic Gregorian Calendar (таким образом, он использует расчеты григорианского високосного года для всей его длины). Не беспокойтесь о юлианском календаре или о том, когда произошел переход с юлианского на григорианский. Просто примите Григорианский для всего.

  • Функция должна работать как минимум в диапазоне «0001-01-01» - «2100-01-01».

  • Не стесняйтесь использовать любые стандартные библиотеки, которые предоставляет выбранный вами язык, но не используйте сторонние библиотеки, если вы не хотите включать этот код в свое решение.

  • Самый короткий код (наименьшее количество символов) выигрывает.

Примеры:

  • func("0001-01-01") -> "Sunday"
  • func("1899-12-03") -> "Monday"
  • func("1970-01-01") -> "Tuesday"
  • func("1999-07-06") -> "Tuesday"
  • func("2003-05-22") -> "Sunday"
  • func("2011-02-17") -> "Wednesday"
  • func("2100-01-01") -> "Friday"

(и нет, вам не нужно называть функцию func)

подсказки:

  • Помните, что годы, заканчивающиеся на 00, которые не делятся на 400, не являются високосными.
  • 1 января 0001 - понедельник.
Джонатан М Дэвис
источник

Ответы:

7

Windows PowerShell, 65

Довольно просто.

filter f{for($d=date $_;($d+='1').day*$d.month-58){}$d.dayofweek}

Как обычно, мы можем сбрить два байта, если готовы долго ждать до завершения:

filter f{for($d=date $_;($d+=9).day*$d.month-58){}$d.dayofweek}

Тестовое задание:

> '0001-01-01','1899-12-03','1970-01-01','1999-07-06','2003-05-22','2011-02-17','2100-01-01'|f
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

История:

  • 2011-02-18 00:06 (65) Первая попытка.
детеныш
источник
Какой путь необходим для этого? У меня есть дата GnuWin на моем пути, которая нарушает ее.
Питер Тейлор
@Peter: Это может конфликтовать с date. Просто удалите GNUWin32 из PATH, и он должен работать. Или измените dateна Get-Date(такой резервный режим работает только тогда, когда команда не найдена - для проверки, просто используйте gcm date). В любом случае, я не считаю, что конкретная проблема с этим скриптом, поскольку GNUWin32 не является частью какой-либо стандартной установки Windows.
Джои
Причина, по которой я спросил, состояла в том, что я уже пытался использовать get-dateи получил сообщение об ошибке. Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.Нужна ли ему PS2 или .Net 4 или что-то еще?
Питер Тейлор
@Peter: я пробовал PowerShell v2. .NET 4 не играет в этом, так как PowerShell связан со средой выполнения 2.0. В любом случае, не должно быть PSObject, возвращающегося из Get-Datea System.DateTime.
Джои
Это очень странно. $d=Get-Date "0400-01-01"; $d++выдает сообщение об ошибке ++не быть определенным в DateTime. То же самое при замене ++на +=1или +="1"или +='1'выдает сообщение об ошибке PSObject. И просто +"1"работает.
Питер Тейлор
5

Ruby 1.9, 85 символов

f=->a{require"date";d=Date.parse(a,0,0)+1;d+=1until d.day*d.month==58;d.strftime"%A"}

Простое решение. Вызовите функцию с помощью f[args].

  • Изменить: (87 -> 97) Исправлен 0001-01-01тестовый случай.
  • Edit 2: (97 -> 91) Date.parse позволяет также указать дату календарной реформы.
  • Правка 3: (91 -> 87) Используйте лямбду вместо функции. Спасибо Догберт !
  • Изменить 4: (87 -> 85) Удалите ненужные пробелы. Еще раз спасибо, Догберт !
Ventero
источник
4
Сбой теста для "0001-01-01". Дата Руби слишком сильна, она учитывает юлианские даты.
Steenslag
@Ventero Что делает def *? Никогда раньше не видел.
Steenslag
@steenslag: Спасибо, исправил этот тест. def*просто определяет вызываемую функцию *. Таким образом, мне не нужен пробел между defименем функции.
Вентеро
1
Не могли бы вы просто определить лямбда? a = -> {...}
Догберт
1
Кроме того, после strftime не требуется никакого пространства.
Догберт
3

T-SQL 166 185 символов

CREATE PROCEDURE f29 (@d DATETIME) AS
DECLARE @i int
SET @i=YEAR(DATEADD(M,-2,@d)+3)
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')

Я уже возился с функциями даты T-SQL, поэтому решил, почему нет ...

Исходное решение было неверным ...

Вот что я на самом деле должен сделать, чтобы эта стратегия заработала:

CREATE PROCEDURE f29 (@d DATE) AS
DECLARE @i int
SET @i = YEAR(@d)
BEGIN TRY 
SET @i=YEAR(DATEADD(D, 3, DATEADD(M,-2,@d)))
END TRY
BEGIN CATCH
END CATCH
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')
mootinator
источник
Учитывая, что я создаю переполнение, вычитающее 2 месяца из 0001-01-01, даже если я использую правильный тип данных, я разочаровываюсь в создании чего-то короткого и правильного для этого вопроса. O_o. Триксси спрашивает.
mootinator
Мне нравится видеть эти решения T-SQL. :)
Стив
3

C #, 176

Func<String,String>f=(d)=>{DateTime n;for(n=DateTime.Parse(d).AddDays(307);!(DateTime.IsLeapYear(n.Year));n=n.AddYears(1)){}return new DateTime(n.Year,2,29).ToString("dddd");};
Крис Иванов
источник
Вы можете сохранить 8 байтов, используя обычное определение функции:string f(string d){...}
Joey
.ToString("dddd")печатает дату в текущей локали, но не на английском.
Джои
165 символов => строка f (строка d) {var n = DateTime.Parse (d) .AddDays (307); while (! (DateTime.IsLeapYear (n.Year))) n = n.AddYears (1); return (новый DateTime (n.Year, 2,29)). DayOfWeek.ToString ();}
Стефан Шинкель
Далее улучшено до 127 персонажей:string f(string d){var n=DateTime.Parse(d).AddDays(1);return DateTime.IsLeapYear(n.Year)&&n.DayOfYear==60?n.DayOfWeek+"":f(n+"");}
Патрик Вестерлунд
3

Баш, 96 байт

Спасибо, Питер ... Отличная версия для гольфа, 96 байт:

i=1;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
date -d "${1} ${i} days" +%A

Старая версия, 229 байт

#!/bin/bash
from=$1
i=1
while [ "$isFeb" = "" ] || [ "$is29" = "" ]
do
isFeb=`date -d "${from} ${i} days" | grep Feb`
is29=`date -d "${from} ${i} days" +%Y-%m-%d | grep "\-29"`
((i++))
done
((i--))
date -d "${from} ${i} days" +%A

ОБРАЗЕЦ I / O

:~/aman>./29Feb.sh 0001-01-01
Sunday
:~/aman>./29Feb.sh 1899-12-03
Monday
:~/aman>./29Feb.sh 1970-01-01
Tuesday
Аман ЗееК Верма
источник
возможно, придется установить TZ, если часовой пояс по умолчанию не установлен, я узнал cyberciti.biz/faq/… пока делал это в какой-то онлайн-среде IDE
Aman ZeeK Verma
1
Вы собираетесь в гольф это? ; p Вы можете заменить все до финальной строкиi=0;d=;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
Питер Тейлор
:-), как мы уже обсуждали о моей необработанности, связанной с bash! ... По какой-то причине я не слишком треплюсь с bash ... они так подвержены ошибкам! .. Спасибо за ваше предложение ... обновлено!
Aman ZeeK Verma
1
Грубость с bash не оправдывает использование четырехбуквенных имен переменных: P
Питер Тейлор
да, сэр, я вас понял.
Aman ZeeK Verma
2

Perl, без библиотеки дат: 160 159 155

sub f {($ y, $ m) = split / - /, @ _ ​​[0], 2; $ y ++ if ($ m> '02 -28 '); $ y = ($ y + 3)% 400 >> 2; $ у + = $ у && ($ у% 25); @ г = (вт, Wednes, ЧГ, Пт, Сб, Вс, Пн) @ г [(5 * $ у - ($ г / 25 & 3))% 7] "день";.}

Реальная выгода от этих библиотек дат состоит в том, чтобы оттолкнуть длину названий дней кому-то еще.

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

Питер Тейлор
источник
2

ДАТА и немного КРАСИВОГО клея (90)

Функция:

f(){ while :;do $(date -d$1+1day +'set - %F %A 1%m%d');(($3==10229))&&break;done;echo $2;}

Тестирование:

$ for x in 0001-01-01 1899-12-03 1970-01-01 1999-07-06 2003-05-22 2011-02-17 2100-01-01 ; do f $x ; done
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

источник
1

D: 175 символов

S f(S)(S s){auto d=Date.fromISOExtString(s)+days(1);while(d.month!=Month.feb||d.day!=29)d+=days(1);return["Sun","Mon","Tues","Wednes","Thurs","Fri","Sat"][d.dayOfWeek]~"day";}

Более разборчиво:

S f(S)(S s)
{
    auto d = Date.fromISOExtString(s) + days(1);

    while(d.month != Month.feb || d.day != 29)
        d += days(1);

    return ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Sat"][d.dayOfWeek] ~ "day";
}

Это очень легко написать на D, но определенно не выиграет ни одного соревнования по коду. Тем не менее, вне игры в код, я бы предпочел, чтобы ее было легко писать и понимать, но дольше, чем кратко, но сложно писать и понимать.

Джонатан М Дэвис
источник
1

Java 8 - 252 символа

Golfed:

import java.time.*;
import java.time.format.*;
public class S{public static void main(String[] a){LocalDate d=LocalDate.parse(a[0]).plusDays(1);while(d.getMonthValue()!=2||d.getDayOfMonth()!=29){d=d.plusDays(1);}System.out.println(d.getDayOfWeek());}}

Ungolfed:

import java.time.*;
import java.time.format.*;
public class S {
    public static void main(String[] a) {
        LocalDate d = LocalDate.parse(a[0]).plusDays(1);

        while(d.getMonthValue()!=2 || d.getDayOfMonth()!=29) {
            d = d.plusDays(1);
        }
        System.out.println(d.getDayOfWeek());
    }
}
Майкл Пасха
источник
Я принимаю отрицательные отзывы, но не могли бы вы объяснить, что «некро реальна», и дать ссылку на FAQ, который объясняет вашу точку зрения? Я не думал, что смогу победить, но подумал, что было бы интересно посмотреть, как может это сделать Java, особенно. с учетом Java 8. Я рассматриваю кодовый гольф как имеющий "весовые категории" по сравнению с прямой конкуренцией. Java редко побеждает Ruby или Python.
Майкл Пасха
OP запрещает использование сторонних библиотек, поэтому в 2011 году решение на Java было бы неприятным, поскольку нельзя было использовать популярную библиотеку Joda Time. Однако Java 8 (выпущенная в марте 2014 года) содержит библиотеку JSR-310 DateTime - en.wikipedia.org/wiki/… . Моя причина в том, что я думал, что Java 8 будет интересной и потенциально интересной для некоторых читателей. (Если вы не один из них, хорошо: есть еще причина для этой должности.)
Майкл Пасха
1

Реболь - 78

f: func[d][system/locale/days/(until[d: d + 1 d/day * d/month = 58]d/weekday)]

Ungolfed:

f: func [d] [
    system/locale/days/(
        until [
            d: d + 1
            d/day * d/month = 58
        ]
        d/weekday
    )
]

Пример использования (в консоли Rebol):

>> f 0001-01-01
== "Sunday"

>> f 2100-01-01
== "Friday"
draegtun
источник
1

PHP, 104 байта

function f($s){for($y=$s-(substr($s,5)<"02-29");!date(L,$t=strtotime(++$y."-2-1")););return date(l,$t);}

сломать

for($y=$s-;                 // "-" casts the string to int; decrement year if ...
    (substr($s,5)<"02-29")  // ... date is before feb 29
    !date(L,                        // loop while incremented $y is no leap year
        $t=strtotime(++$y."-2-1")   // $t=feb 01 in that year (same weekday, but shorter)
    );
);
return date(l,$t);          // return weekday name of that timestamp

date(L): 1для високосного года, 0остальное
date(l): полное текстовое представление дня недели

Titus
источник
0

GNU coreutils, 71 байт

f(){
seq -f "$1 %gday" 2921|date -f- +'%m%d%A'|sed 's/0229//;t;d;:;q'
}

Линейный поиск на следующие 8 лет (наихудший случай, дан 2096-02-29). Sed находит и выводит первую строку, которая соответствует 29 февраля.

Я был удивлен, обнаружив, что t;d;:;qэто короче тестирования, чтобы увидеть, остались ли цифры ( /[01]/d;q), несмотря на то, что команд было в два раза больше.

тесты

Я добавил дополнительную строку тестов для сложных угловых случаев:

for i in 0001-01-01.Sunday 1899-12-03.Monday \
    1970-01-01.Tuesday     1999-07-06.Tuesday \
    2003-05-22.Sunday      2011-02-17.Wednesday 2100-01-01.Friday \
    2000-02-28.Tuesday     2000-02-29.Sunday    2000-03-01.Sunday   2096-02-29.Friday
do
    printf "%s => %s (expected %s)\n" ${i%.*} $(f ${i%.*}) ${i#*.}
done
Тоби Спейт
источник