Krótka data na angielski Długa data


14

Konwertuj format krótkiej daty na angielską długą datę w jak najmniejszej liczbie bajtów.

Wejście

Dane wejściowe będą miały postać łańcucha o formacie yyyy-mm-dd, z opcjonalnym wypełnieniem zerowym dla wszystkich wartości. Możesz założyć, że jest to poprawna składniowo, ale niekoniecznie poprawna data. Ujemne wartości roku nie muszą być obsługiwane.

Wynik

Musisz przekonwertować datę na angielski format długiej daty (np 14th February 2017.). Wypełnianie zera tutaj jest niedozwolone.

Jeśli data jest nieprawidłowa (np. 2011-02-29), Należy ją w jakiś sposób rozpoznać. Zgłaszanie wyjątku jest dozwolone.

Więcej przykładów można zobaczyć poniżej.

Przypadki testowe

"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
Czy dozwolone jest wypełnianie zerami? aka 03rdzamiast3rd
Value Ink

@ValueInk Jeśli czytasz mój poprzedni komentarz, zignoruj ​​go; Źle zrozumiałem pytanie. Zero padding na wyjściu jest niedozwolone.
GarethPW

Czy powinniśmy rozważyć rok na więcej niż 4 znaki (np. 10987-01-01)?
mdahmoune

@mdahmoune Nie musisz tego wspierać, chyba że jest to łatwiejsze.
GarethPW

Co 2016-2-29?
Olivier Grégoire

Odpowiedzi:


5

PostgreSQL, 61 znaków

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

Przygotowana instrukcja przyjmuje dane wejściowe jako parametr.

Przykładowy przebieg:

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.

Fajnie, szkoda, że ​​MS-SQL rozpoznaje styl formatowania „th”.
BradC

Biorąc pod uwagę, że udało ci się poprawnie wykonać zadanie przy jak najmniejszej liczbie bajtów, przypuszczam, że twoje rozwiązanie jest zwycięzcą!
GarethPW

Łał. Dzięki. To zupełnie nieoczekiwane. Do tej pory nie zauważyłem braku dedykowanych języków golfowych. Jednak akceptacja rozwiązania już po jednym dniu jest trochę szybka.
manatwork

@manatwork Zastanawiałem się, czy to może być trochę za wcześnie. Ale i tak mogę to zmienić.
GarethPW

7

Python 3.6, 137 129 bajtów

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

Wypróbuj online!


3
%-djest wersją bez wypełniania %d, której można używać w formatowaniu ciągów zamiast {g[2]}. Ponadto, 12powinno stać 12th, a nie 12nd(numery od 10-19 nie przestrzegają tych samych zasad jak 1-9 i 20+)
Value Ink

1
+1. nie wiedziałem o fstrunach
Felipe Nardi Batista

@ValueInk dzięki! naprawiono także błąd porządkowy
Uriel

5

JavaScript (ES6), 142 140 bajtów

Dane wyjściowe NaNth Invalid Datedla nieprawidłowych dat.

Kod liczb porządkowych został dostosowany z tej odpowiedzi .

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


1
Daje „1 marca 2011” dla 2011-2-29 w Chrome. To może być trudne rozwiązanie.
Rick Hitchcock

5

Python 3.6 , 154 bajty

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

Wypróbuj online! (Ustaw strumień wejściowy, a następnie uruchom.)

Dzięki dobrym sugestiom komentujących poniżej.


Możesz zapisać bajt, usuwając spację między int(x)i forna liście komp.
Christian Dean

@ChristianDean Dzięki, gotowe!
Łukasz Sawczak

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')zamiast obecnego warunkowego dla -3 bajtów.
Wartość tuszu

@ValueInk Niestety, wyprodukuje 31 pozycję. Innym sposobem, w jaki myślałem o podziale, było „th”, jeśli nie 0 <b% 10 <4 lub 10 <b <14, ale nie oszczędzało to żadnych bajtów.
Łukasz Sawczak

