День тижня наступного 29 лютого


14

Напишіть функцію, яка приймає дату і повертає день тижня наступного 29 лютого після цієї дати.

  • Вхід - це рядок у розширеному форматі ISO: РРРР-ММ-DD (наприклад, 27 травня 2010 року буде "2010-05-27").

  • Вихід - це рядок, який називає день тижня (наприклад, "понеділок"). Капіталізація не має значення, але вказуйте повну назву англійською мовою.

  • Якщо дана дата - 29 лютого, поверніть день тижня наступного 29 лютого.

  • Використовуйте обчислення для пролептичного григоріанського календаря (так, він використовує підрахунки григоріанського високосного року на всю його довжину). Не хвилюйтеся з приводу Юліанського календаря або коли відбувся перехід з Джуліана на Григоріанський. Просто припустимо, що Григоріан для всього.

  • Функція повинна працювати принаймні в діапазоні "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.
Joey

Причину, яку я запитав, було те, що я вже намагався використовувати 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. У будь-якому випадку, не повинно бути об'єкта PSO, який повертається з, Get-Dateале а System.DateTime.
Joey

Це дуже дивно. $d=Get-Date "0400-01-01"; $d++подає повідомлення про помилку про те, що ++не визначено в DateTime. Ж заміна ++з +=1або +="1"або +='1'видає повідомлення про помилку про PSObject. І просто +"1"працює.
Пітер Тейлор

5

Рубін 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) Видаліть зайві пробіли. Ще раз дякую, Догберте !

4
Не вдалося виконати контрольну скриньку для "0001-01-01". Дата Рубі надто потужна, вона враховує дати Джуліана.
steenslag

@Ventero Що робить def *? Ніколи цього не бачив.
steenslag

@steenslag: Спасибі, виправив цю тестову шафу. def*просто визначає функцію, яку називають *. Таким чином мені не потрібно пробіл між defі назвою функції.
Вентеро

1
Невже ви не могли б просто визначити лямбда? a = -> {...}
Wile E. Coyote

1
Крім того, немає необхідності в будь-якому просторі після стропового переривання.
Wile E. Coyote

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

Зважаючи на те, що я створюю переповнення, віднімаючи 2 місяці від 0001-01-01, навіть якщо я використовую правильний тип даних, я відмовляюся від створення чогось короткого та дійсного для цього питання. О_о. Трикси запитання.
мотиватор

Я люблю бачити ці рішення 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 ();}
Stephan Schinkel

Далі покращено до 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

Зразок вводу / виводу

:~/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
Пітер Тейлор

:-), як ми вже обговорювали мою сировину над башем! ... Чомусь я не сильно поспілкуюся з башем ... вони настільки схильні до помилок! .. Дякую за пропозицію ур ... оновлено!
Aman ZeeK Verma

1
Сирість з bash - це не привід для використання чотирибуквених імен змінних: P
Пітер Тейлор

так, сер, я зрозумів вашу думку.
Aman ZeeK Verma

2

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

sub f {($ y, $ m) = split / - /, @ _ ​​[0], 2; $ y ++, якщо ($ m> '02 -28 '); $ y = ($ y + 3)% 400 >> 2; $ y + = $ y &&! ($ Y% 25); @ r = (Вт, Веднес, Чт, Пт, Сату, Сонце, Пн); @ r [(5 * $ y - ($ y / 25 і 3))% 7]. "День";}

Справжня користь бібліотек цих дат - це відштовхувати довжину назв днів від когось іншого.

З іншого боку, я думаю, що це єдине рішення на даний момент, яке працює незалежно від місцевості.


2

ДАТА та деякий клей BASHy (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

Д: 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 символи

Гольф:

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());}}

Безголівки:

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 рідко переможе Рубі або Пітона прямо.
Майкл Пасха

ОП забороняє сторонні бібліотеки, тому в 2011 році рішення Java було б неприємним, оскільки не вдалося використати популярну бібліотеку Joda Time. Однак Java 8 (випущена в березні 2014 року) містить бібліотеку дата-часу JSR-310 - 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)]

Безголівки:

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"

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): повне текстове зображення дня тижня


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