Converti un codice data di Excel in una "data"


15

Dato un codice data intero in stile Excel non negativo, restituisci la "data" corrispondente in qualsiasi forma ragionevole che mostri chiaramente anno, mese e "giorno".

Triviale, potresti pensare. Hai notato le "virgolette"? Ho usato quelli perché Excel ha alcune stranezze. Excel conta giorni con il numero 1 per gennaio 1 ° , 1900, ma come se 1900 ha avuto un gennaio 0 ° e 29 febbraio ° , in modo da essere molto attenti a cercare tutti i casi di test:

 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

1
Ha ogni anno ha un 0a gennaio e il 29 febbraio o è di 1900 l'unica anomalia?
Shaggy,

4
1900 è l'anomalia. Excel tratta correttamente gli anni bisestili ad eccezione del 1900 (che non è un anno bisestile). Ma quello era per compatibilità con Lotus 1-2-3, da dove il bug ha avuto origine.
Rick Hitchcock,

3
@RickHitchcock Apparentemente, gli sviluppatori Lotus 1-2-3 lo hanno fatto per risparmiare sul codice dell'anno bisestile, in modo che la regola diventasse semplicemente ogni quattro anni. Con buone ragioni anche; Il 1900 era lontano nel passato e il 2100 lo è, beh, in un po '.
Adám,

3
@RickHitchcock Potrebbe benissimo essere che l'originale Lotus 1-2-3 non fosse in grado di gestire Y2K, e quindi Microsoft ha deciso di imitare quel problema, ma per il resto è giusto. A proposito, le vite precedenti su: OADate di .NET ha epoca 1899-12- 30 in modo che si schiererà con Excel su tutti, ma i primi due mesi del 1900, tuttavia ciò richiede il DayOfWeekmetodo perché l'epoca originale, 1899-12-30 (o il fittizio 1900-01-00) fu scelto in modo tale che il giorno della settimana fosse semplicemente il mod-7 del numero del giorno, ma che non funzionerà con il 1899-12-30.
Adám,

4
Ecco la storia dietro il "perché" delle date di Excel: Joel on Software: My First BillG Review . Lettura informativa (e divertente).
BradC,

Risposte:


14

Excel, 3 (+7?)

=A1

con il formato

yyy/m/d

Porto puro


Il formato di output può ovviamente variare in base alle impostazioni locali.
Adám,

2
Funziona solo su Excel per Windows. Excel per Mac ha un sistema numerico che inizia con le date nel 1904, non nel 1900. Non riporterà una data per nessun anno nel 1900, che fa parte dei casi di test. Potresti voler specificare che si tratta di Excel per Windows.
Keeta - ripristina Monica il

1
@Keeta Affinché funzioni su Excel per Mac, deseleziona semplicemente "Usa il sistema di data 1904" nelle preferenze .
BradC,

1
@BradC Sebbene sia vero, qualsiasi modifica alla configurazione predefinita di un programma è perfettamente soddisfacente, MA deve essere incluso nella risposta. Lo commento come punto per migliorare la risposta. Vorrei dire o cambiare il nome di esso in Excel per Windows, aggiungere l'avvertenza o passare a OpenOffice Calc (o simile, poiché includevano anche intenzionalmente il bug). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - ripristina Monica il

6

k (kdb + 3,5), 55 54 51 50 byte

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

per testare, incollare questa riga nella console 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;

l'output dovrebbe essere

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

{ } è una funzione con argomento x

0 60?xindice xtra 0 60o 2 se non trovato

ˋ1900.01.00ˋ1900.02.29 un elenco di due simboli

, aggiungere ad esso

"d"$ convertito in una data

x-36526 numero di giorni dal 1900 (invece del 2000 predefinito)

- x<60 regolare per l'errore di salto di Excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xgiustapposizione significa indicizzazione - la "@" nel mezzo è implicita

$ converti in stringa


1
Per una versione diversa di k (k5 / k6, credo), {$[x;$`d$x-65746;"1900.01.00"]} sembra funzionare . Presumo che qualcosa trabocca da qualche parte 100000.
zgrep,

@zgrep Dovresti postare dal momento che le versioni di K in pratica sono lingue completamente diverse.
Adám,

3

Python 2 , 111 byte

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

Provalo online!

-5 grazie a ngn .


Nota: sono abbastanza sicuro che questo si rivelerà più lungo come lambda, poiché il formato del risultato non dovrebbe variare.
Erik the Outgolfer,

3

JavaScript (ES6),  89 82  77 byte

Risparmiato  7  12 byte grazie a @tsh

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

Provalo online!


n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
dal

@tsh Questo è davvero molto meglio. Grazie. (Inoltre, mi chiedo se questo approccio potrebbe in qualche modo essere giocato a golf.)
Arnauld,

Ho appena scoperto che new Date(0,0,1)è lo stesso di new Date(1900,0,1). Quindi rimuovere 190salva 3 byte. E ...
TSH

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

Deve essere eseguito in GMT0 / -x?
l4m2

2

Pulito , 205 189 byte

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)

Provalo online!


1
Prima risposta che non utilizza la gestione della data integrata. Bello!
Adám,


1

APL (Dyalog Classic) , 31 byte

Funzione prefisso tacito anonimo. Data di ritorno come[Y,M,D]

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

Provalo online!

× segno del codice data

⊢- sottrarlo dall'argomento (il codice della data)

60∘>+ incrementare se il codice data è superiore a sessanta

2⎕NQ#263, usalo come argomento immediato per "Evento 263" (IDN fino ad oggi)
IDN è proprio come il codice data di Excel, ma senza il 29 febbraio 1900 e il giorno prima del 1 ° gennaio 1900 è il 31 dicembre 1899

3↑ prendine i primi tre elementi (il quarto è il giorno della settimana)

(... )+ aggiungi quanto segue a quelli:

60∘≠ 0 se il codice data è 60; 1 se il codice data non è 60

×- sottrarlo dal segno del codice data

¯3↑ prendi gli ultimi tre elementi (ce n'è solo uno) imbottitura con (due) zeri

sviluppato insieme a @ Adám in chat


1

C # (.NET Core) , 186 185 byte

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

Provalo online!


-1 byte sostituendo l'operatore OR (||) con l'operatore binario OR (|).



0

T-SQL, 141 95 94 byte

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

L'interruzione di riga è solo per leggibilità.

L'input viene preso tramite la tabella i preesistente con il campo intero n , secondo i nostri standard IO .

SQL utilizza un punto di partenza 1-1-1900 simile (ma corretto) per il suo formato di data interno, quindi devo solo compensarlo di 1 o 2 giorni nel DATEADD funzione.

SQL non può generare una colonna contenente un mix di valori di data e carattere, quindi non posso tralasciare il FORMATcomando (poiché proverebbe quindi a convertire1/0/1900 in una data, che ovviamente non è valida).

La cosa bella di SQL è che posso caricare tutti i valori di input nella tabella ed eseguirli tutti in una volta. La mia località (USA) viene impostata automaticamente su un m/d/yyyyformato data:

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

EDIT : salvato 46 byte passando a un nidificato IIF()anziché molto più dettagliato CASE WHEN.

EDIT 2 : salvato un altro byte spostando il -davanti a IIF.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.