Kurzes Date ins Englische Langes Date

14

Konvertieren Sie das kurze Datumsformat in so wenig Byte wie möglich in das englische lange Datum.

Eingang

Die Eingabe erfolgt in Form einer Zeichenfolge mit Format yyyy-mm-dd, wobei das Auffüllen mit Nullen für alle Werte optional ist. Sie können davon ausgehen, dass dies syntaktisch korrekt ist, jedoch nicht unbedingt ein gültiges Datum. Negative Jahreswerte müssen nicht unterstützt werden.

Ausgabe

Sie müssen das Datum in das englische Langzeitformat konvertieren (z. B. 14th February 2017 . ). Hier ist kein Auffüllen zulässig.

Wenn das Datum ungültig ist (z 2011-02-29 ), muss dies auf irgendeine Weise erkannt werden. Das Auslösen einer Ausnahme ist zulässig.

Weitere Beispiele finden Sie weiter unten.

Testfälle

"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
quelle
5
Ist das Auffüllen mit Nullen erlaubt? aka 03rdstatt3rd
Value Ink
@ValueInk Wenn Sie meinen vorherigen Kommentar gelesen haben, ignorieren Sie ihn. Ich habe die Frage falsch verstanden. Das Auffüllen der Ausgabe mit Nullen ist nicht zulässig.
GarethPW
Sollten wir ein Jahr mit mehr als 4 Zeichen in Betracht ziehen (z. B. 10987-01-01)?
mdahmoune
@mdahmoune Sie müssen dies nur unterstützen, wenn es einfacher ist.
GarethPW
Was ist 2016-2-29?
Olivier Grégoire

Antworten:

5

PostgreSQL, 61 Zeichen

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

Prepared-Anweisung, übernimmt die Eingabe als Parameter.

Probelauf:

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.
Mann bei der Arbeit
quelle
Schön, ich wünschte, MS-SQL hätte den "th" Formatierungsstil erkannt.
BradC
In Anbetracht der Tatsache, dass Sie es geschafft haben, die Aufgabe mit den wenigsten Bytes ordnungsgemäß abzuschließen, ist Ihre Lösung der Gewinner!
GarethPW
Beeindruckend. Vielen Dank. Das ist völlig unerwartet. Ich habe bis jetzt nicht bemerkt, dass es keine speziellen Golfsprachen gibt. Eine Lösung nach nur einem Tag zu akzeptieren, ist jedoch ein bisschen bald.
Manatwork
@manatwork Ich habe mich gefragt, ob es ein bisschen früh sein könnte. Aber ich kann es bei Bedarf trotzdem ändern.
GarethPW
7

Python 3.6, 137 129 Bytes

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

Probieren Sie es online!

Uriel
quelle
3
%-dist die Version ohne Auffüllen %d, die Sie für die Formatierung von Zeichenfolgen anstelle von verwenden können {g[2]}. Auch 12sollten sich 12thnicht 12nd(Nummern 10 bis 19 nicht den gleichen Regeln wie 1-9 folgen und 20+)
Wert Ink
1
+1. wusste nichts über die fSaiten
Felipe Nardi Batista
@ ValueInk danke! Außerdem wurde das Problem
Uriel,
5

JavaScript (ES6), 142 140 Byte

Ausgänge NaNth Invalid Date für ungültige Daten.

Der Code für Ordnungszahlen wurde aus dieser Antwort angepasst .

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

darrylyeo
quelle
1
Gibt "1. März 2011" für 2011-2-29 in Chrome. Das kann eine schwierige Lösung sein.
Rick Hitchcock
5

Python 3.6 , 154 Bytes

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

Probieren Sie es online!(Stellen Sie den Eingabestream ein und führen Sie ihn aus.)

Dank guter Vorschläge von Kommentatoren unten.

