Convertir un code de date Excel en une «date»

15

Étant donné un code de date de type Excel entier non négatif, renvoyez la "date" correspondante sous toute forme raisonnable qui indique clairement l'année, le mois et le "jour".

Trivial, vous pouvez penser. Avez-vous remarqué les "citations effrayantes"? Je les ai utilisés car Excel a des bizarreries. Excel compte jours avec le numéro 1 pour 1 Janvier er , 1900, mais comme si 1900 avait un Janvier 0 e et A29 Février e , donc être très prudent d'essayer tous les tests:

 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
Adam
la source
1
Chaque année a- t-elle un 0 janvier et 29 février ou 1900 est-elle la seule anomalie?
Shaggy
4
1900 est l'anomalie. Excel traite correctement les années bissextiles à l'exception de 1900 (qui n'est pas une année bissextile). Mais c'était pour la compatibilité avec Lotus 1-2-3, d'où le bogue est originaire.
Rick Hitchcock
3
@RickHitchcock Apparemment, les développeurs Lotus 1-2-3 l'ont fait pour économiser sur le code de l'année bissextile, de sorte que la règle est simplement devenue tous les quatre ans. Avec raison aussi; 1900 était loin dans le passé, et 2100 l'est, enfin, dans un certain temps.
Adám
3
@RickHitchcock Il se peut très bien que l'original Lotus 1-2-3 ne puisse pas gérer Y2K, et donc Microsoft a décidé d'imiter ce problème, mais sinon, il reste correct. BTW, la vie héritées sur: OADate de .NET a époque 1899-12- 30 afin qu'il aligner avec Excel sur tous , mais les deux premiers mois de 1900, mais cela nécessite la DayOfWeekméthode parce que l'époque d' origine, 1899-12-30 (ou le fictif 1900-01-00) a été choisi de telle sorte que le jour de la semaine était simplement le mod-7 du numéro du jour, mais cela ne fonctionnera pas avec 1899-12-30.
Adám
4
Voici l'histoire derrière le «pourquoi» des dates Excel: Joel sur le logiciel: ma première revue BillG . Lecture informative (et divertissante).
BradC

Réponses:

14

Excel, 3 (+7?)

=A1

avec format

yyy/m/d

Port pur

l4m2
la source
Le format de sortie peut bien sûr varier en fonction de votre environnement local.
Adám
2
Cela ne fonctionne que sur Excel pour Windows. Excel pour Mac a un système de numérotation qui commence par des dates en 1904 et non en 1900. Il ne signalera aucune date pour une année en 1900, qui fait partie des cas de test. Vous souhaiterez peut-être spécifier qu'il s'agit d'Excel pour Windows.
Keeta - réintègre Monica
1
@Keeta Pour que cela fonctionne sur Excel pour Mac, décochez simplement "Utiliser le système de date 1904" dans les préférences .
BradC
1
@BradC Bien que vrai, toute modification de la configuration par défaut d'un programme est parfaitement correcte MAIS doit être incluse dans la réponse. Je commente ceci pour améliorer la réponse. Je dirais soit changer le nom de celui-ci en Excel pour Windows, ajouter la mise en garde, ou passer à OpenOffice Calc (ou similaire, car ils ont également inclus le bogue à dessein). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - réintègre Monica
6

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

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

pour tester, collez cette ligne dans la 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;

la sortie doit être

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

{ } est une fonction avec argument x

0 60?xindice xparmi 0 60ou 2 s'il n'est pas trouvé

ˋ1900.01.00ˋ1900.02.29 une liste de deux symboles

, y ajouter

"d"$ converti en date

x-36526 nombre de jours depuis 1900 (au lieu de 2000 par défaut)

- x<60 ajuster pour l'erreur de saut d'Excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xjuxtaposition signifie indexation - le "@" au milieu est implicite

$ convertir en chaîne

ngn
la source
1
Pour une version différente de k (k5 / k6, je pense), {$[x;$`d$x-65746;"1900.01.00"]} semble fonctionner . Je suppose que quelque chose déborde quelque part 100000.
zgrep
@zgrep Vous devriez publier car les versions de K sont fondamentalement des langages totalement différents.
Adám
3

Python 2 , 111 octets

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

Essayez-le en ligne!

-5 grâce à ngn .

Erik le Outgolfer
la source
Remarque: je suis presque sûr que cela se révélera plus long en tant que lambda, car le format du résultat ne devrait pas varier.
Erik the Outgolfer
3

JavaScript (ES6),  89 82  77 octets

 7  12 octets enregistrés grâce à @tsh

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

Essayez-le en ligne!

Arnauld
la source
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
tsh
@tsh C'est bien mieux en effet. Merci. (Aussi, je me demande si cette approche pourrait être mise en pratique d'une manière ou d'une autre.)
Arnauld
Je découvre que new Date(0,0,1)c'est la même chose que new Date(1900,0,1). Donc, supprimer 190enregistre 3 octets. Et ...
tsh
2
77 octets:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh
Doit-il être exécuté en GMT0 / -x?
l4m2
2

Nettoyer , 205 189 octets

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)

Essayez-le en ligne!

Οurous
la source
1
Première réponse qui n'utilise pas la gestion des dates intégrée. Agréable!
Adám
1

APL (Dyalog Classic) , 31 octets

Fonction de préfixe tacite anonyme. Renvoie la date comme[Y,M,D]

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

Essayez-le en ligne!

× signe du code de date

⊢- soustrayez cela de l'argument (le code de date)

60∘>+ incrémenter si le code de date est supérieur à soixante

2⎕NQ#263, utilisez-le comme argument immédiat pour "événement 263" (IDN à ce jour)
IDN est exactement comme le code de date d'Excel, mais sans le 29 février 1900 et la veille du 1er janvier 1900 est le 31 décembre 1899

3↑ prendre les trois premiers éléments de cela (le quatrième est le jour de la semaine)

()+ Ajoutez ce qui suit à ceux-ci:

60∘≠ 0 si le code de date est 60; 1 si le code de date n'est pas 60

×- soustrayez cela du signe du code de date

¯3↑ prendre les trois derniers éléments (il n'y en a qu'un) remplissage avec (deux) zéros

développé en collaboration avec @ Adám dans le chat

ngn
la source
1

C # (.NET Core) , 186185 octets

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

Essayez-le en ligne!


-1 octet en remplaçant l'opérateur OR (||) par l'opérateur OR binaire (|).

cobaltp
la source
0

T-SQL, 141 95 94 octets

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

Le saut de ligne est uniquement pour la lisibilité.

L'entrée est prise via la table préexistante i avec le champ entier n , selon nos normes IO .

SQL utilise un point de départ similaire (mais corrigé) 1-1-1900 pour son format de date interne, je n'ai donc qu'à le compenser de 1 ou 2 jours dans le DATEADD fonction.

SQL ne peut pas sortir une colonne contenant un mélange de valeurs de date et de caractère, donc je ne peux pas laisser la FORMATcommande (car elle essaierait alors de convertir1/0/1900 en une date, ce qui est bien sûr invalide).

Ce qui est bien avec SQL, c'est que je peux charger toutes les valeurs d'entrée dans la table et les exécuter toutes en même temps. Ma localité (US) utilise par défaut un m/d/yyyyformat de date:

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 : économisé 46 octets en passant à un imbriqué IIF()au lieu du beaucoup plus verbeuxCASE WHEN .

EDIT 2 : Sauvegarde un autre octet en déplaçant le -devant du IIF.

BradC
la source