Date courte en anglais Date longue

14

Convertissez le format de date courte en date longue en anglais en aussi peu d'octets que possible.

Contribution

L'entrée sera sous la forme d'une chaîne de format yyyy-mm-dd, avec un remplissage nul en option pour toutes les valeurs. Vous pouvez supposer que c'est syntaxiquement correct, mais pas nécessairement une date valide. Les valeurs d'année négatives n'ont pas besoin d'être prises en charge.

Production

Vous devez convertir la date au format anglais de date longue (par exemple 14th February 2017). Le remplissage nul ici n'est pas autorisé.

Si la date n'est pas valide (par exemple 2011-02-29), cela doit être reconnu d'une manière ou d'une autre. Le lancement d'une exception est autorisé.

Plus d'exemples peuvent être vus ci-dessous.

Cas de test

"1980-05-12" -> 12th May 1980
"2005-12-3"  -> 3rd December 2005
"150-4-21"   -> 21st April 150
"2011-2-29"  -> (error/invalid)
"1999-10-35" -> (error/invalid)
GarethPW
la source
5
Le remplissage nul est-il autorisé? alias 03rdau lieu de3rd
Value Ink
@ValueInk Si vous lisez mon commentaire précédent, ignorez-le; J'ai mal compris la question. Le remplissage nul dans la sortie n'est pas autorisé.
GarethPW
Faut-il considérer une année sur plus de 4 caractères (par exemple 10987-01-01)?
mdahmoune
@mdahmoune Vous n'avez pas besoin de prendre en charge cela, sauf si c'est plus facile à faire.
GarethPW
Et alors 2016-2-29?
Olivier Grégoire

Réponses:

5

PostgreSQL, 61 caractères

prepare f(date)as select to_char($1,'fmDDth fmMonth fmYYYY');

Instruction préparée, prend l'entrée comme paramètre.

Exemple d'exécution:

Tuples only is on.
Output format is unaligned.
psql (9.6.3, server 9.4.8)
Type "help" for help.

psql=# prepare f(date)as select to_char($1,'fmDDth fmMonth fmYYYY');
PREPARE

psql=# execute f('1980-05-12');
12th May 1980

psql=# execute f('2005-12-3');
3rd December 2005

psql=# execute f('150-4-21');
21st April 150

psql=# execute f('2011-2-29');
ERROR:  date/time field value out of range: "2011-2-29"
LINE 1: execute f('2011-2-29');
                  ^
psql=# execute f('1999-10-35');
ERROR:  date/time field value out of range: "1999-10-35"
LINE 1: execute f('1999-10-35');
                  ^
HINT:  Perhaps you need a different "datestyle" setting.
homme au travail
la source
Bien, j'aimerais que MS-SQL reconnaisse le style de formatage "th".
BradC
Étant donné que vous avez réussi à terminer la tâche correctement avec le moins d'octets, je suppose que votre solution est gagnante!
GarethPW
Sensationnel. Merci. C'est complètement inattendu. Je n'ai pas remarqué jusqu'à présent l'absence de langues dédiées au golf. Cependant, accepter une solution après une seule journée est un peu rapide.
manatwork
@manatwork Je me suis demandé si ça pourrait être un peu tôt. Mais je peux le changer si besoin est de toute façon.
GarethPW
7

Python 3.6, 137 129 octets

from datetime import*
def f(k):g=[*map(int,k.split('-'))];n=g[2];return f"{date(*g):%-d{'tsnrhtdd'[n%5*(n^15>4>n%10)::4]} %B %Y}"

Essayez-le en ligne!

Uriel
la source
3
%-dest la version sans rembourrage %dque vous pouvez utiliser dans votre mise en forme de chaîne au lieu de {g[2]}. En outre, 12devrait devenir 12thnon 12nd(les nombres de 10 à 19 ne suivent pas les mêmes règles que 1-9 et 20+)
Value Ink
1
+1. ne connaissait pas les fcordes
Felipe Nardi Batista
@ValueInk merci! également, corrigé le problème des ordinaux
Uriel
5

JavaScript (ES6), 142 140 octets

Sorties NaNth Invalid Datepour des dates non valides.

Le code des nombres ordinaux a été adapté de cette réponse .

d=>`${s=(D=new Date(d)).getDate()+''}${[,'st','nd','rd'][s.match`1?.$`]||'th'} `+D.toLocaleDateString('en-GB',{month:'long',year:'numeric'})