Luke Sawczak
quelle
Sie können ein Byte speichern, indem Sie das Leerzeichen zwischen int(x)und forin Ihrer Listenkomponente entfernen .
Christian Dean
@ChristianDean Danke, fertig!
Luke Sawczak
(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')anstelle Ihrer aktuellen Bedingung für -3 Bytes.
Value Ink
@ ValueInk Leider wird das 31. produzieren. Eine andere Möglichkeit, es zu zerlegen, war 'th', wenn nicht 0 <b% 10 <4 oder 10 <b <14, aber es wurden keine Bytes gespeichert.
Luke Sawczak
In diesem Fall Missbrauch Typ Coversion. (3<b<21)+(23<b<31)für -1 Byte. Probieren Sie es online!
Value Ink
5

PHP, 87 Bytes

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

Laufen Sie als Pipe mit -Foder testen Sie es online . Gibt immer eine vierstellige Jahreszahl aus. scheitert seit Jahren> 9999.

keine Gültigkeitsprüfung, 35 Bytes:

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

Bash + Coreutils, 115 78

  • 2 Bytes gespart dank @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"

Probieren Sie es online aus .

Digitales Trauma
quelle
1
Es scheint , dass Zeichenfolge anstelle von Array mit einem wenig helfen würde: f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
Manatwork
1
Übrigens, Ihre Revision 1 inspirierte einen Bash-Tipp . ;)
manatwork
@manatwork ja - es ist lustig - ich dachte darüber nach, es zu versuchen, dachte aber nicht, dass es helfen würde. Danke für den Schubs.
Digital Trauma
4

C #, 147 143 Bytes

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 Bytes dank @The_Lone_Devil eingespart.

TheLethalCoder
quelle
Könnten Sie das zweite nicht ersetzen t.Daymit deiner 4 - Byte - Einsparung?
The_Lone_Devil
@The_Lone_Devil Natürlich könnte ich mich bedanken, weiß nicht wie ich das verpasst habe.
TheLethalCoder
4

mIRC Version 7.49 (197 Bytes)

//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
quelle
3

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

Verwendet -rdate -p Programmflags.

-1 Byte von Handarbeit.

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

Probieren Sie es online!

Wert Tinte
quelle
Fehlt mir ein Grund, warum Sie keinen ternären Operator verwendet haben? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
Manatwork
@manatwork Eine Zahl wie 26versucht, auf Indizes 12..13in der außerhalb der Grenzen liegenden Suchzeichenfolge zuzugreifen , und gibt diese zurück nil. Somit macht es d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th"die Verwendung des Ternären , das um 2 Bytes länger ist.
Value Ink
Ah ich sehe. Na dann geiler Trick @ValueInk.
Manatwork
Fast vergessen, eine kleine Veränderung: "th":th.
Manatwork
2

C # (.NET Core) , 167 bis 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

Probieren Sie es online!

+30 Bytes für

using System;

DateTime.Parse()

kakkarot
quelle
Sie können die ternäre Prüfung umkehren, um das !für -1 Byte zu entfernen. Und Sie können das ändern , &&um &für -3 Bytes. Da Sie s.Day7-mal verwenden, werden einige Bytes gespart, um einen temporären Wert dafür zu erstellen: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 Danke!
Kakkarot
Sie müssen using System;das DateTimeObjekt auch einschließen oder vollständig qualifizieren .
TheLethalCoder
Auch DateTime.MinValueist 1-1-1so glaube ich nicht , dass Sie , dass der Check benötigen. Das würde auch meinen vorherigen Punkt irrelevant machen.
TheLethalCoder
1
Die Eingabe als DateTimeund das Parsen außerhalb der Methode ist nicht akzeptabel. Sie sollten die gesamte Arbeit innerhalb der Methode ausführen. Oder fügen Sie eine zusätzliche Methode hinzu, um die Arbeit abzuspalten.
TheLethalCoder
2

Excel, 212 Bytes

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

Wenn Sie es bei jedem kaufmännischen Und in Stücke teilen, erhalten Sie die folgenden Teile:

  • ABS()Ruft die Tageszahl aus den letzten beiden Zeichen der Zeichenfolge ab. Da dies einen Bindestrich enthalten kann, ABSwird dieser in einen positiven umgewandelt.
  • IF((ABS-12)<2,"th",SWITCH())fügt die Ordnungszahl hinzu. Das -12Bit ist , weil 11, 12 und 13 nicht der normale Regel folgen und sie alle bekommen thstatt st, ndund rd. Das korrigiert das.
    • Hinweis: Die SWITCHFunktion ist nur in Excel 2016 und höher verfügbar. ( Quelle ) Es ist kürzer als CHOOSEin diesem Fall, da es einen Wert zurückgeben kann, wenn keine Übereinstimmung gefunden wird, während CHOOSEeine numerische Eingabe erforderlich ist und für jeden möglichen Wert eine entsprechende Rückgabe erfolgen muss.
  • TEXT(MID()*30," mmmm ")extrahiert den Monatsnamen. MID()Zieht die Monatszahl als String heraus und multipliziert mit 30 ergibt sich eine Zahl. Excel sieht diese Zahl als Datum (1900-01-30, 1900-02-29, 1900-03-30 usw.) und TEXT()formatiert sie als Monatsnamen mit einem Leerzeichen an beiden Enden. 28 und 29 hätten auch geklappt aber 30 sieht "schöner" aus.
  • LEFT() extrahiert die Jahreszahl.

