Ngày ngắn sang tiếng Anh Ngày dài


14

Chuyển đổi định dạng ngày ngắn thành ngày dài bằng tiếng Anh với càng ít byte càng tốt.

Đầu vào

Đầu vào sẽ ở dạng một chuỗi có định dạng yyyy-mm-dd, với phần đệm bằng 0 tùy chọn cho tất cả các giá trị. Bạn có thể cho rằng điều này là đúng về mặt cú pháp, nhưng không nhất thiết là một ngày hợp lệ. Giá trị năm âm không cần phải được hỗ trợ.

Đầu ra

Bạn phải chuyển đổi ngày thành định dạng ngày dài tiếng Anh (ví dụ 14th February 2017). Không đệm ở đây là không được phép.

Nếu ngày không hợp lệ (ví dụ 2011-02-29), thì điều này phải được nhận ra theo một cách nào đó. Ném một ngoại lệ được cho phép.

Nhiều ví dụ có thể được nhìn thấy dưới đây.

Các trường hợp thử nghiệm

"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
Được phép không đệm? aka 03rdthay vì3rd
Ink Ink

@ValueInk Nếu bạn đọc bình luận trước đây của tôi, hãy bỏ qua nó; Tôi hiểu nhầm câu hỏi. Không có đệm trong đầu ra không được phép.
GarethPW

Chúng ta có nên xem xét một năm với hơn 4 ký tự (ví dụ 10987-01-01) không?
mdahmoune

@mdahmoune Bạn không cần phải hỗ trợ điều này trừ khi việc đó dễ dàng hơn.
GarethPW

Thế còn 2016-2-29?
Olivier Grégoire

Câu trả lời:


5

PostgreSQL, 61 ký tự

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

Chuẩn bị tuyên bố, lấy đầu vào làm tham số.

Chạy mẫu:

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.

Rất vui, chúc MS-SQL nhận ra phong cách định dạng "th".
BradC

Xem xét bạn quản lý để hoàn thành nhiệm vụ đúng với ít byte nhất, tôi cho rằng giải pháp của bạn là người chiến thắng!
GarethPW

Ồ Cảm ơn. Điều đó hoàn toàn bất ngờ. Cho đến bây giờ không có ngôn ngữ chơi gôn chuyên dụng. Tuy nhiên, chấp nhận một giải pháp chỉ sau một ngày là hơi sớm.
manatwork

@manatwork Tôi đã tự hỏi nếu nó có thể là một chút sớm. Nhưng tôi có thể thay đổi nó nếu cần.
GarethPW

7

Con trăn 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}"

Hãy thử trực tuyến!


3
%-dlà phiên bản không có phần đệm %dmà bạn có thể sử dụng trong định dạng chuỗi của mình thay vì {g[2]}. Ngoài ra, 12nên trở thành 12th, không 12nd(các số từ 10-19 không tuân theo các quy tắc tương tự như 1-9 và 20+)
Ink Ink

1
+1. không biết gì về fchuỗi
Felipe Nardi Batista

@ValueInk cảm ơn! Ngoài ra, đã khắc phục sự cố thứ tự
Uriel

5

JavaScript (ES6), 142 140 byte

Đầu ra NaNth Invalid Date cho ngày không hợp lệ.

Mã cho số thứ tự đã được điều chỉnh từ câu trả lời này .

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


1
Cung cấp "ngày 1 tháng 3 năm 2011" cho 2011-2-29 trong Chrome. Đó có thể là một sửa chữa khó khăn.
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"))

Hãy thử trực tuyến!(Đặt luồng đầu vào và sau đó chạy.)

Nhờ những gợi ý tốt từ những người bình luận bên dưới.


Bạn có thể lưu một byte bằng cách xóa khoảng trắng giữa int(x)fortrong danh sách comp của bạn.
Christian Dean

@ChristianDean Cảm ơn, đã xong!
Luke Sawczak

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')thay vì điều kiện hiện tại của bạn cho -3 byte.
Mực giá trị

@ValueInk Đáng buồn thay, nó sẽ sản xuất thứ 31. Một cách khác tôi nghĩ về việc phá vỡ nó là 'th' nếu không 0 <b% 10 <4 hoặc 10 <b <14 nhưng nó không lưu bất kỳ byte nào.
Luke Sawczak

