Konwertuj kod daty Excela na „datę”

15

Biorąc pod uwagę nieujemną liczbę całkowitą kod daty w stylu Excel, zwróć odpowiednią „datę” w dowolnej rozsądnej formie, która wyraźnie pokazuje rok, miesiąc i „dzień”.

Trywialne, może się wydawać. Czy zauważyłeś „przerażające cytaty”? Użyłem ich, ponieważ Excel ma pewne dziwactwa. Excel liczy dni z numerem 1 na 1 stycznia st 1900, ale jakby miała stycznia 1900 0 th i 29 lutego th , więc być bardzo ostrożny, aby spróbować wszystkich przypadków testowych:

 Input → Output (example format)
     0 → 1900-01-00    Note: NOT 1899-12-31
     1 → 1900-01-01
     2 → 1900-01-02
    59 → 1900-02-28
    60 → 1900-02-29    Note: NOT 1900-03-01
    61 → 1900-03-01
   100 → 1900-04-09
  1000 → 1902-09-26
 10000 → 1927-05-18
100000 → 2173-10-14
Adám
źródło
1
Czy każdego roku przypada 0 stycznia i 29 lutego, czy też 1900 to jedyna anomalia?
Kudłaty
4
1900 to anomalia. Excel poprawnie traktuje lata przestępne, z wyjątkiem 1900 (który nie jest rokiem przestępnym). Było to jednak zgodne z Lotus 1-2-3, z którego pochodzi błąd.
Rick Hitchcock
3
@ RickHitchcock Najwyraźniej twórcy Lotus 1-2-3 zrobili to, by zaoszczędzić na kodzie roku przestępnego, tak że reguła stała się co cztery lata. Również z dobrego powodu; 1900 był daleko w przeszłości, a 2100 jest, no cóż, za jakiś czas.
Adám
3
@ RickHitchcock Może się zdarzyć, że oryginalny Lotus 1-2-3 nie był w stanie obsłużyć Y2K, więc Microsoft postanowił naśladować ten jeden problem, ale w przeciwnym razie pozostanie w porządku. Btw, dziedzictwo mieszka w: .NET za OADate ma epokę 1899-12- 30 tak, że będzie w jednej linii z Excela na wszystko, ale w pierwszych dwóch miesiącach 1900 roku, jednak wymaga to DayOfWeekmetoda, ponieważ oryginalny epoka, 30.12.1899 (lub fikcyjny 1900-01-00) został wybrany tak, że dzień tygodnia był po prostu mod-7 numeru dnia, ale to nie zadziała z 1899-12-30.
Adám
4
Oto historia związana z datami Excela: „ Joel on Software: My First BillG Review” . Pouczające (i zapewniające rozrywkę) lektura.
BradC

Odpowiedzi:

14

Excel, 3 (+7?)

=A1

z formatem

yyy/m/d

Czysty port

l4m2
źródło
Format wyjściowy może oczywiście różnić się w zależności od ustawień regionalnych.
Adám
2
Działa to tylko w programie Excel dla systemu Windows. Excel dla komputerów Mac ma system liczb, który zaczyna się od dat w 1904, a nie 1900. Nie będzie podawać daty dla żadnego roku w 1900, które są częścią przypadków testowych. Możesz określić, że jest to Excel dla systemu Windows.
Keeta
1
@Keeta Aby to działało w programie Excel dla komputerów Mac, po prostu usuń zaznaczenie opcji „Użyj systemu dat 1904” w preferencjach .
BradC
1
@BradC Chociaż prawda, każda zmiana domyślnej konfiguracji programu jest całkowicie w porządku, ALE musi być zawarta w odpowiedzi. Komentuję to, aby poprawić odpowiedź. Powiedziałbym, że albo zmień jego nazwę na Excel dla Windows, dodaj zastrzeżenie, albo przełącz na OpenOffice Calc (lub podobny, ponieważ celowo również zawierają błąd). codegolf.meta.stackexchange.com/questions/10037/…
przywróć Monikę
6

k (kdb + 3,5), 55 54 51 50 bajtów

{$(`1900.01.00`1900.02.29,"d"$x-36526-x<60)0 60?x}

aby przetestować, wklej ten wiersz do konsoli q:

k)-1@{$(`1900.01.00`1900.02.29,"d"$x-36526-x<60)0 60?x}'0 1 2 59 60 61 100 1000 10000 100000;

wyjście powinno być

1900.01.00
1900.01.01
1900.01.02
1900.02.28
1900.02.29
1900.03.01
1900.04.09
1902.09.26
1927.05.18
2173.10.14

{ } jest funkcją z argumentem x

0 60?xindeks xspośród 0 60lub 2, jeśli nie znaleziono

ˋ1900.01.00ˋ1900.02.29 lista dwóch symboli

, dołącz do niego

"d"$ konwertowane na datę

x-36526 liczba dni od 1900 roku (zamiast domyślnego 2000)

- x<60 skoryguj o błąd skoku programu Excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xzestawienie oznacza indeksowanie - „@” pośrodku jest niejawne

$ przekonwertować na ciąg