W takim przypadku należy użyć typu „nadużycie”. (3<b<21)+(23<b<31)dla -1 bajtu. Wypróbuj online!
Wartość tuszu

5

PHP, 87 bajtów

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

Uruchom jako potok -Flub przetestuj go online . Zawsze drukuje 4-cyfrowy rok; zawodzi przez lata> 9999.

brak kontroli ważności, 35 bajtów:

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

5

Bash + coreutils, 115 78

  • 2 bajty zapisane dzięki @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"

Wypróbuj online .


1
Wydaje się, że przy użyciu ciąg zamiast tablicy pomogłoby trochę: f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
manatwork

1
BTW, twoja wersja 1 zainspirowała wskazówkę Bash . ;)
manatwork

@manatwork tak - to zabawne - rozważałem wypróbowanie tego, ale nie sądziłem, że to pomoże. Dzięki za szturchnięcie.
Cyfrowa trauma

4

C #, 147 143 bajtów

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

Zaoszczędzono 4 bajty dzięki @The_Lone_Devil.


Mógłbyś nie zastąpi drugiego t.Dayzd dla oszczędzania 4 bajtów?
The_Lone_Devil

@The_Lone_Devil Oczywiście, że mogłem podziękować, nie wiem, jak mi tego brakowało.
TheLethalCoder

4

Wersja mIRC 7.49 (197 bajtów)

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

Rubin , 104 103 102 + 8 = 112 111 110 bajtów

Wykorzystuje -rdate -pflagi programu.

-1 bajt z manatwork.

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

Wypróbuj online!


Czy brakuje mi powodu, dla którego nie użyłeś operatora trójskładnikowego? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
manatwork

@manatwork Liczba taka jak 26spróbuje uzyskać dostęp do indeksów 12..13w ciągu wyszukiwania, który jest poza zakresem, a zatem zwraca nil. Zatem użycie trójskładnika sprawia, że d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th"jest on dłuższy o 2 bajty.
Wartość tuszu

O, rozumiem. No to fajna sztuczka @ ValueInk.
manatwork

Prawie zapomniałem, drobna zmiana: "th":th.
manatwork

2

C # (.NET Core) , 167 197 bajtów

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

Wypróbuj online!

+30 bajtów dla

using System;

DateTime.Parse()


Możesz odwrócić kontrolę trójskładnikową, aby pozbyć się !bajtu dla -1. Można zmienić &&, aby &do -3 bajtów. Ponadto, ponieważ używasz s.Day7 razy, oszczędza to kilka bajtów, aby utworzyć dla niego wartość tymczasową: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 Thanks!
kakkarot

Musisz także dołączyć using System;lub w pełni zakwalifikować DateTimeobiekt.
TheLethalCoder

Również DateTime.MinValuejest 1-1-1więc nie sądzę, trzeba ten czek. Co sprawiłoby, że mój poprzedni punkt byłby nieistotny.
TheLethalCoder

1
Przyjmowanie danych wejściowych jako DateTimei analizowanie poza metodą jest niedopuszczalne, powinieneś wykonać całą pracę wewnątrz metody. Lub dodaj dodatkową metodę podziału pracy.
TheLethalCoder

2

Excel, 212 bajtów

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

Jeśli podzielisz go na kawałki na każdym znaku handlowego, otrzymasz następujące elementy:

  • ABS()pobiera liczbę dni z dwóch ostatnich znaków w ciągu. Ponieważ może zawierać łącznik, ABSkonwertuje go na dodatni.
  • IF((ABS-12)<2,"th",SWITCH())dodaje porządek. -12Nieco dlatego, 11, 12 i 13 nie stosują normalnej regułę i oni wszyscy się thzamiast st, ndi rd. To poprawia to.
    • Uwaga: SWITCHfunkcja jest dostępna tylko w programie Excel 2016 i nowszych. ( Źródło ) Jest krótszy niż CHOOSEw tym przypadku, ponieważ może zwrócić wartość, jeśli nie zostanie znalezione dopasowanie, podczas gdy CHOOSEwymaga wprowadzania danych liczbowych i musi mieć odpowiedni zwrot dla każdej możliwej wartości.
  • TEXT(MID()*30," mmmm ")wyodrębnia nazwę miesiąca. MID()wyciąga liczbę miesięcy jako ciąg znaków i pomnożenie przez 30 zwraca liczbę. Excel widzi tę liczbę jako datę (1900-01-30, 1900-02-29, 1900-03-30 itd.) I TEXT()formatuje ją jako nazwę miesiąca ze spacją na obu końcach. 28 i 29 też by działały, ale 30 wygląda „ładniej”.
  • LEFT() wyodrębnia numer roku.

