Convierta un código de fecha de Excel en una "fecha"

15

Dado un código de fecha entero de estilo Excel no negativo, devuelva la "fecha" correspondiente en cualquier forma razonable que muestre claramente año, mes y "día".

Trivial, puedes pensar. ¿Notaste las "citas de miedo"? Los usé porque Excel tiene algunas peculiaridades. Excel cuenta días con el número 1 para enero 1 st , 1900, pero como si 1900 registró en enero 0 º y Un informe de febrero 29 de XX , por lo que tener mucho cuidado para tratar todos los casos de prueba:

 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án
fuente
1
¿ Todos los años tienen un 0 de enero y un 29 de febrero o es 1900 la única anomalía?
Shaggy
44
1900 es la anomalía. Excel trata los años bisiestos correctamente, excepto 1900 (que no es un año bisiesto). Pero eso fue por compatibilidad con Lotus 1-2-3, donde se originó el error.
Rick Hitchcock el
3
@RickHitchcock Aparentemente, los desarrolladores de Lotus 1-2-3 lo hicieron para ahorrar en el código del año bisiesto, de modo que la regla simplemente se convirtió cada cuatro años. Con buena razón también; 1900 estuvo lejos en el pasado, y 2100 es, bueno, en un tiempo.
Adám
3
@RickHitchcock Es muy posible que el Lotus 1-2-3 original no pueda manejar Y2K, por lo que Microsoft decidió imitar ese problema, pero por lo demás se mantuvo en lo cierto. Por cierto, la vida de legado sobre: OADate de .NET tiene época 1899-12- 30 de manera que quede alineada con Excel en todos menos en los dos primeros meses de 1900, sin embargo esto requiere el DayOfWeekmétodo porque la época original, 1899-12-30 (o el ficticio 1900-01-00) se eligió de modo que el día de la semana simplemente fuera el mod-7 del número del día, pero eso no funcionará con 1899-12-30.
Adám
44
Aquí está la historia detrás del "por qué" sobre las fechas de Excel: Joel en Software: Mi primera revisión de BillG . Lectura informativa (y entretenida).
BradC

Respuestas:

14

Excel, 3 (+7?)

=A1

con formato

yyy/m/d

Puerto puro

l4m2
fuente
El formato de salida, por supuesto, puede variar de acuerdo con su entorno local.
Adám
2
Esto solo funciona en Excel para Windows. Excel para Mac tiene un sistema numérico que comienza con fechas en 1904, no 1900. No informará una fecha para ningún año en 1900, que son parte de los casos de prueba. Es posible que desee especificar que se trata de Excel para Windows.
Keeta - reinstalar a Mónica el
1
@ Keeta Para que esto funcione en Excel para Mac, simplemente desmarque "Usar el sistema de fechas 1904" en las preferencias .
BradC
1
@BradC Aunque es cierto, cualquier cambio en la configuración predeterminada de un programa está perfectamente bien, PERO debe incluirse en la respuesta. Comento esto como un punto para mejorar la respuesta. Yo diría que cambie su nombre a Excel para Windows, agregue la advertencia o cambie a OpenOffice Calc (o similar, ya que también incluyeron el error a propósito). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - reinstalar a Monica el
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 probar, pegue esta línea en la consola 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;

la salida debe 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

{ } es una función con argumento x

0 60?xíndice de xentre 0 60o 2 si no se encuentra

ˋ1900.01.00ˋ1900.02.29 una lista de dos símbolos

, añádele

"d"$ convertido a una fecha

x-36526 número de días desde 1900 (en lugar del predeterminado 2000)

- x<60 ajustar por error de salto de Excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xyuxtaposición significa indexación: la "@" en el medio está implícita

$ convertir a cadena

ngn
fuente
1
Para una versión diferente de k (k5 / k6, creo), {$[x;$`d$x-65746;"1900.01.00"]} parece funcionar . Supongo que algo se desborda en alguna parte 100000.
zgrep
@zgrep Debería publicar ya que las versiones de K básicamente son idiomas completamente diferentes.
Adám
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]

Pruébalo en línea!

-5 gracias a ngn .

Erik el Outgolfer
fuente
Nota: estoy bastante seguro de que esto será más largo como lambda, ya que el formato del resultado no debería variar.
Erik the Outgolfer
3

JavaScript (ES6),  89 82  77 bytes

Guardado  7  12 bytes gracias a @tsh

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

Pruébalo en línea!

Arnauld
fuente
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
tsh
@tsh Eso es mucho mejor de hecho. Gracias. (Además, me pregunto si este enfoque podría de alguna manera ser golfizado.)
Arnauld
Me acabo de enterar new Date(0,0,1)es lo mismo que new Date(1900,0,1). Entonces eliminar 190guarda 3 bytes. Y ...
tsh
2
77 bytes:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh
¿Necesita ejecutarse en GMT0 / -x?
l4m2
2

Limpio , 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)

Pruébalo en línea!

Οurous
fuente
1
Primera respuesta que no usa manejo de fecha incorporado. ¡Agradable!
Adám
1

APL (Dyalog Classic) , 31 bytes

Función de prefijo tácito anónimo. Fecha de devolución como[Y,M,D]

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

Pruébalo en línea!

× signo del código de fecha

⊢- reste eso del argumento (el código de fecha)

60∘>+ aumentar si el código de fecha es superior a sesenta

2⎕NQ#263, úselo como argumento inmediato para el "Evento 263" (IDN hasta la fecha)
IDN es como el código de fecha de Excel, pero sin el 29 de febrero de 1900, y el día anterior al 1 de enero de 1900 es el 31 de diciembre de 1899

3↑ tome los primeros tres elementos de eso (el cuarto es el día de la semana)

()+ Agregue lo siguiente a aquellos:

60∘≠ 0 si el código de fecha es 60; 1 si el código de fecha no es 60

×- reste eso del signo del código de fecha

¯3↑ tome los últimos tres elementos (solo hay uno) relleno con (dos) ceros

desarrollado junto con @ Adám en el chat

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

Pruébalo en línea!


-1 byte reemplazando el operador OR (||) con el operador OR binario (|).

cobalto
fuente
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

El salto de línea es solo para legibilidad.

La entrada se toma a través de la tabla i existente con el campo entero n , según nuestros estándares IO .

SQL utiliza un punto de inicio similar (pero corregido) 1-1-1900 para su formato de fecha interno, por lo que solo tengo que compensarlo en 1 o 2 días en el DATEADD función.

SQL no puede generar una columna que contenga una combinación de valores de fecha y caracteres, por lo que no puedo omitir el FORMATcomando (ya que luego intentaría convertir 1/0/1900a una fecha, que por supuesto no es válida).

Lo bueno de SQL es que puedo cargar todos los valores de entrada en la tabla y ejecutarlos todos a la vez. Mi localidad (de EE. UU.) Tiene un m/d/yyyyformato de fecha predeterminado :

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

EDITAR : guardó 46 bytes al cambiar a un anidado en IIF()lugar del mucho más detallado CASE WHEN.

EDITAR 2 : guardado otro byte moviendo el -frente de IIF.

BradC
fuente