Data breve in inglese Data lunga


14

Converti il ​​formato della data breve in una data lunga inglese nel minor numero di byte possibile.

Ingresso

L'input avrà la forma di una stringa con formato yyyy-mm-dd, con zero padding opzionale per tutti i valori. Puoi presumere che questa sia sintatticamente corretta, ma non necessariamente una data valida. I valori degli anni negativi non devono essere supportati.

Produzione

È necessario convertire la data nel formato di data lunga inglese (ad es 14th February 2017.). L'imbottitura zero qui non è consentita.

Se la data non è valida (ad es. 2011-02-29), Questa deve essere riconosciuta in qualche modo. È ammessa l'eccezione.

Di seguito sono riportati altri esempi.

Casi 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)

5
È consentito lo zero padding? alias 03rdinvece di3rd
Value Ink il

@ValueInk Se leggi il mio commento precedente, ignoralo; Ho frainteso la domanda. Non è consentito il padding zero nell'output.
GarethPW,

Dovremmo considerare un anno con più di 4 caratteri (ad es. 10987-01-01)?
mdahmoune,

@mdahmoune Non è necessario supportarlo a meno che non sia più facile farlo.
GarethPW,

Che dire 2016-2-29?
Olivier Grégoire,

Risposte:


5

PostgreSQL, 61 caratteri

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

Istruzione preparata, accetta input come parametro.

Esecuzione di esempio:

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.

Bello, vorrei che MS-SQL riconoscesse lo stile di formattazione "th".
BradC,

Considerando che sei riuscito a completare correttamente l'attività con il minor numero di byte, suppongo che la tua soluzione sia il vincitore!
GarethPW,

Wow. Grazie. È del tutto inaspettato. Fino ad ora non ho notato l'assenza di linguaggi golfistici dedicati. Tuttavia, accettare una soluzione dopo solo un giorno è un po 'presto.
arte

@manatwork Mi chiedevo se potesse essere un po 'presto. Ma posso cambiarlo, se necessario, comunque.
GarethPW,

7

Python 3.6, 137 129 byte

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

Provalo online!


3
%-dè la versione senza padding %dche puoi usare nella formattazione della stringa anziché {g[2]}. Inoltre, 12dovrebbe diventare 12thno 12nd(i numeri da 10 a 19 non seguono le stesse regole di 1-9 e 20+)
Value Ink,

1
+1. non sapevo delle fcorde
Felipe Nardi Batista,

@ValueInk grazie! inoltre, risolto il problema degli ordinali
Uriel,

5

JavaScript (ES6), 142 140 byte

Output NaNth Invalid Dateper date non valide.

Il codice per i numeri ordinali è stato adattato da questa risposta .

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


1
Fornisce "1 marzo 2011" per il periodo 2011-2-29 in Chrome. Potrebbe essere una soluzione difficile.
Rick Hitchcock,

5

Python 3.6 , 154 byte

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

Provalo online!(Imposta il flusso di input ed esegui.)

Grazie ai buoni suggerimenti dei commentatori qui sotto.


È possibile salvare un byte rimuovendo lo spazio tra int(x)e fornell'elenco comp.
Christian Dean,

@ChristianDean Grazie, fatto!
Luke Sawczak,

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')invece dell'attuale condizione per -3 byte.
Value Ink

@ValueInk Purtroppo, produrrà il 31 °. Un altro modo in cui ho pensato di scomporlo era 'th' se non 0 <b% 10 <4 o 10 <b <14 ma non ha salvato alcun byte.
Luke Sawczak,

In tal caso, abuso di tipo coersion. (3<b<21)+(23<b<31)per -1 byte. Provalo online!
Value Ink

5

PHP, 87 byte

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

Esegui come pipe -Fo testalo online . Stampa sempre un anno a 4 cifre; fallisce per anni> 9999.

nessun controllo di validità, 35 byte:

<?=date("jS F Y",strtotime($argn));

5

Bash + coreutils, 115 78

  • 2 byte salvati grazie a @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"

Provalo online .


1
Sembra che l'utilizzo di stringa invece di matrice aiuterebbe un po ': f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
arte

1
A proposito, la tua revisione 1 ha ispirato un suggerimento Bash . ;)
arte

@manatwork sì - è divertente - ho pensato di provarlo ma non pensavo che sarebbe stato d'aiuto. Grazie per la spinta.
Digital Trauma,

4

C #, 147 143 byte

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

Salvato 4 byte grazie a @The_Lone_Devil.


Non potresti sostituire il secondo t.Daycon dun salvataggio di 4 byte?
The_Lone_Devil

@The_Lone_Devil Certo che potrei ringraziare, non so come mi sono perso.
TheLethalCoder

4

mIRC versione 7.49 (197 byte)

//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))

3

Rubino , 104 103 102 + 8 = 112 111 110 byte

Utilizza -rdate -pflag di programma.

-1 byte da manatwork.

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

Provalo online!


Mi manca un motivo per cui non hai usato l'operatore ternario? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
arte

@manatwork Un numero simile 26tenterà di accedere agli indici 12..13nella stringa di ricerca, che è fuori dai limiti, e quindi ritorna nil. Pertanto, l'uso del ternario lo rende d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th", che è più lungo di 2 byte.
Value Ink

Ah, capisco. Bene, allora bel trucco @ValueInk.
arte