ngn
źródło
1
{$[x;$`d$x-65746;"1900.01.00"]} Wydaje się , że w przypadku innej wersji k (k5 / k6) działa . Zakładam, że coś się gdzieś przelewa 100000.
zgrep
@zgrep Powinieneś pisać, ponieważ wersje K w zasadzie są całkowicie odmiennymi językami.
Adám
3

Python 2 , 111 bajtów

from datetime import*
n=input()
print('1900-0'+'12--0209'[n>9::2],date(1900,1,1)+timedelta(n+~(n>59)))[0<n!=60]

Wypróbuj online!

-5 dzięki ngn .

Erik the Outgolfer
źródło
Uwaga: Jestem prawie pewien, że okaże się, że będzie on dłuższy jako lambda, ponieważ format wyniku nie powinien się różnić.
Erik the Outgolfer
3

JavaScript (ES6),  89 82  77 bajtów

Zaoszczędź  7  12 bajtów dzięki @tsh

n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')

Wypróbuj online!

Arnauld
źródło
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
tsh
@tsh To rzeczywiście o wiele lepsze. Dzięki. (Zastanawiam się także, czy to podejście można w jakiś sposób pograć w golfa.)
Arnauld
Właśnie się dowiedziałem, że new Date(0,0,1)to samo new Date(1900,0,1). Więc usuń 190zapisuje 3 bajty. I ...
tsh
2
77 bajtów:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh
Czy trzeba go uruchamiać w GMT0 / -x?
l4m2
2

Czysty , 205 189 bajtów

import StdEnv
a=30;b=31;c=1900;r=rem
@m=sum(take m(?c))
?n=[b,if(n>c&&(r n 4>0||r n 100<1&&r n 400>0))28 29,b,a,b,a,b,b,a,b,a,b: ?(n+1)]
$n#m=while(\m= @m<n)inc 0-1
=(c+m/12,1+r m 12,n- @m)

Wypróbuj online!

Obrzydliwe
źródło
1
Pierwsza odpowiedź, która nie korzysta z wbudowanej obsługi dat. Ładny!
Adám
1

Japt, 43 bajty

Skończyło się to częściowym portem rozwiązania Arnaulda .

Dane wyjściowe są w yyyy-m-dformacie.

?U-#<?Ð#¾0TUaU>#<)s7:"1900-2-29":"1900-1-0"

Wypróbuj online lub przetestuj 0-100

Kudłaty
źródło
1

APL (Dyalog Classic) , 31 bajtów

Anonimowa ukryta funkcja prefiksu. Zwraca datę jako[Y,M,D]

3↑×-60∘≠)+32NQ#263,60∘>+⊢-×

Wypróbuj online!

× znak kodu daty

⊢- odejmij to od argumentu (kod daty)

60∘>+ przyrost, jeśli kod daty jest większy niż sześćdziesiąt

2⎕NQ#263, użyj tego jako bezpośredniego argumentu dla „Zdarzenia 263” (IDN do tej pory)
IDN jest jak kod daty Excela, ale bez 29 lutego 1900 r., a dzień przed 1 stycznia 1900 r. to 31 grudnia 1899 r.

3↑ weź trzy pierwsze elementy (czwarty to dzień tygodnia)

()+ Dodaj następujące elementy:

60∘≠ 0, jeśli kod daty to 60; 1, jeśli kod daty nie ma 60

×- odejmij to od znaku kodu daty

¯3↑ weź trzy ostatnie elementy (jest tylko jeden) wypełnienie (dwoma) zerami

opracowane wspólnie z @ Adám na czacie

ngn
źródło
1

C # (.NET Core) , 186 185 bajtów

using System;class P{static void Main(){var i=int.Parse(Console.ReadLine());Console.Write((i==0|i==60)?$"1900-{i%59+1}-{i%31}":DateTime.FromOADate(i+(i<60?1:0)).ToString("yyyy-M-d"));}}

Wypróbuj online!


-1 bajt poprzez zastąpienie operatora OR (||) binarnym operatorem OR (|).

kobalt
źródło
0

T-SQL, 141 95 94 bajtów

SELECT IIF(n=0,'1/0/1900',IIF(n=60,'2/29/1900',
FORMAT(DATEADD(d,n,-IIF(n<60,1,2)),'d')))FROM i

Podział linii służy wyłącznie do odczytu.

Dane wejściowe są pobierane za pośrednictwem istniejącej tabeli i z polem całkowitym n , zgodnie z naszymi standardami we / wy .

SQL używa podobnego (ale poprawionego) punktu początkowego 1-1-1900 dla swojego wewnętrznego formatu daty, więc muszę go przesunąć tylko o 1 lub 2 dni w DATEADD funkcji.

SQL nie może wypisać kolumny zawierającej mieszankę wartości daty i znaków, więc nie mogę pominąć FORMAT polecenia (ponieważ wtedy próbowałby przekonwertować 1/0/1900na datę, co oczywiście jest nieprawidłowe).

Zaletą SQL jest to, że mogę załadować wszystkie wartości wejściowe do tabeli i uruchomić je wszystkie naraz. Domyślną lokalizacją w mojej (USA) jest m/d/yyyyformat daty:

n       output
0       1/0/1900
1       1/1/1900
2       1/2/1900
59      2/28/1900
60      2/29/1900
61      3/1/1900
100     4/9/1900
1000    9/26/1902
10000   5/18/1927
43432   11/28/2018
100000  10/14/2173

EDYCJA : Zapisano 46 bajtów, zmieniając na zagnieżdżony IIF()zamiast o wiele bardziej szczegółowy CASE WHEN.

EDYCJA 2 : Zapisano kolejny bajt, przesuwając -przed nim IIF.

BradC
źródło