Trong trường hợp đó, lạm dụng loại coersion. (3<b<21)+(23<b<31)cho -1 byte. Hãy thử trực tuyến!
Mực giá trị

5

PHP, 87 byte

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

Chạy như ống với -Fhoặc kiểm tra trực tuyến . Luôn in một năm 4 chữ số; thất bại trong nhiều năm> 9999.

không kiểm tra tính hợp lệ, 35 byte:

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

5

Bash + coreutils, 115 78

  • Lưu 2 byte nhờ @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"

Hãy thử trực tuyến .


1
Có vẻ như sử dụng chuỗi thay vì mảng sẽ giúp một chút : f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y".
manatwork

1
BTW, phiên bản 1 của bạn đã truyền cảm hứng cho một mẹo Bash . ;)
thao tác

@manatwork có - thật buồn cười - Tôi đã cân nhắc thử điều đó nhưng không nghĩ nó sẽ giúp ích. Cảm ơn vì sự nũng nịu.
Chấn thương kỹ thuật số

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

Đã lưu 4 byte nhờ @The_Lone_Devil.


Bạn có thể không thay thế cái thứ hai t.Daybằng dcách tiết kiệm 4 byte không?
The_Lone_Devil

@The_Lone_Devil Tất nhiên tôi có thể cảm ơn, không biết làm thế nào tôi bỏ lỡ điều đó.
TheLethalCoder

4

mIRC phiên bản 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

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

Sử dụng -rdate -pcờ chương trình.

-1 byte từ manatwork.

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

Hãy thử trực tuyến!


Tôi có thiếu một lý do tại sao bạn không sử dụng toán tử ternary? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
manatwork

@manatwork Một số like 26sẽ cố gắng truy cập các chỉ mục 12..13trong chuỗi tra cứu, nằm ngoài giới hạn và do đó trả về nil. Do đó, việc sử dụng ternary làm cho nó d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th"dài hơn 2 byte.
Mực giá trị

Ah tôi thấy. Chà, mẹo hay đấy @ValueInk.
manatwork

Hầu như quên mất, một thay đổi nhỏ: "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

Hãy thử trực tuyến!

+30 byte cho

using System;

DateTime.Parse()


Bạn có thể đảo ngược kiểm tra ternary để loại bỏ !-1 byte. Và bạn có thể thay đổi &&để &cho -3 byte. Ngoài ra, vì bạn sử dụng s.Day7 lần nên nó tiết kiệm được một số byte để tạo giá trị tạm thời cho nó: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 Cảm ơn!
kakkarot

Bạn cũng cần bao gồm using System;hoặc đủ điều kiện DateTimeđối tượng.
TheLethalCoder

Ngoài ra DateTime.MinValue1-1-1vì vậy tôi không nghĩ rằng bạn cần kiểm tra. Điều này cũng sẽ làm cho điểm trước đây của tôi không liên quan.
TheLethalCoder

1
Lấy đầu vào làm DateTimevà phân tích cú pháp bên ngoài phương thức không được chấp nhận, bạn nên thực hiện tất cả công việc bên trong phương thức. Hoặc thêm một phương thức bổ sung để phân chia công việc.
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)

Nếu bạn chia nó thành nhiều phần tại mỗi ký hiệu, bạn sẽ nhận được các phần sau:

  • ABS()kéo số ngày từ hai ký tự cuối cùng trong chuỗi. Vì có thể bao gồm một dấu gạch nối,ABS chuyển đổi nó thành tích cực.
  • IF((ABS-12)<2,"th",SWITCH())thêm thứ tự. Các -12bit là vì 11, 12 và 13 không tuân theo các quy tắc bình thường và tất cả họ đều có được ththay vì st, ndrd . Điều này sửa cho điều đó.
    • Lưu ý: SWITCHChức năng chỉ khả dụng trong Excel 2016 trở lên. ( Nguồn ) Nó ngắn hơn CHOOSEtrong trường hợp này bởi vì nó có thể trả về một giá trị nếu không tìm thấy kết quả khớp nào trong khi CHOOSEyêu cầu đầu vào số và phải có một trả về tương ứng cho mỗi giá trị có thể.
  • TEXT(MID()*30," mmmm ")trích xuất tên tháng. MID()lấy ra số tháng dưới dạng một chuỗi và nhân với 30 trả về một số. Excel xem số đó là một ngày (1900-01-30, 1900-02-29, 1900-03-30, v.v.)TEXT()định dạng nó dưới dạng tên tháng với một khoảng trắng ở cả hai đầu. 28 và 29 cũng sẽ hoạt động nhưng 30 trông "đẹp hơn".
  • LEFT() trích số năm.

