短日期转换为英语长日期


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
是否允许零填充?aka 03rd代替3rd
Value Ink 2016年

@ValueInk如果您阅读了我之前的评论,请忽略它;我误解了这个问题。不允许在输出中填充零。
GarethPW

我们是否应该考虑一年使用4个以上的字符(例如10987-01-01)?
mdahmoune

@mdahmoune除非更容易这样做,否则不需要支持它。
GarethPW

2016-2-29
奥利维尔·格雷戈尔

Answers:


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

哇。谢谢。那完全是出乎意料的。直到现在都没有发现专门的高尔夫语言。但是,仅在一天后接受解决方案会很快。
manatwork 2015年

@manatwork我确实想知道是否会早一点。但是我仍然可以根据需要更改它。
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+相同的规则)
价值墨水

1
+1。不知道f弦乐
Felipe Nardi Batista

@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
在Chrome中为2011-2-29给出“ 2011年3月1日”。那可能是一个艰难的解决。
里克·希区柯克

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

在线尝试!(设置输入流,然后运行。)

感谢下面的评论者的好的建议。


您可以通过删除list comp 之间int(x)和之间的空格来节省一个字节for
Christian Dean

@ChristianDean谢谢,完成!
卢克·索扎克

(('st','nd','rd')[b%10-1]if b<4 or 20<b<24 else'th')而不是您当前的条件-3字节。
Value Ink 2015年

@ValueInk可悲的是,它将产生31。我想将其分解的另一种方式是'th',如果不是0 <b%10 <4或10 <b <14,但它不保存任何字节。
卢克·索扎克

在这种情况下,滥用类型的胁迫。(3<b<21)+(23<b<31)-1个字节。在线尝试!
Value Ink 2013年

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

  • @manatwork节省了2个字节。
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"
manatwork

1
顺便说一句,您的修订版1启发了Bash技巧。;)
manatwork 2015年

@manatwork是的-很有趣-我考虑过尝试一下,但是认为没有帮助。谢谢你的轻推。
Digital Trauma

4

C#,147143字节

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

由于@The_Lone_Devil,节省了4个字节。


你能不能取代第二t.Dayd一个4字节的储蓄?
The_Lone_Devil

@The_Lone_Devil当然,我要感谢,不知道我是怎么想念它的。
TheLethalCoder

4

mIRC版本7.49(197字节)

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

红宝石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

@manatwork像这样的数字26将尝试访问12..13查找字符串中的索引,该索引超出范围,因此返回nil。因此,使用三元数会使它d<4||d>20?"..stndrd"[d%10*2,2]||"th":"th"更长2个字节。
Value Ink 2013年

知道了 好吧,然后@ValueInk很酷。
manatwork

几乎忘了一个很小的变化:"th":th
manatwork

2

C#(.NET核心)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;}
Kevin 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代替stndrd。对此进行了纠正。
    • 注意:该SWITCH功能仅在Excel 2016及更高版本中可用。(Source)比CHOOSE在这种情况下短,因为如果找不到匹配项,它可以返回一个值,而CHOOSE需要数字输入,并且必须为每个可能的值都有一个对应的返回值。
  • TEXT(MID()*30," mmmm ")提取月份名称。MID()拉出月份数字作为字符串,然后乘以30将返回一个数字。Excel将该数字视为日期(1900-01-30、1900-02-29、1900-03-30等),并将TEXT()其设置为月份名称,并在其两端均带有空格。28和29也可以,但30看起来“更黑”。
  • LEFT() 提取年份数字。

现在,考虑到所有这些,如果测试用例全部位于Excel可以作为实际日期处理的日期范围内,那将变得更加容易。最大的优点是整个日期可以立即格式化。该解决方案是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字节

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标准,输入是通过现有表t中的第i列输入的。

适用于从0001年1月1日到9999年12月31日的日期。输出的年份至少为3位(以150AD为例)。

无效的日期将导致以下难看的错误:

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

不同的默认语言/区域设置可能会更改此行为。如果您希望输出错误消息(NULL),请更改PARSE()为,以增加4个字节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')

从0001年1月1日到9999年12月31日,DATESQL 2008中引入的数据类型允许的范围比得多DATETIME

我的美国地区设置可能会将某些很早的日期解析为错误的日期(“ 01-02-03”变成“ Jan 2 2003”),因此我在前面加上了两个额外的零,因此它知道第一个值是年份。

在那之后,只是CASE增加了序数后缀到今天的混乱声明。令人讨厌的是,SQL FORMAT命令无法自动执行此操作。


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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.