วันสั้น ๆ เป็นวันภาษาอังกฤษแบบยาว


14

แปลงรูปแบบวันที่แบบย่อเป็นวันที่แบบยาวของอังกฤษในจำนวนไบต์น้อยที่สุด

อินพุต

อินพุตจะอยู่ในรูปแบบของสตริงที่มีรูปแบบyyyy-mm-ddโดยมีการเติมเต็มศูนย์เป็นตัวเลือกสำหรับค่าทั้งหมด คุณสามารถสันนิษฐานได้ว่าสิ่งนี้ถูกต้องทางไวยากรณ์ แต่ไม่จำเป็นต้องเป็นวันที่ที่ถูกต้อง ค่าปีเชิงลบไม่จำเป็นต้องได้รับการสนับสนุน

เอาท์พุต

คุณต้องแปลงวันที่เป็นรูปแบบวันที่แบบยาวของอังกฤษ (เช่น14th February 2017) ไม่อนุญาตให้มีการเติมเต็มศูนย์ที่นี่

หากวันที่ไม่ถูกต้อง (เช่น2011-02-29) จะต้องมีการรับรู้ในบางวิธี อนุญาตให้ทำการโยนข้อยกเว้นได้

ตัวอย่างเพิ่มเติมสามารถดูได้ด้านล่าง

กรณีทดสอบ

"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
อนุญาตให้มีการเว้นศูนย์หรือไม่ อาคา03rdแทน3rd
หมึกมูลค่า

@ValueInk หากคุณอ่านความคิดเห็นก่อนหน้าของฉันไม่ต้องสนใจ ฉันเข้าใจผิดคำถาม ไม่อนุญาตให้มีการเติมเต็มศูนย์ในเอาต์พุต
GarethPW

เราควรพิจารณาหนึ่งปีสำหรับตัวละครมากกว่า 4 ตัว (เช่น 10987-01-01) หรือไม่
mdahmoune

@mdahmoune คุณไม่จำเป็นต้องสนับสนุนสิ่งนี้เว้นแต่ว่าจะทำได้ง่ายกว่า
GarethPW

เกี่ยวกับ2016-2-29อะไร
Olivier Grégoire

คำตอบ:


5

PostgreSQL 61 ตัว

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

คำสั่งที่เตรียมไว้รับอินพุตเป็นพารามิเตอร์

วิ่งตัวอย่าง:

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.

ดีหวังว่า MS-SQL จะรู้จักสไตล์การจัดรูปแบบ "th"
BradC

เมื่อพิจารณาว่าคุณสามารถทำงานให้เสร็จอย่างเหมาะสมด้วยจำนวนไบต์น้อยที่สุดฉันคิดว่าโซลูชันของคุณคือผู้ชนะ!
GarethPW

ว้าว. ขอบคุณ นั่นไม่คาดคิดอย่างสมบูรณ์ ไม่ได้สังเกตจนกระทั่งถึงตอนนี้ยังไม่มีภาษาสำหรับเล่นกอล์ฟโดยเฉพาะ อย่างไรก็ตามการยอมรับวิธีแก้ปัญหาหลังจากผ่านไปหนึ่งวันก็จะเร็วขึ้น
จัดการ

@ การทำงานฉันสงสัยว่ามันอาจจะเร็วไปหน่อย แต่ฉันสามารถเปลี่ยนได้ถ้าต้องการอยู่แล้ว
GarethPW

7

Python 3.6, 137 129 ไบต์

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

ลองออนไลน์!


3
%-dเป็นรุ่นที่ไม่มีรองของที่คุณสามารถใช้ในการจัดรูปแบบสายของคุณแทน%d {g[2]}นอกจากนี้12ควรกลายเป็น12thไม่ใช่12nd(ตัวเลขตั้งแต่ 10-19 ไม่เป็นไปตามกฎเดียวกันกับ 1-9 และ 20+)
Value Ink

1
+1 ไม่ทราบเกี่ยวกับfสตริง
เฟลิเป้นาร์ดีบาติสตา

@ValueInk ขอบคุณ! นอกจากนี้แก้ไขปัญหาของกฎ
Uriel

