Tanggal Pendek ke Bahasa Inggris Tanggal Panjang

14

Ubah format tanggal pendek menjadi tanggal panjang Inggris dalam sesedikit mungkin byte.

Memasukkan

Input akan berupa string dengan format yyyy-mm-dd,, dengan nol bantalan opsional untuk semua nilai. Anda dapat berasumsi bahwa ini secara sintaksis benar, tetapi tidak harus tanggal yang valid. Nilai tahun negatif tidak perlu didukung.

Keluaran

Anda harus mengubah tanggal menjadi format tanggal panjang bahasa Inggris (mis 14th February 2017.). Tidak ada bantalan di sini.

Jika tanggal tidak valid (mis. 2011-02-29), Maka ini harus dikenali dengan beberapa cara. Melempar pengecualian diperbolehkan.

Lebih banyak contoh dapat dilihat di bawah ini.

Uji Kasus

"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
sumber
5
Apakah zero-padding diperbolehkan? alias 03rdbukannya3rd
Nilai Tinta
@ValueInk Jika Anda membaca komentar saya sebelumnya, abaikan saja; Saya salah paham pertanyaannya. Padding nol dalam output tidak diperbolehkan.
GarethPW
Haruskah kita mempertimbangkan satu tahun lebih dari 4 karakter (mis. 10987-01-01)?
mdahmoune
@mdahmoune Anda tidak perlu mendukung ini kecuali lebih mudah melakukannya.
GarethPW
Bagaimana dengan 2016-2-29?
Olivier Grégoire

Jawaban:

5

PostgreSQL, 61 karakter

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

Pernyataan siap, mengambil input sebagai parameter.

Contoh dijalankan:

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.
manatwork
sumber
Bagus, semoga MS-SQL mengenali gaya format "th".
BradC
Mengingat Anda berhasil menyelesaikan tugas dengan benar dengan byte paling sedikit, saya kira solusi Anda adalah pemenangnya!
GarethPW
Wow. Terima kasih. Benar-benar tidak terduga. Tidak memperhatikan sampai sekarang tidak ada bahasa golf khusus. Namun menerima solusi setelah hanya satu hari agak cepat.
manatwork
@Manatwork Saya bertanya-tanya apakah mungkin sedikit lebih awal. Tapi saya bisa mengubahnya jika perlu.
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}"

Cobalah online!

Uriel
sumber
3
%-dadalah versi tanpa-padding %dyang bisa Anda gunakan dalam pemformatan string Anda {g[2]}. Juga, 12harus menjadi 12th, bukan 12nd(angka 10-19 tidak mengikuti aturan yang sama dengan 1-9 dan 20+)
Value Ink
1
+1. tidak tahu tentang fsenarnya
Felipe Nardi Batista
@ Nilai, terima kasih! juga, memperbaiki masalah tata cara
Uriel
5

JavaScript (ES6), 142 140 byte

Keluaran NaNth Invalid Date untuk tanggal yang tidak valid.

Kode untuk nomor urut diadaptasi dari jawaban ini .

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

Darrylyeo
sumber
1
Memberikan "1 Maret 2011" untuk 2011-2-29 di Chrome. Itu mungkin perbaikan yang sulit.
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"))

Cobalah online!(Atur aliran input dan kemudian jalankan.)

Terima kasih atas saran bagus dari komentator di bawah ini.