Bây giờ, với tất cả những điều đó, mọi thứ sẽ dễ dàng hơn nếu các trường hợp thử nghiệm đều nằm trong phạm vi ngày mà Excel có thể xử lý như một ngày thực tế: 1900-01-01 đến 9999-12-31. Ưu điểm lớn là toàn bộ ngày được định dạng cùng một lúc. Giải pháp đó là 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")

Rào cản lớn khác là phải bao gồm cả thứ tự. Không có điều đó, giải pháp chỉ là 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)")}

Hãy thử trực tuyến!


8
Chào mừng đến với trang web! Ở đây mục tiêu là làm cho mã càng ngắn càng tốt, tôi có thể thấy bạn có tên biến dài và nhiều khoảng trắng, bạn có thể rút ngắn và loại bỏ chúng để tiết kiệm rất nhiều byte. Chúng tôi cũng thường bao gồm một tiêu đề ở đầu câu trả lời ở dạng # Language, N bytes. Sẽ rất tốt nếu bạn có thể thêm một cái nữa.
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')

Đầu vào là thông qua cột văn bản i trong bảng t có sẵn , theo các tiêu chuẩn IO của chúng tôi .

Hoạt động cho các ngày từ ngày 1 tháng 1 năm 0001 đến ngày 31 tháng 12 năm 9999. Năm là đầu ra có ít nhất 3 chữ số (ví dụ trên 150AD).

Ngày không hợp lệ sẽ dẫn đến lỗi xấu sau đây:

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

Các cài đặt ngôn ngữ / văn hóa mặc định khác nhau có thể thay đổi hành vi này. Nếu bạn muốn một đầu ra lỗi duyên dáng hơn một chút (NULL), hãy thêm 4 byte bằng cách thay đổi PARSE()thành TRY_PARSE().

Định dạng và giải thích:

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

Kiểu DATEdữ liệu được giới thiệu trong SQL 2008 cho phép phạm vi rộng hơn nhiều so với DATETIME, từ ngày 1 tháng 1 năm 0001 đến ngày 31 tháng 12 năm 9999.

Một số ngày rất sớm có thể bị phân tích cú pháp sai với cài đặt địa phương tại Hoa Kỳ của tôi ("01/02/03" trở thành "ngày 2 tháng 1 năm 2003"), vì vậy tôi đã đăng ký trước một vài số không để nó biết rằng giá trị đầu tiên là năm.

Sau đó, nó chỉ là một CASEtuyên bố lộn xộn để thêm hậu tố thứ tự cho ngày. Khó chịu, lệnh SQL FORMATkhông có cách nào để làm điều đó tự động.


1

q / kdb + 210 byte, không cạnh tranh

Giải pháp:

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

Ví dụ:

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

Giải trình:

Đây là một thách thức khủng khiếp vì không có định dạng ngày, vì vậy tôi phải tạo ra nhiều tháng từ đầu (95 byte) cũng như tạo hậu tố.

Giải pháp không được chấp nhận ở bên dưới, về cơ bản tách chuỗi đầu vào và sau đó nối lại với nhau sau khi chúng tôi đã thêm hậu tố và chuyển ra tháng.

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

Ghi chú:

Ngày trong q chỉ quay lại ~ 1709 vì vậy tôi không có cách xác thực ngày nào, vì vậy đây là mục không cạnh tranh ... Điều tốt nhất tôi có thể làm là kiểm tra xem ngày đó có phải là 31 hay tháng không > 12 và trả về 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.