Znajdź najbliższą datę, podając datę docelową i dzień tygodnia

12

Znajdź datę najbliższą docelowej dacie dla danego dnia tygodnia.

Na przykład, biorąc pod uwagę datę 20161219i dzień tygodnia Friday (6), odpowiedź brzmi 20161216.

Innym przykładem, biorąc pod uwagę datę 20161219i dzień tygodnia Wednesday (4), odpowiedź jest 20161221.

Ostatnim przykładem, biorąc pod uwagę datę 20161219i dzień tygodnia Monday (2), odpowiedź brzmi 20161219.

Zasady:

  • Format daty dla danych wejściowych i wyjściowych musi być zgodny. W przykładach użyłem yyyymmdd, ale możesz użyć dowolnego formatu, o ile rok (co najmniej dwie cyfry), miesiąc i dzień miesiąca są „czytelne dla człowieka”.
  • Dzień tygodnia jest wprowadzany jako liczba całkowita. W moim przykładzie niedziela jest pierwszym dniem tygodnia, dlatego jest dniem tygodnia 1. Możesz mieć dowolną numerację w Dniu Tygodnia, o ile zauważysz, że różni się ona od przykładu.
  • Lata 1970–2030 muszą zostać uwzględnione.
  • Dozwolone są narzędzia i biblioteki danych w języku potocznym, ale uliczne dane są przyznawane tym, którzy zdecydują się ich nie używać.
  • Najmniej wygranych bajtów .
Brett VanderVeen
źródło
2
Czy odpowiedzi mogą być przydatne w innej formie? Również dni tygodnia były niewygodne dla języków, w których poniedziałek jest pierwszym dniem tygodnia
Blue
4
Tak, ścisłe wymagania dotyczące formatu sprawiają, że to zadanie bardziej dotyczy parsowania / konwertowania / formatowania, niż faktycznego wyszukiwania daty. Byłoby lepiej, gdyby IMO określiło to zgodnie z zasadą „ Możesz zaakceptować datę i dzień tygodnia w dowolnym rozsądnym formacie, pod warunkiem, że używasz tego samego formatu dla danych wejściowych i wyjściowych ”. Ale ponieważ wiele osób już przesłało odpowiedzi, myślę, że trzeba to zachować tak, jak jest teraz.
smls,
@smls Zgadzam się. Lekcja wyciągnięta na następny raz.
Brett VanderVeen
1
@BrettVanderVeen Nie sądzę, że jest już za późno na złagodzenie wymagań. Możesz po prostu dodać komentarz do każdej (obecnie 8) odpowiedzi na temat zaktualizowanej specyfikacji. Robiłem tak czasami.
Adám,

Odpowiedzi:

1

Perl 6 , 46 bajtów

{~first *.day-of-week==$^b,Date.new($^a)-3..*}

Lambda, która akceptuje dwa argumenty: Ciąg daty w yyyy-mm-ddformacie i numer dnia tygodnia między 1= poniedziałek a 7= niedziela.

Wyjaśnienie:

                           Date.new($^a)       # Construct Date object from first argument.
                                        -3     # Subtract 3 days.
                                          ..*  # Construct a Range from that, to infinity.
  first                   ,                    # Iterate the range, and return first date...
        *.day-of-week==$^b                     # whose weekday number equals the second arg.

Przy użyciu formatu daty i dnia tygodnia użytego w przykładach będzie to 88 bajtów:

