Converter um código de data do Excel em uma "data"

15

Dado um código de data inteiro não negativo no estilo Excel, retorne a "data" correspondente em qualquer forma razoável que mostre claramente ano, mês e "dia".

Trivial, você pode pensar. Você notou as "citações de susto"? Eu usei isso porque o Excel tem algumas peculiaridades. Excel conta os dias com o número 1 para janeiro 1 st de 1900, mas como se 1900 teve um janeiro 0 º e um fevereiro 29 th , que deve ter muito cuidado para tentar todos os casos de teste:

 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ão
fonte
1
Será que cada ano tem um 0 de janeiro e 29 de fevereiro, ou seja 1900, a única anomalia?
Shaggy
4
1900 é a anomalia. O Excel trata os anos bissextos corretamente, exceto em 1900 (que não é um ano bissexto). Mas isso era para compatibilidade com o Lotus 1-2-3, de onde o bug se originou.
21718 Rick Ricky
3
@ RickHitchcock Aparentemente, os desenvolvedores do Lotus 1-2-3 fizeram isso para economizar no código do ano bissexto, de modo que a regra simplesmente se tornasse a cada quarto ano. Com boas razões também; 1900 estava longe no passado, e 2100 é, bem, daqui a pouco.
Adám 27/11/18
3
@RickHitchcock Pode muito bem ser que o Lotus 1-2-3 original não possa lidar com o Y2K, e por isso a Microsoft decidiu imitar esse problema, mas, de outra forma, fique certo. Btw, as vidas do legado sobre: do .NET OADate tem época 1899-12- 30 para que ele irá alinhar com Excel em todos, mas os dois primeiros meses de 1900, no entanto, isso requer o DayOfWeekmétodo, porque a época original, 1899-12-30 (ou o fictício 1900-01-00) foi escolhido de forma que o dia da semana fosse simplesmente o número 7 do dia, mas isso não funcionaria com 1899-12-30.
Adám 27/11/18
4
Aqui está a história por trás do "porquê" sobre as datas do Excel: Joel on Software: My First BillG Review . Leitura informativa (e divertida).
BradC

Respostas:

14

Excel, 3 (+7?)

=A1

com formato

yyy/m/d

Porto puro

l4m2
fonte
O formato de saída pode variar de acordo com a sua localidade.
Adám 27/11/18
2
Isso funciona apenas no Excel para Windows. O Excel para Mac possui um sistema numérico que começa com datas em 1904, e não em 1900. Ele não informa uma data para nenhum ano em 1900, que faz parte dos casos de teste. Você pode especificar que este é o Excel para Windows.
Keeta - reinstala Monica 28/11
1
@ Keeta Para que isso funcione no Excel para Mac, basta desmarcar "Usar o sistema de datas 1904" nas preferências .
BradC
1
@BradC Embora seja verdade, qualquer alteração na configuração padrão de um programa está perfeitamente correta, MAS deve ser incluída na resposta. Comento isso como um ponto para melhorar a resposta. Eu diria que ou mude o nome dele para o Excel para Windows, adicione a ressalva ou mude para o OpenOffice Calc (ou similar, pois eles também incluíram o bug de propósito). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - reinstala Monica 28/11
6

k (kdb + 3.5), 55 54 51 50 bytes

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

para testar, cole esta linha no 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;

a saída deve ser

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

{ } é uma função com argumento x

0 60?xíndice de xentre 0 60ou 2 se não for encontrado

ˋ1900.01.00ˋ1900.02.29 uma lista de dois símbolos

, anexar a ele

"d"$ convertido para uma data

x-36526 número de dias desde 1900 (em vez do padrão 2000)

- x<60 ajustar para o erro de salto do excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@0 60?x justaposição significa indexação - o "@" no meio está implícito

$ converter em string

ngn
fonte
1
Para uma versão diferente do k (k5 / k6, eu acho), {$[x;$`d$x-65746;"1900.01.00"]} parece funcionar . Presumo que algo transborda em algum lugar 100000.
Zgrep
@ zgrep Você deve postar, já que as versões do K são basicamente idiomas totalmente diferentes.
Adám 28/11/18
3

Python 2 , 111 bytes

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

Experimente online!

-5 graças a ngn .

Erik, o Outgolfer
fonte
Nota: Tenho certeza de que isso acabará sendo mais longo como um lambda, pois o formato do resultado não deve variar.
Erik the Outgolfer
3

JavaScript (ES6),  89 82  77 bytes

Guardado  7  12 bytes graças a @tsh

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

Experimente online!

Arnauld
fonte
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
TSH
@tsh Isso é muito melhor mesmo. Obrigado. (Além disso, gostaria de saber se esta abordagem poderia de alguma forma ser golfed.)
Arnauld
Acabei de descobrir que new Date(0,0,1)é o mesmo new Date(1900,0,1). Então remova 190salva 3 bytes. E ...
tsh 29/11
2
77 bytes:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh 29/11
Precisa ser executado em GMT0 / -x?
L4m2
2

Limpo , 205 189 bytes

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)

Experimente online!

Furioso
fonte
1
Primeira resposta que não usa manipulação de data interna. Agradável!
Adám 29/11/18
1

APL (Dyalog Classic) , 31 bytes

Função de prefixo tácito anônimo. Retorna a data como[Y,M,D]

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

Experimente online!

× sinal do código da data

⊢- subtraia isso do argumento (o código da data)

60∘>+ incremento se o código da data estiver acima de sessenta

2⎕NQ#263, use isso como argumento imediato para o "Evento 263" (IDN até o momento)
IDN é exatamente como o código de data do Excel, mas sem 29 de fevereiro de 1900, e o dia anterior a 1º de janeiro de 1900 é 31 de dezembro de 1899

3↑ pegue os três primeiros elementos disso (o quarto é dia da semana)

()+ Adicione o seguinte a esses:

60∘≠ 0 se o código da data for 60; 1 se o código da data não for 60

×- subtraia isso do sinal do código da data

¯3↑ pegue os três últimos elementos (existe apenas um) preenchimento com (dois) zeros

desenvolvido em conjunto com @ Adám no chat

ngn
fonte
1

C # (.NET Core) , 186 185 bytes

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

Experimente online!


-1 byte, substituindo o operador OR (||) pelo operador OR binário (|).

cobaltp
fonte
0

T-SQL, 141 95 94 bytes

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

A quebra de linha é apenas para legibilidade.

A entrada é obtida via tabela preexistente i com campo inteiro n , de acordo com nossos padrões de IO .

O SQL usa um ponto de partida 1-1-1900 semelhante (mas corrigido) para seu formato de data interno; portanto, só preciso compensá-lo por 1 ou 2 dias no DATEADD função.

O SQL não pode gerar uma coluna que contenha uma combinação de valores de data e caractere, portanto, não posso deixar de lado o FORMATcomando (pois ele tentaria converter 1/0/1900para uma data, o que obviamente é inválido).

O interessante do SQL é que eu posso carregar todos os valores de entrada na tabela e executá-los todos de uma vez. Minha localidade (EUA) é padronizada para um m/d/yyyyformato de 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 : Salvo 46 bytes, alterando para um aninhado em IIF()vez de muito mais detalhado CASE WHEN.

EDIÇÃO 2 : salvou outro byte movendo o -na frente do IIF.

BradC
fonte