Biorąc to wszystko pod uwagę, byłoby znacznie łatwiej, gdyby wszystkie przypadki testowe znajdowały się w zakresie dat, który Excel może obsłużyć jako rzeczywistą datę: od 1900-01-01 do 9999-12-31. Dużą zaletą jest to, że cała data jest formatowana jednocześnie. To rozwiązanie ma 133 bajty :

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

Inną dużą przeszkodą było uwzględnienie porządkowej. Bez tego rozwiązanie ma tylko 34 bajty :

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

1

Swift 3: 298 bajtów

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

Wypróbuj online!


8
Witamy na stronie! Tutaj celem jest, aby kod był jak najkrótszy. Widzę, że masz długie nazwy zmiennych i dużo białych znaków, możesz je skracać i usuwać, aby zaoszczędzić dużo bajtów. Zazwyczaj dołączamy również nagłówek u góry odpowiedzi w postaci # Language, N bytes. Byłoby dobrze, gdybyś mógł dodać jeszcze jeden.
TheLethalCoder

1

T-SQL, 194 bajty

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

Dane wejściowe są wprowadzane za pomocą kolumny tekstowej i w istniejącej tabeli t , zgodnie z naszymi standardami we / wy .

Działa dla dat od 1 stycznia 0001 do 31 grudnia 9999. Rok jest generowany z co najmniej 3 cyframi (na przykład 150AD).

Nieprawidłowe daty spowodują następujący brzydki błąd:

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

Różne domyślne ustawienia języka / kultury mogą zmienić to zachowanie. Jeśli chcesz nieco bardziej płynnego wyjścia błędu (NULL), dodaj 4 bajty, zmieniając PARSE()na TRY_PARSE().

Format i objaśnienie:

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

Typ DATEdanych wprowadzony w SQL 2008 pozwala na znacznie szerszy zakres niż DATETIMEod 1 stycznia 0001 do 31 grudnia 9999.

Niektóre bardzo wczesne daty mogą zostać błędnie przeanalizowane w moich ustawieniach lokalizacji w USA („01-02-03” zmienia się na „2 stycznia 2003 r.”), Więc przygotowałem kilka dodatkowych zer, aby wiedzieć, że pierwszą wartością jest rok.

Potem jest to tylko niechlujne CASEstwierdzenie, aby dodać porządkowy przyrostek do dnia. Irytujące jest to, że FORMATpolecenie SQL nie ma możliwości zrobienia tego automatycznie.


1

q / kdb + 210 bajtów, niekonkurujące

Rozwiązanie:

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

Przykłady:

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

Wyjaśnienie:

To straszne wyzwanie, ponieważ nie ma formatowania daty, więc muszę tworzyć miesiące od zera (95 bajtów), a także generować przyrostek.

Niegolfowane rozwiązanie jest poniżej, w zasadzie podziel ciąg wejściowy, a następnie połącz ponownie, po dodaniu sufiksu i zmianie miesiąca.

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

Uwagi:

Daty w q wracają tylko do ~ 1709, więc nie mam trywialnego sposobu na sprawdzenie daty, dlatego jest to niekonkurencyjny wpis ... Najlepsze, co mogę zrobić, to sprawdzić, czy dzień ma> 31, czy miesiąc > 12 i zwróć 0.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.