Quasi dimenticato, un piccolo cambiamento: "th":th.
arte

2

C # (.NET Core) , 167 197 byte

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

Provalo online!

+30 byte per

using System;

DateTime.Parse()


È possibile invertire il controllo ternario per eliminare il !per -1 byte. E puoi cambiarlo &&in &per -3 byte. Inoltre, poiché si utilizza s.Day7 volte, vengono salvati alcuni byte per creare un valore temporaneo: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 Grazie!
Kakkarot,

È inoltre necessario includere using System;o qualificare completamente l' DateTimeoggetto.
TheLethalCoder

Inoltre DateTime.MinValueè 1-1-1così non credo è necessario che il check. Il che renderebbe anche irrilevante il mio punto precedente.
TheLethalCoder

1
Prendere input come DateTimeanalisi e analizzare al di fuori del metodo non è accettabile, dovresti fare tutto il lavoro all'interno del metodo. Oppure aggiungi un altro metodo per dividere il lavoro.
TheLethalCoder

2

Excel, 212 byte

=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)

Se lo spezzi in pezzi in ogni e commerciale, ottieni questi pezzi:

  • ABS()estrae il numero del giorno dagli ultimi due caratteri nella stringa. Dal momento che può includere un trattino, lo ABSconverte in positivo.
  • IF((ABS-12)<2,"th",SWITCH())aggiunge l'ordinale. Il fatto -12è che 11, 12 e 13 non seguono la regola normale e ottengono tutti thinvece di st,nd e rd. Questo corregge per quello.
    • Nota: la SWITCHfunzione è disponibile solo in Excel 2016 e versioni successive. ( Sorgente ) È più breve che CHOOSEin questo caso perché può restituire un valore se non viene trovata alcuna corrispondenza, mentre CHOOSErichiede un input numerico e deve avere un ritorno corrispondente per ogni possibile valore.
  • TEXT(MID()*30," mmmm ")estrae il nome del mese. MID()estrae il numero del mese come stringa e moltiplicandolo per 30 restituisce un numero. Excel vede quel numero come una data (1900-01-30, 1900-02-29, 1900-03-30, ecc.) ETEXT() formatta come un nome di mese con uno spazio su entrambe le estremità. Anche 28 e 29 avrebbero funzionato, ma 30 sembra "più bello".
  • LEFT() estrae il numero dell'anno.

Ora, dato tutto ciò, sarebbe stato molto più semplice se i casi di test fossero tutti in un intervallo di date che Excel può gestire come data effettiva: dal 1900-01-01 al 9999-12-31. Il grande vantaggio è che l'intera data viene formattata contemporaneamente. Tale soluzione è di 133 byte :

=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'altro grande ostacolo doveva includere l'ordinale. Senza questo, la soluzione è di soli 34 byte :

=TEXT(DATEVALUE(A1),"d mmmm yyyy")

1

Swift 3: 298 byte

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

Provalo online!


8
Benvenuti nel sito! Qui l'obiettivo è rendere il codice il più breve possibile, vedo che hai nomi di variabili lunghi e un sacco di spazi bianchi, puoi accorciarli e rimuoverli per risparmiare molti byte. Di solito includiamo anche un'intestazione nella parte superiore della risposta sotto forma di # Language, N bytes. Sarebbe bello se si potesse aggiungere anche uno.
TheLethalCoder

1

T-SQL, 194 byte

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'immissione avviene tramite la colonna di testo i nella tabella t preesistente , secondo i nostri standard IO .

Funziona per le date dal 1 gennaio 0001 al 31 dicembre 9999. L'anno viene prodotto con almeno 3 cifre (per esempio 150 dC).

Date non valide comporteranno il seguente brutto errore:

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

Diverse impostazioni di lingua / cultura predefinite potrebbero modificare questo comportamento. Se si desidera un output dell'errore leggermente più grazioso (NULL), aggiungere 4 byte cambiando PARSE()in TRY_PARSE().

Formato e spiegazione:

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')

Il DATEtipo di dati introdotto in SQL 2008 consente un intervallo molto più ampio rispetto DATETIMEal 1 gennaio 0001 al 31 dicembre 9999.

Alcune date molto precoci possono essere analizzate erroneamente con le mie impostazioni di località negli Stati Uniti ("01-02-03" diventa "2 gennaio 2003"), quindi ho anticipato un paio di zeri in più in modo che sappia che il primo valore è l'anno.

Dopodiché, è solo una CASEdichiarazione disordinata per aggiungere il suffisso ordinale al giorno. Stranamente, il FORMATcomando SQL non ha modo di farlo automaticamente.


1

q / kdb + 210 byte, non concorrenti

Soluzione:

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

Esempi:

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

Spiegazione:

Questa è una sfida orribile in quanto non esiste una formattazione della data, quindi devo creare mesi da zero (95 byte) oltre a generare il suffisso.

La soluzione non golfata è di seguito, sostanzialmente dividere la stringa di input e quindi ricollegarsi dopo aver aggiunto il suffisso e cambiato il mese.

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

Appunti:

Le date in q risalgono solo a ~ 1709, quindi non ho un modo banale di convalidare la data, quindi questa è una voce non competitiva ... Il meglio che posso fare è controllare se il giorno è> 31 o il mese è > 12 e restituisce 0.

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.