5

JavaScript (ES6), 142 140 ไบต์

เอาต์พุตNaNth Invalid Dateสำหรับวันที่ไม่ถูกต้อง

รหัสสำหรับเลขลำดับถูกดัดแปลงจากคำตอบนี้

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


1
ให้ "1 มีนาคม 2011" สำหรับ 2011-2-29 ใน Chrome นั่นอาจเป็นการแก้ไขที่ยากลำบาก
Rick Hitchcock

5

Python 3.6 , 154 ไบต์

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

ลองออนไลน์! (ตั้งค่าอินพุตสตรีมแล้วเรียกใช้)

ขอบคุณคำแนะนำที่ดีจากผู้แสดงความคิดเห็นด้านล่าง


คุณสามารถบันทึกไบต์โดยลบช่องว่างระหว่างint(x)และforในคอมพ์รายการของคุณ
Christian Dean

@ChristianDean ขอบคุณเสร็จแล้ว!
Luke Sawczak

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')แทนเงื่อนไขปัจจุบันของคุณเป็น -3 ไบต์
มูลค่าหมึก

@ValueInk น่าเศร้าที่จะผลิต 31 อีกวิธีที่ฉันคิดว่าทำลายมันลงคือ 'th' หากไม่ใช่ 0 <b% 10 <4 หรือ 10 <b <14 แต่มันไม่ได้บันทึกไบต์ใด ๆ
Luke Sawczak

ในกรณีดังกล่าวให้ใช้ประเภทการละเมิด (3<b<21)+(23<b<31)สำหรับ -1 ไบต์ ลองออนไลน์!
มูลค่าหมึก

5

PHP, 87 ไบต์

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

ทำงานเป็นท่อที่มี-Fหรือทดสอบออนไลน์ พิมพ์ปี 4 หลักเสมอ ล้มเหลวเป็นเวลาหลายปี> 9999

ไม่มีการตรวจสอบความถูกต้อง 35 ไบต์:

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

5

Bash + coreutils, 115 78

  • บันทึก 2 ไบต์ด้วย @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"

ลองมันออนไลน์


1
f=thstndrd; $d"${f:t/10-1?t%10<4?t%10*2:0:0:2} %B %Y"ดูเหมือนว่าการใช้สตริงแทนของอาร์เรย์จะช่วยบิต:
จัดการ

1
BTW, คุณแก้ไข 1แรงบันดาลใจปลายทุบตี ;)
จัดการ

@ การจัดการงานใช่ - มันตลก - ฉันลองคิดดู แต่ก็ไม่คิดว่ามันจะช่วยได้ ขอบคุณสำหรับเขยิบ
บาดเจ็บทางระบบดิจิตอล

4

C #, 147 143 ไบต์

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 ไบต์ด้วย @The_Lone_Devil


คุณไม่สามารถแทนที่ที่สองt.Dayด้วยdการประหยัด 4 ไบต์ได้หรือไม่
The_Lone_Devil

@The_Lone_Devil แน่นอนฉันจะขอบคุณไม่ทราบว่าฉันพลาด
TheLethalCoder


3

Ruby , 104 103 102 + 8 = 112 111 110 ไบต์

ใช้-rdate -pแฟล็กโปรแกรม

-1 ไบต์จากการผลิต

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

ลองออนไลน์!


ฉันไม่มีเหตุผลใดที่คุณไม่ใช้ผู้ประกอบการที่ประกอบไปด้วย? d<4||d>20?"..stndrd"[d%10*2,2]:"th"
จัดการ

@manatwork จำนวนเหมือน26จะพยายามที่จะเข้าถึงดัชนีในสตริงการค้นหาซึ่งเป็นออกจากขอบเขตและทำให้ผลตอบแทน12..13 nilดังนั้นการใช้ ternary ทำให้มันd<4||d>20?"..stndrd"[d%10*2,2]||"th":"th"มีความยาว 2 ไบต์
มูลค่าหมึก

อ่าฉันเข้าใจแล้ว เอาล่ะเคล็ดลับเด็ด ๆ ที่ @ValueInk
จัดการ