Luke Sawczak
sumber
Anda dapat menyimpan byte dengan menghapus ruang di antara int(x)dan fordi daftar comp Anda.
Christian Dean
@ChristianDean Terima kasih, sudah selesai!
Luke Sawczak
(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')bukannya kondisi Anda saat ini untuk -3 byte.
Value Ink
@ ValueInk Sedihnya, itu akan menghasilkan ke-31. Cara lain yang saya pikirkan untuk memecahnya adalah 'th' jika bukan 0 <b% 10 <4 atau 10 <b <14 tetapi tidak menyimpan byte.
Luke Sawczak
Dalam hal ini, penyalahgunaan jenis koersi. (3<b<21)+(23<b<31)untuk -1 byte. Cobalah online!
Value Ink
5

PHP, 87 byte

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

Jalankan sebagai pipa dengan -Fatau uji secara online . Selalu mencetak tahun 4 digit; gagal selama bertahun-tahun> 9999.

tidak ada pemeriksaan validitas, 35 byte:

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

Bash + coreutils, 115 78

  • 2 byte disimpan berkat @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"

Cobalah online .

Trauma Digital
sumber
1
Tampaknya menggunakan string, bukan array akan membantu sedikit: f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
manatwork
1
BTW, revisi 1 Anda menginspirasi tip Bash . ;)
manatwork
@Manatwork ya - lucu - saya mempertimbangkan untuk mencobanya tetapi tidak berpikir itu akan membantu. Terima kasih atas dorongannya.
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");}

Disimpan 4 byte berkat @The_Lone_Devil.

TheLethalCoder
sumber
Tidak bisakah Anda mengganti yang kedua t.Daydengan dtabungan 4 byte?
The_Lone_Devil
@The_Lone_Devil Tentu saja saya bisa berterima kasih, tidak tahu bagaimana saya melewatkannya.
TheLethalCoder
4

mIRC versi 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))
OS
sumber
3

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

Menggunakan -rdate -pbendera program.

-1 byte dari manatwork.

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

Cobalah online!

Nilai Tinta
sumber
Apakah saya kehilangan alasan mengapa Anda tidak menggunakan operator ternary? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
manatwork
@manatwork Sejumlah seperti 26akan mencoba mengakses indeks 12..13dalam string pencarian, yang di luar batas, dan dengan demikian kembali nil. Jadi menggunakan ternary membuatnya d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th", yang lebih panjang 2 byte.
Value Ink
Ah, begitu. Nah, kalau begitu keren trik @ValueInk.
manatwork
Hampir lupa, perubahan kecil: "th":th.
manatwork
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

Cobalah online!

+30 byte untuk

using System;

DateTime.Parse()

kakkarot
sumber
Anda dapat membalikkan cek ternary untuk menghilangkan !byte -1. Dan Anda dapat mengubah &&ke &untuk -3 byte. Juga, karena Anda menggunakan s.Day7 kali menghemat beberapa byte untuk membuat nilai temp untuk itu: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 Terima kasih!
kakkarot
Anda juga perlu memasukkan using System;atau sepenuhnya memenuhi syarat DateTimeobjek.
TheLethalCoder
Juga DateTime.MinValueadalah 1-1-1jadi saya tidak berpikir Anda perlu cek. Yang juga akan membuat poin saya sebelumnya tidak relevan.
TheLethalCoder
1
Mengambil input sebagai DateTimedan menguraikan di luar metode tidak dapat diterima, Anda harus melakukan semua pekerjaan di dalam metode. Atau tambahkan metode tambahan untuk memisahkan pekerjaan.
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)

Jika Anda memecahnya menjadi potongan-potongan di setiap ampersand, Anda mendapatkan potongan-potongan ini:

  • ABS()menarik nomor hari dari dua karakter terakhir dalam string. Karena itu mungkin termasuk tanda hubung, ABSmengubahnya menjadi positif.
  • IF((ABS-12)<2,"th",SWITCH())tambah ordinal. The -12bit adalah karena 11, 12, dan 13 tidak mengikuti aturan yang normal dan mereka semua mendapatkan thbukan st, nd, dan rd. Ini mengoreksi untuk itu.
    • Catatan: SWITCHFungsi ini hanya tersedia di Excel 2016 dan yang lebih baru. ( Sumber ) Lebih pendek daripada CHOOSEdalam kasus ini karena dapat mengembalikan nilai jika tidak ada kecocokan yang ditemukan sedangkan CHOOSEmemerlukan input numerik dan harus memiliki pengembalian yang sesuai untuk setiap nilai yang mungkin.
  • TEXT(MID()*30," mmmm ")ekstrak nama bulan. MID()mengeluarkan angka bulan sebagai string dan mengalikannya dengan 30 mengembalikan angka. Excel melihat angka itu sebagai tanggal (1900-01-30, 1900-02-29, 1900-03-30, dll.) Dan TEXT()memformatnya sebagai nama bulan dengan spasi di kedua ujungnya. 28 dan 29 juga berfungsi tetapi 30 terlihat "lebih bagus".
  • LEFT() ekstrak nomor tahun.