darrylyeo
la source
1
Donne "1er mars 2011" pour le 29-2-2011 dans Chrome. Cela peut être une solution difficile.
Rick Hitchcock
5

Python 3.6 , 154 octets

from datetime import*
s=[*map(int,input().split('-'))]
b=s[2]
print(date(*s).strftime(f"%-d{'th'if(3<b<21)+(23<b<31)else('st','nd','rd')[b%10-1]} %B %Y"))

Essayez-le en ligne! (Définissez le flux d'entrée, puis exécutez.)

Merci aux bonnes suggestions des commentateurs ci-dessous.

Luke Sawczak
la source
Vous pouvez enregistrer un octet en supprimant l'espace entre int(x)et fordans votre liste de composition.
Christian Dean
@ChristianDean Merci, c'est fait!
Luke Sawczak
(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')au lieu de votre conditionnelle actuelle pour -3 octets.
Value Ink
@ValueInk Malheureusement, cela produira le 31ème. Une autre façon de penser à le décomposer était «th» sinon 0 <b% 10 <4 ou 10 <b <14 mais cela n'a pas sauvé d'octets.
Luke Sawczak
Dans ce cas, abusez de la coersion de type. (3<b<21)+(23<b<31)pour -1 octet. Essayez-le en ligne!
Value Ink
5

PHP, 87 octets

<?=checkdate(($a=explode("-",$argn))[1],$a[2],$a[0])?date("jS F Y",strtotime($argn)):E;

Exécuter en tant que pipe avec -Fou tester en ligne . Imprime toujours une année à 4 chiffres; échoue pendant des années> 9999.

pas de contrôle de validité, 35 octets:

<?=date("jS F Y",strtotime($argn));
Titus
la source
5

Bash + coreutils, 115 78

  • 2 octets enregistrés grâce à @manatwork.
d="date -d$1 +%-e"
t=`$d`
f=thstndrd
$d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y"

Essayez-le en ligne .

Traumatisme numérique
la source
1
Il semble que l' utilisation de la chaîne au lieu d' un tableau aiderait un peu: f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
manatwork
1
BTW, votre révision 1 a inspiré une astuce Bash . ;)
manatwork
@manatwork oui - c'est drôle - j'ai envisagé d'essayer mais je ne pensais pas que cela aiderait. Merci pour le coup de coude.
Digital Trauma
4

C #, 147 143 octets

s=>{var t=System.DateTime.Parse(s);int d=t.Day,o=d%10;return d+((d/10)%10==1?"th":o==1?"st":o==2?"nd":o==3?"rd":"th")+t.ToString(" MMMM yyy");}

4 octets enregistrés grâce à @The_Lone_Devil.

TheLethalCoder
la source
Ne pourriez-vous pas remplacer le second t.Daypar dune sauvegarde de 4 octets?
The_Lone_Devil
@The_Lone_Devil Bien sûr, je pourrais vous remercier, je ne sais pas comment j'ai raté ça.
TheLethalCoder
4

mIRC version 7.49 (197 octets)

//tokenize 45 2-2-2 | say $iif($3 isnum 1- $iif($2 = 2,$iif(4 // $1 && 25 \\ $1||16//$1,29,28),$iif($or($2,6) isin 615,30,31))&&$2 isnum1-12&&1//$1,$asctime($ctime($+($1,-,$2,-,$3)date), doo mmmm yyyy))
OS
la source
3

Ruby , 104 103 102 + 8 = 112 111 110 octets

Utilise -rdate -ples indicateurs de programme.

-1 octet de manatwork.

sub(/.*-(\d*)/){Date.parse($&).strftime"%-d#{d=eval$1;(d<4||d>20)&&"..stndrd"[d%10*2,2]||:th} %B %-Y"}

Essayez-le en ligne!

Encre de valeur
la source
Est-ce que je manque une raison pour laquelle vous n'avez pas utilisé d'opérateur ternaire? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
manatwork
@manatwork Un nombre comme 26va essayer d'accéder aux index 12..13dans la chaîne de recherche, qui est hors limites, et revient donc nil. Ainsi, l'utilisation du ternaire le rend d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th", qui est plus long de 2 octets.
Value Ink
Ah, je vois. Eh bien, alors truc cool @ValueInk.
manatwork
Presque oublié, un tout petit changement: "th":th.
manatwork
2

C # (.NET Core) , 167 197 octets

s=>s.Equals(DateTime.MinValue)?"":s.Day+((s.Day%10==1&s.Day!=11)?"st":(s.Day%10==2&s.Day!=12)?"nd":(s.Day%10==3&s.Day!=13)?"rd":"th")+" "+s.ToString("MMMM")+" "+s.Year

Essayez-le en ligne!

+30 octets pour

using System;

DateTime.Parse()

kakkarot
la source
Vous pouvez inverser le contrôle ternaire pour supprimer le !for -1 byte. Et vous pouvez changer la &&à &de -3 octets. De plus, comme vous l'utilisez s.Day7 fois, il enregistre quelques octets pour créer une valeur temporaire pour lui:s=>{var t=s.Day;return s.Equals(DateTime.MinValue)?"":t+((t%10==1&t!=11)?"st":(t%10==2&t!=12)?"nd":(t%10==3&t!=13)?"rd":"th")+" "+s.ToString("MMMM")+" "+s.Year;}
Kevin Cruijssen
@KevinCruijssen Merci!
kakkarot
Vous devez également inclure using System;ou qualifier entièrement l' DateTimeobjet.
TheLethalCoder
Aussi DateTime.MinValueest 1-1-1donc je ne pense pas que vous avez besoin que l' enregistrement. Ce qui rendrait également mon point précédent non pertinent.
TheLethalCoder
1
Prendre l'entrée en tant que DateTimeet analyser en dehors de la méthode n'est pas acceptable, vous devez faire tout le travail à l'intérieur de la méthode. Ou ajoutez une méthode supplémentaire pour diviser le travail.
TheLethalCoder
2

Excel, 212 octets

=ABS(RIGHT(A1,2))&IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th"))&TEXT(MID(A1,FIND("-",A1)+1,FIND("-",REPLACE(A1,1,FIND("-",A1),""))-1)*30," mmmm ")&LEFT(A1,FIND("-",A1)-1)

Si vous le divisez en morceaux à chaque esperluette, vous obtenez ces pièces:

  • ABS()extrait le numéro du jour des deux derniers caractères de la chaîne. Comme cela peut inclure un trait d'union, le ABSconvertit en positif.
  • IF((ABS-12)<2,"th",SWITCH())ajoute l'ordinal. Le -12bit est parce que 11, 12 et 13 ne suivent pas la règle normale et ils obtiennent tous thau lieu de st,nd et rd. Cela corrige cela.
    • Remarque: La SWITCHfonction est uniquement disponible dans Excel 2016 et versions ultérieures. ( Source ) Il est plus court que CHOOSEdans ce cas car il peut renvoyer une valeur si aucune correspondance n'est trouvée alors qu'il CHOOSEnécessite une entrée numérique et doit avoir un retour correspondant pour chaque valeur possible.
  • TEXT(MID()*30," mmmm ")extrait le nom du mois. MID()extrait le numéro du mois sous forme de chaîne et multiplier par 30 renvoie un nombre. Excel voit ce nombre comme une date (1900-01-30, 1900-02-29, 1900-03-30, etc.) et le TEXT()formate comme un nom de mois avec un espace aux deux extrémités. 28 et 29 auraient également fonctionné mais 30 semble "plus joli".
  • LEFT() extrait le numéro de l'année.

Maintenant, étant donné tout cela, il aurait été beaucoup plus facile si les cas de test se trouvaient tous dans une plage de dates qu'Excel peut gérer comme une date réelle: 1900-01-01 à 9999-12-31. Le gros avantage est que la date entière est formatée à la fois. Cette solution est de 133 octets :

=TEXT(DATEVALUE(A1),"d""" & IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th")) & """ mmmm yyyy")

L'autre grand obstacle devait inclure l'ordinal. Sans cela, la solution ne fait que 34 octets :

=TEXT(DATEVALUE(A1),"d mmmm yyyy")
Ingénieur Toast
la source
1

Swift 3: 298 octets

let d=DateFormatter()
d.dateFormat="yyyy-MM-dd"
if let m=d.date(from:"1999-10-3"){let n=NumberFormatter()
n.numberStyle = .ordinal
let s=n.string(from:NSNumber(value:Calendar.current.component(.day, from:m)))
d.dateFormat="MMMM YYY"
print("\(s!) \(d.string(from:m))")}else{print("(error/invalid)")}

Essayez-le en ligne!

A. Pooja
la source
8
Bienvenue sur le site! Ici, l'objectif est de rendre le code aussi court que possible, je peux voir que vous avez de longs noms de variables et beaucoup d'espace, vous pouvez les raccourcir et les supprimer pour économiser beaucoup d'octets. Nous incluons également généralement un en-tête en haut de la réponse sous la forme de # Language, N bytes. Ce serait bien si vous pouviez en ajouter un aussi.
TheLethalCoder
1

T-SQL, 194 octets

DECLARE @ DATE;SELECT @=PARSE('00'+i AS DATE)FROM t;PRINT DATENAME(d,@)+CASE WHEN DAY(@)IN(1,21,31)THEN'st'WHEN DAY(@)IN(2,22)THEN'nd'WHEN DAY(@)IN(3,23)THEN'rd'ELSE'th'END+FORMAT(@,' MMMM yyy')

L'entrée se fait via la colonne de texte i dans le tableau préexistant t , selon nos normes IO .

Fonctionne pour les dates du 1er janvier 0001 au 31 décembre 9999. L'année est sortie avec au moins 3 chiffres (par exemple 150AD).

Des dates non valides entraîneront l'erreur laide suivante:

Error converting string value 'foo' into data type date using culture ''.

Différents paramètres de langue / culture par défaut peuvent modifier ce comportement. Si vous voulez une sortie d'erreur légèrement plus gracieuse (NULL), ajoutez 4 octets en changeant PARSE()en TRY_PARSE().

Format et explication:

DECLARE @ DATE;
SELECT @=PARSE('00'+i AS DATE)FROM t;
PRINT DATENAME(d,@) + 
    CASE WHEN DAY(@) IN (1,21,31) THEN 'st'
         WHEN DAY(@) IN (2,22)    THEN 'nd'
         WHEN DAY(@) IN (3,23)    THEN 'rd'
         ELSE 'th' END
    + FORMAT(@, ' MMMM yyy')

Le DATEtype de données introduit dans SQL 2008 permet une plage beaucoup plus large que DATETIME, du 1er janvier 0001 au 31 décembre 9999.

Certaines dates très précoces peuvent être mal analysées avec mes paramètres de localité aux États-Unis (le "01-02-03" devient le "2 janvier 2003"), j'ai donc ajouté quelques zéros supplémentaires pour qu'il sache que la première valeur est l'année.

Après cela, c'est juste une CASEdéclaration désordonnée pour ajouter le suffixe ordinal à la journée. De façon ennuyeuse, la FORMATcommande SQL n'a aucun moyen de le faire automatiquement.

BradC
la source
1

q / kdb + 210 octets, non concurrents

Solution:

f:{a:"I"$"-"vs x;if[(12<a 1)|31<d:a 2;:0];" "sv(raze($)d,$[d in 1 21 31;`st;d in 2 22;`nd;d in 3 23;`rd;`th];$:[``January`February`March`April`May`June`July`August`September`October`November`December]a 1;($)a 0)};

Exemples:

q)f "2017-08-03"
"3rd August 2017"
q)f "1980-05-12"
"12th May 1980"
q)f "2005-12-3"
"3rd December 2005"
q)f "150-4-21" 
"21st April 150"
q)f "2011-2-29"       / yes it's wrong :(
"29th February 2011"
q)f "1999-10-35"
0

Explication:

C'est un défi horrible car il n'y a pas de formatage de date, donc je dois créer des mois à partir de zéro (95 octets) ainsi que générer le suffixe.

La solution non golfée est ci-dessous, divise essentiellement la chaîne d'entrée, puis se réunit à nouveau après avoir ajouté le suffixe et changé le mois.

f:{
   // split input on "-", cast to integers, save as variable a
   a:"I"$ "-" vs x;
   // if a[1] (month) > 12 or a[2] (day) > 31 return 0; note: save day in variable d for later
   if[(12<a 1) | 31<d:a 2;
     :0];
   // joins the list on " " (like " ".join(...) in python)
   " " sv (
           // the day with suffix
           raze string d,$[d in 1 21 31;`st;d in 2 22;`nd;d in 3 23;`rd;`th];
           // index into a of months, start with 0 as null, to mimic 1-indexing
           string[``January`February`March`April`May`June`July`August`September`October`November`December]a 1;
           // the year cast back to a string (removes any leading zeroes)
           string a 0)
  };

Remarques:

Les dates en q ne remontent qu'à ~ 1709, donc je n'ai pas de moyen trivial de valider la date, donc c'est une entrée non concurrente ... Le mieux que je puisse faire est de vérifier si le jour est> 31 ou le mois est > 12 et retournez 0.

streetster
la source