{S:g/\-//with ~first *.day-of-week==($^b-2)%7+1,Date.new(|($^a~~/(....)(..)(..)/))-3..*}
smls
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
@BrettVanderVeen: Zaktualizowano.
smls
2

Perl 6 , 83 bajtów

->$_,\w{~(Date.new(|m/(....)(..)(..)/)-3...*.day-of-week%7+1==w)[*-1]~~{S:g/"-"//}}

Spróbuj

Rozszerzony

->     # pointy block lambda
  $_,
  \w
{
  ~(  # turn into a Str

    Date.new( |m/(....)(..)(..)/ ) - 3 # three days earlier
    ...                                # generate a sequence
    *.day-of-week % 7 + 1 == w         # stop when the right day is found

  )[*-1]  # the last one

  ~~      # apply the following block

  {
    S:g/"-"//  # remove 「-」
  }
}
Brad Gilbert b2gills
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
2

JavaScript (ES6), 93 bajty

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().slice(0,10)

Używa %Y-%m-%dformatu daty. Jeśli %a %b %d %Yjest akceptowalnym formatem daty, to dla 82 bajtów:

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toDateString()

Mógłbym zaoszczędzić kolejne 2 bajty, wymagając od niedzieli = 10 do soboty = 16, ale to głupiutki dzień mapowania tygodnia. Poprzednie 142 141 bajtów (dzięki @Guedes) wersja, która używała określonego formatu daty RRRRMMDD, z wyjaśnieniem:

(s,n,d=new Date(s.replace(/(?=..(..)?$)/g,'-')))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().replace(/-(..)-(..).*/,'$1$2')

To wydaje się zbyt długie. Objaśnienie: Najpierw wstawia -s do daty, aby uzyskać format ISO, który new Datemożna następnie przeanalizować. Następnie porównuje pożądany dzień z faktycznym dniem, aby uzyskać wartość pomiędzy -3i 3dla rzeczywistego przesunięcia. Magia 9pochodzi z 7(ponieważ %jest to modul CPU, a nie true modulo) plus 3(dla -3offsetu) minus 1(ponieważ nma indeks 1 i indeks getDay0). Data jest następnie konwertowana z powrotem do formatu ISO, a niepożądane znaki są usuwane.

Neil
źródło
Możesz zapisać jeden bajt, zmieniając pierwszy zamień na.replace(/(?=..(..)?$)/g,'-')
Washington Guedes,
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
1

Python, 150 149 bajtów

from datetime import*
lambda s,n,t='%Y%m%d':[d for d in[datetime.strptime(s,t)+timedelta(o-3)for o in range(7)]if(n-2)%7==d.weekday()][0].strftime(t)

Oouuf, 149. repl. It

Nienazwany funkcja, która pobiera ciąg s, jako datę (w formacie określonym ciągiem t='%Y%m%d'zarówno wejście i wyjście) i numer w [1,7] n.
Sprawdza siedem dni od trzech dni przed trzema dniami po tym, jak podano dla żądanego dnia tygodnia.
Tydzień datetimezaczyna się w poniedziałek i jest zerowy, więc test jest (n-2)%7==d.weekday().

Jonathan Allan
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
1

Bash + coreutils, 50

date -d$1+$[($2-`date -d$1 +%u`+9)%7-3]day +%Y%m%d

Wypróbuj online .

  • date -d$1 +%upodaje dzień tygodnia (1..7); 1 to poniedziałek
  • Jest to odejmowane od wejściowego dnia tygodnia, aby dać różnicę indeksów dziennych. Chcemy dodać współczynnik z zakresu [-3, 3] do daty wejściowej, aby uzyskać najbliższą datę, więc dodajemy współczynnik magiczny 9, bierzemy moduł 7, a następnie odejmujemy 3. Współczynnik magiczny 9 to 3 + 7 - 1. 3 dostosowuje zakres wejściowy dla zakresu [-3, 3] i jest ponownie odejmowany po modulo. 7 jest wymagane, ponieważ modulo bash jest takie samo jak modulo procesora i może dać -ve wyniki - dodanie 7 dopasowań we właściwym zakresie. -1 oznacza, że ​​na wejściu 1 oznacza niedzielę, ale przy wyjściu% u 1 oznacza poniedziałek.
  • Zewnętrzne datenastępnie analizuje <input date> + <magic factor>daysi przedstawia je w formacie RRRRMMDD.
Cyfrowa trauma
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
1

SAS Macro Language, 110 bajtów

%macro s(d,a);%put %sysfunc(putn(%sysfunc(intnx(week.&a.,%eval(%sysfunc(putn(&d,8.))-4),1)),yymmddn8.));%mend;

Okropny język golfa, ale oto wyjaśnienie (od wewnątrz):

Utwórz makro, sktóre akceptuje wprowadzanie daty di numeryczny dzień tygodnia a. Następnie %eval(%sysfunc(putn(&d,8.))-4)konwertuje datę na datę numeryczną SAS i zmniejsza ją o 4 dni. Następnie intnxfunkcja zwraca następne wystąpienie określonego dnia tygodnia. putnnastępnie formatuje datę z powrotem do rrrrmmdd i %putwypisuje dane wyjściowe do dziennika.

J_Lard
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
1

Mathematica, 85 49 bajtów

#~DatePlus~Mod[#2-#~DateValue~"ISOWeekDay",7,-3]&

Format wejściowy dla dat jest albo listą podobną, {2016, 12, 16}albo faktyczną DateObject(myślę, że kilka innych również działa, ale je przetestowałem). W obu przypadkach format wyjściowy zostanie dopasowany automatycznie. Numeracja dni zaczyna się od 1poniedziałku.

Chodzi o to, aby obliczyć różnicę między wejściowym dniem roboczym a docelowym dniem roboczym za pomocą, #2-#~DateValue~"ISOWeekDay"a następnie zmapować go [-3, 3]za pomocą modulo z przesunięciem (tj Mod[...,7,-3].). Wynik jest po prostu dodawany do daty wejściowej (domyślną jednostką dodawania obiektu daty są dni).

Martin Ender
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
@BrettVanderVeen dzięki, edytowane.
Martin Ender,
1

R, 119 77 56 bajtów

Nienazwana funkcja, która pobiera dwa dane wejściowe: datę D(ciąg) i dzień d(numerycznie).

function(D,d,s=-3:3+as.Date(D))s[lubridate::wday(s)==d]

Korzysta z funkcji wday()z lubridatepakietu. Może wygodnie konwertować Dateobiekty na dni tygodnia, 1domyślnie traktowane jako niedziela.

Edycja: I / O jest teraz domyślną as.Date()funkcją:"YYYY-mm-dd"

Nieoznakowany i wyjaśniony

function(D,d){
    D=as.Date(D);            # Format input date
    s=-3:3+D;                # Generate sequence of +- 3 days
    s[lubridate::wday(s)==d] # Match the weekday that equals to target day                                    
}

Edycja: Teraz tworzy sekwencję +-3dni, w których można znaleźć każdy dzień tygodnia. Następnie musimy dopasować tylko jeden dzień, co znacznie ułatwiło problem.

Billywob
źródło
Do twojej wiadomości, złagodziłem zasady formatu daty i dnia tygodnia. Prześlij ponownie.
Brett VanderVeen
@BrettVanderVeen Dzięki, zaktualizowano.
Billywob