เกือบลืมไปแล้วว่ามีการเปลี่ยนแปลงเล็ก ๆ : →"th" :th
จัดการ

2

C # (.NET Core) , 167 197 ไบต์

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

ลองออนไลน์!

+30 ไบต์สำหรับ

using System;

DateTime.Parse()


คุณสามารถย้อนกลับการตรวจสอบที่สามเพื่อกำจัด!-1 ไบต์ และคุณสามารถเปลี่ยน&&ไป&สำหรับ -3 ไบต์ นอกจากนี้ตั้งแต่คุณใช้s.Day7 ครั้งมันจะช่วยประหยัดไบต์บางอย่างเพื่อสร้างมูลค่าชั่วคราวสำหรับมัน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;}
เควิน Cruijssen

@KevinCruijssen ขอบคุณ!
kakkarot

คุณต้องรวมusing System;หรือมีคุณสมบัติของDateTimeวัตถุอย่างเต็มที่
TheLethalCoder

อีกอย่างDateTime.MinValueคือ1-1-1ฉันไม่คิดว่าคุณต้องการเช็ค ซึ่งจะทำให้จุดก่อนหน้าของฉันไม่เกี่ยวข้อง
TheLethalCoder

1
การป้อนข้อมูลเป็น a DateTimeและการแยกวิเคราะห์นอกเมธอดไม่เป็นที่ยอมรับคุณควรทำงานทั้งหมดภายในเมธอด หรือเพิ่มวิธีพิเศษเพื่อแยกการทำงานออก
TheLethalCoder

2

Excel, 212 ไบต์

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

หากคุณแบ่งมันเป็นชิ้น ๆ ที่เครื่องหมายและคุณจะได้รับชิ้นส่วนเหล่านี้

  • ABS()ดึงหมายเลขวันจากอักขระสองตัวสุดท้ายในสตริง เนื่องจากอาจประกอบด้วยยัติภังค์ให้ABSเปลี่ยนเป็นบวก
  • IF((ABS-12)<2,"th",SWITCH())เพิ่มลำดับ -12บิตเป็นเพราะ 11, 12, 13 และไม่ปฏิบัติตามกฎปกติและพวกเขาทั้งหมดได้รับthแทนst, และnd rdสิ่งนี้ถูกต้องสำหรับสิ่งนั้น
    • หมายเหตุ: SWITCHฟังก์ชันนี้มีเฉพาะใน Excel 2016 และใหม่กว่า ( ที่มา ) มันสั้นกว่าCHOOSEในกรณีนี้เพราะสามารถคืนค่าได้หากไม่พบการจับคู่ในขณะที่CHOOSEต้องใช้การป้อนตัวเลขและต้องมีการส่งคืนที่สอดคล้องกันสำหรับแต่ละค่าที่เป็นไปได้
  • TEXT(MID()*30," mmmm ")แยกชื่อเดือน MID()ดึงตัวเลขเดือนเป็นสตริงและคูณด้วย 30 ส่งคืนตัวเลข Excel เห็นตัวเลขนั้นเป็นวันที่(1900-01-30, 1900-02-29, 1900-03-30 ฯลฯ )และจัดTEXT()รูปแบบเป็นชื่อเดือนที่มีช่องว่างทั้งสองด้าน 28 และ 29 จะใช้งานได้ แต่ 30 หน้าจะดูดีกว่า
  • LEFT() แยกจำนวนปี

ตอนนี้ให้ทุกอย่างมันจะง่ายขึ้นถ้ากรณีทดสอบทั้งหมดอยู่ในช่วงวันที่ที่ Excel สามารถจัดการเป็นวันที่จริง: 1900-01-01 ถึง 9999-12-31 ข้อได้เปรียบที่ยิ่งใหญ่คือการจัดรูปแบบวันที่ทั้งหมดในครั้งเดียว โซลูชันนั้นคือ133 ไบต์ :

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

อุปสรรค์ใหญ่อีกอันหนึ่งก็ต้องรวมลำดับ หากไม่มีวิธีแก้ปัญหาก็คือ34 ไบต์ :

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

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