Sekarang, mengingat semua itu, akan jauh lebih mudah jika kasus uji semua dalam rentang tanggal yang dapat ditangani Excel sebagai tanggal aktual: 1900-01-01 hingga 9999-12-31. Keuntungan besar adalah bahwa seluruh tanggal diformat sekaligus. Solusi itu adalah 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")

Rintangan besar lainnya adalah harus memasukkan ordinal. Tanpa itu, solusinya hanya 34 byte :

=TEXT(DATEVALUE(A1),"d mmmm yyyy")
Toast insinyur
sumber
1

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

Cobalah online!

A. Pooja
sumber
8
Selamat datang di situs ini! Di sini tujuannya adalah untuk membuat kode sesingkat mungkin, saya dapat melihat Anda memiliki nama variabel yang panjang dan banyak spasi, Anda dapat mempersingkat dan menghapusnya untuk menyimpan banyak byte. Kami juga biasanya menyertakan tajuk di bagian atas jawaban dalam bentuk # Language, N bytes. Akan lebih baik jika Anda bisa menambahkannya juga.
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')

Input melalui kolom teks i pada tabel t yang sudah ada , sesuai standar IO kami .

Bekerja untuk tanggal mulai 1 Januari 0001 hingga 31 Desember 9999. Tahun ini merupakan keluaran dengan setidaknya 3 digit (per 150AD contoh).

Tanggal yang tidak valid akan menghasilkan kesalahan jelek berikut:

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

Pengaturan bahasa / budaya default yang berbeda dapat mengubah perilaku ini. Jika Anda ingin output kesalahan yang sedikit lebih anggun (NULL), tambahkan 4 byte dengan mengubah PARSE()ke TRY_PARSE().

Format dan penjelasan:

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

The DATEtipe data yang diperkenalkan di SQL 2008 memungkinkan jangkauan yang lebih luas daripada DATETIME, dari 1 Jan 0001 sampai 31 Des 9999.

Beberapa tanggal yang sangat awal dapat diuraikan salah dengan pengaturan lokalitas AS saya ("01-02-03" menjadi "2 Januari 2003"), jadi saya menunggu beberapa nol tambahan sehingga ia tahu bahwa nilai pertama adalah tahun.

Setelah itu, itu hanya CASEpernyataan berantakan untuk menambahkan akhiran ordinal ke hari itu. Mengganggu, FORMATperintah SQL tidak memiliki cara untuk melakukannya secara otomatis.

BradC
sumber
1

q / kdb + 210 byte, tidak bersaing

Larutan:

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

Contoh:

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

Penjelasan:

Ini adalah tantangan yang mengerikan karena tidak ada format tanggal, jadi saya harus membuat bulan dari awal (95 byte) serta menghasilkan sufiks.

Solusi ungolfed di bawah, pada dasarnya membagi string input dan kemudian bergabung kembali bersama setelah kami menambahkan akhiran dan beralih bulan.

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

Catatan:

Tanggal di q hanya kembali ke ~ 1709 jadi saya tidak punya cara sepele untuk memvalidasi tanggal, maka ini adalah entri yang tidak bersaing ... Yang terbaik yang bisa saya lakukan adalah memeriksa apakah hari itu> 31 atau bulan adalah > 12 dan kembali 0.

streetster
sumber