Angesichts dessen wäre es jetzt viel einfacher gewesen, wenn die Testfälle alle in einem Datumsbereich lagen, den Excel als aktuelles Datum behandeln kann: 1900-01-01 bis 9999-12-31. Der große Vorteil ist, dass das gesamte Datum auf einmal formatiert wird. Diese Lösung ist 133 Bytes :

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

Die andere große Hürde bestand darin, die Ordnungszahl aufzunehmen. Ohne das ist die Lösung nur 34 Bytes :

=TEXT(DATEVALUE(A1),"d mmmm yyyy")
Ingenieur Toast
quelle
1

Schnelle 3: 298 Bytes

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

Probieren Sie es online!

A. Pooja
quelle
8
Willkommen auf der Seite! Hier ist das Ziel, den Code so kurz wie möglich zu machen. Ich kann sehen, dass Sie lange Variablennamen und viele Leerzeichen haben. Sie können diese verkürzen und entfernen, um viele Bytes zu sparen. Wir fügen in der Regel auch eine Überschrift in Form von oben in die Antwort ein # Language, N bytes. Es wäre gut, wenn Sie auch eine hinzufügen könnten.
TheLethalCoder
1

T-SQL, 194 Bytes

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

Die Eingabe erfolgt über Textspalte i in vorbestehenden Tabelle t , gemäß unseren IO - Standards .

Funktioniert für Daten vom 1. Januar 0001 bis zum 31. Dezember 9999. Das Jahr wird mit mindestens 3 Ziffern ausgegeben (pro 150AD-Beispiel).

Ungültige Daten führen zu folgendem hässlichen Fehler:

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

Unterschiedliche Standardeinstellungen für Sprache / Kultur können dieses Verhalten ändern. Wenn Sie einen etwas anmutigen Fehlerausgang (NULL) mögen, fügen Sie 4 Bytes durch Änderung PARSE()zu TRY_PARSE().

Format und Erklärung:

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

Der DATEin SQL 2008 eingeführte Datentyp ermöglicht einen viel größeren Bereich als DATETIMEvom 1. Januar 0001 bis zum 31. Dezember 9999.

Einige sehr frühe Daten können mit meinen US-Ländereinstellungen falsch analysiert werden ("01-02-03" wird zu "Jan 2 2003"), daher habe ich ein paar zusätzliche Nullen vorangestellt, damit festgestellt wird, dass der erste Wert das Jahr ist.

Danach ist es nur eine unordentliche CASEAnweisung, dem Tag das Ordnungssuffix hinzuzufügen. Es ist ärgerlich, dass der SQL- FORMATBefehl dies nicht automatisch ausführen kann.

BradC
quelle
1

q / kdb + 210 Bytes, nicht konkurrierend

Lösung:

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

Beispiele:

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

Erläuterung:

Dies ist eine schreckliche Herausforderung, da es keine Datumsformatierung gibt. Daher muss ich Monate von Grund auf neu erstellen (95 Byte) und das Suffix generieren.

Ungolfed Lösung ist unten, teilen Sie im Grunde die Eingabezeichenfolge und verbinden Sie sich dann wieder, nachdem wir das Suffix hinzugefügt und den Monat umgestellt haben.

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

Anmerkungen:

Die Daten in q gehen nur auf ~ 1709 zurück, sodass ich keine einfache Möglichkeit habe, das Datum zu validieren. Daher ist dies ein nicht konkurrierender Eintrag. Das Beste, was ich tun kann, ist zu überprüfen, ob der Tag> 31 oder der Monat ist > 12 und gebe 0 zurück.

Streetster
quelle