ลองออนไลน์!


8
ยินดีต้อนรับสู่เว็บไซต์! ที่นี่มีเป้าหมายคือทำให้รหัสสั้นที่สุดเท่าที่จะเป็นไปได้ฉันเห็นว่าคุณมีชื่อตัวแปรยาวและพื้นที่ว่างมากมายคุณสามารถย่อและลบรหัสเหล่านี้เพื่อบันทึกไบต์จำนวนมาก # Language, N bytesนอกจากนี้เรายังมักจะมีส่วนหัวที่ด้านบนของคำตอบในรูปแบบของการ มันจะดีถ้าคุณสามารถเพิ่มได้เช่นกัน
TheLethalCoder

1

T-SQL, 194 ไบต์

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

การป้อนข้อมูลผ่านทางคอลัมน์ข้อความฉันในที่มีอยู่ก่อนตารางที ,ตามมาตรฐาน IO ของเรา

ใช้งานได้ตั้งแต่วันที่ 1 มกราคม 0001 ถึง 31 ธันวาคม 9999 ปีนี้จะแสดงผลอย่างน้อย 3 หลัก (ต่อ 150AD ตัวอย่าง)

วันที่ไม่ถูกต้องจะส่งผลให้เกิดข้อผิดพลาดที่น่าเกลียดดังต่อไปนี้:

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

การตั้งค่าภาษา / วัฒนธรรมเริ่มต้นที่แตกต่างกันอาจเปลี่ยนพฤติกรรมนี้ ถ้าคุณต้องการออกข้อผิดพลาดเล็กน้อยที่สง่างามมากขึ้น (NULL) เพิ่ม 4 ไบต์โดยการเปลี่ยนไปPARSE()TRY_PARSE()

รูปแบบและคำอธิบาย:

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

DATEชนิดข้อมูลแนะนำใน SQL 2008 จะช่วยให้ช่วงกว้างกว่าDATETIMEจากวันที่ 1 มกราคม 0001 ถึงวันที่ 31 ธ.ค. 9999

วันที่เริ่มต้นบางวันสามารถแยกวิเคราะห์ผิดได้ด้วยการตั้งค่าตำแหน่งในสหรัฐอเมริกาของฉัน ("01-02-03" กลายเป็น "Jan 2 2003") ดังนั้นฉันจึงเตรียมค่าศูนย์สองคู่ไว้ล่วงหน้าเพื่อให้รู้ว่าค่าแรกคือปี

หลังจากนั้นมันเป็นเพียงCASEคำสั่งที่ยุ่งเหยิงที่จะเพิ่มคำต่อท้ายตามลำดับลงไปในวันนั้น น่ารำคาญFORMATคำสั่งSQL ไม่มีวิธีดำเนินการโดยอัตโนมัติ


1

q / kdb + 210 ไบต์ไม่ใช่การแข่งขัน

วิธีการแก้:

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

ตัวอย่าง:

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

คำอธิบาย:

นี่เป็นความท้าทายที่น่ากลัวเนื่องจากไม่มีการจัดรูปแบบวันที่ดังนั้นฉันต้องสร้างเดือนตั้งแต่เริ่มต้น (95 ไบต์) รวมถึงการสร้างคำต่อท้าย

วิธีการแก้ปัญหาที่ Ungolfed อยู่ด้านล่างโดยทั่วไปแล้วแยกสตริงอินพุตจากนั้นเข้าร่วมกันอีกครั้งหลังจากเราได้เพิ่มคำต่อท้ายและเปลี่ยนเดือน

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

หมายเหตุ:

วันที่ในqกลับไปที่ ~ 1709 เท่านั้นดังนั้นฉันจึงไม่มีวิธีตรวจสอบความถูกต้องของวันที่ดังนั้นนี่เป็นรายการที่ไม่เข้าแข่งขัน ... สิ่งที่ดีที่สุดที่ฉันทำได้คือตรวจสอบว่าวันนั้นคือ 31 วันหรือไม่ > 12 และส่งคืน 0

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.