Given a date written in any (must handle all in the same program) of the following formats, parse it into a valid yyyy/mm/dd date.
17th May 2012
March 14th, 2016
20 February 2014
September 14, 2017
Sunday, June 8, 2015
Rules
- Dates will sometimes be invalid, ie. incorrect day for the month or number of months in a year, you must handle both cases. Either by erroring out or returning a consistent falsey value, you choose. (They will however stick to the template formats above)
- Padding for days and months less than 10 must be used to create a two digit output.
- Month names will always be the full name, not shortened to their three character counterparts.
- You can assume the year will always be within the 0000-9999 range.
- Negative numbers need not be handled.
- You can create a full program or function so output can be in any format, printed to console or returned from a function.
- Input will always be a string, output must always be a string, if it makes it shorter to take it as a single argument in an array eg.
["17th May 2012"]you may do so and output can be the same["2012/05/17"] - You can assume spelling in input will be correct.
BONUS: cos who here doesnt like a challenge ;)
If you can manage to also allow the input formats of The Fourteenth of March, 2016 or March the Fourteenth, 2016 you may take an extra 20 bytes off your code with any final byte counts less than 1 resulting in 1.
Here are the full written numbers for each of the days to avoid any confusion on spelling.
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Nineth, Tenth, Eleventh, Twelfth, Thirteenth, Fourteenth, Fifteenth, Sixteenth, Seventeenth, Eighteenth, Nineteenth, Twentieth, Twenty First, Twenty Second, Twenty Third, Twenty Fourth, Twenty Fifth, Twenty Sixth, Twenty Seventh, Twenty Eighth, Twenty Nineth, Thirtieth, Thirty First
Test Cases
INPUT | Output
17th May 2012 | 2012年05月17日
March 14th, 2016 | 2016年03月14日
20 February 2014 | 2014年02月20日
September 14, 2017 | 2017年09月14日
Sunday, June 8, 2015 | 2015年06月08日
1st January 1918 | 1918年01月01日
The Fourteenth of March, 2016 | 2016年03月14日
March the Fourteenth, 2016 | 2016年03月14日
November the Seventeenth, 2019 | 2019年11月17日
The Thirtieth of April, 2016 | 2016年04月30日
30 February 2014 | Invalid
September 99, 2017 | Invalid
Sunday, June8, 2015 | Invalid
The Thirty First of April, 2016 | Invalid
7 Answers 7
PowerShell, (削除) 91 (削除ここまで) (削除) 89 (削除ここまで) (削除) 91 (削除ここまで) 56 bytes
date("$args"-replace'th|rd|st|(\b.*)day|,')-f yyyy/MM/dd
Takes input as a string. Uses a -replace to get rid of junk, then uses the built-in Get-Date command with the -format flag to specify the required yyyy/MM/dd format. That string is left on the pipeline and output is implicit.
Saved two bytes thanks to Mr Xcoder. Saved a huge chunk thanks to TessellatingHeckler's regex golfing.
-
1\$\begingroup\$ Hey look competitive PowerShell submission! \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年08月25日 14:05:25 +00:00Commented Aug 25, 2017 at 14:05
-
\$\begingroup\$ @EriktheOutgolfer Date manipulation is one of PowerShell's strengths. \$\endgroup\$AdmBorkBork– AdmBorkBork2017年08月25日 14:06:20 +00:00Commented Aug 25, 2017 at 14:06
-
1\$\begingroup\$ Why do you have all those extraneous spaces? \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年08月25日 14:06:55 +00:00Commented Aug 25, 2017 at 14:06
-
\$\begingroup\$ @Mr.Xcoder "all those" = 2. lol. Thanks! \$\endgroup\$AdmBorkBork– AdmBorkBork2017年08月25日 14:10:10 +00:00Commented Aug 25, 2017 at 14:10
-
\$\begingroup\$ You can remove the
''from the date format, for -2. If you want to stick to your approach, given the "spelling is correct" then you can replace'th|rd|st|(\b.*)day|,'and it drops to 56 bytes and handles the same cases. Although I think it's wrong because if you drop the days, you can't pick up theSunday, June8, 2015 | Invalidcase because it was Monday. It should error, but it parses as valid. Not sure what the ruling on that will be, or if others are checking it. \$\endgroup\$TessellatingHeckler– TessellatingHeckler2017年08月26日 09:28:25 +00:00Commented Aug 26, 2017 at 9:28
Rails, (削除) 41 (削除ここまで), (削除) 37 (削除ここまで) 35 bytes
->x{x.to_date.strftime('%Y/%m/%d')}
I don't know of an online interpreter for Rails, but here is a screenshot demonstrating this proc
-
\$\begingroup\$ Online interpreter link? \$\endgroup\$Jonathan Allan– Jonathan Allan2017年08月25日 18:50:41 +00:00Commented Aug 25, 2017 at 18:50
-
1\$\begingroup\$ Does this really work for all the formats in question? :o \$\endgroup\$totallyhuman– totallyhuman2017年08月25日 19:40:49 +00:00Commented Aug 25, 2017 at 19:40
-
\$\begingroup\$ @totallyhuman Added a screenshot showing the results. Unfortunately I don't know of an online interpreter :( \$\endgroup\$Suever– Suever2017年08月25日 20:09:36 +00:00Commented Aug 25, 2017 at 20:09
PHP, (削除) 73 (削除ここまで) 164+1 bytes
for(preg_match("#(\d+)[^\d]+(\d+)#",$d=$argn,$r);$m++<12;)strpos(_.$d,date(F,strtotime($r[2].-$m)))&&printf(checkdate($m,$r[1],$r[2])?"$r[2]/%02d/%02d":E,$m,$r[1]);
Run as pipe with -nR or try it online.
The date check was really expensive: I had to disassemble the date before using a builtin, then try and error on the month name.
-
\$\begingroup\$ I think you have to support all formats not just one of them? \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年08月25日 14:08:32 +00:00Commented Aug 25, 2017 at 14:08
-
1\$\begingroup\$ @EriktheOutgolfer it does. But not the bonus formats. \$\endgroup\$Titus– Titus2017年08月25日 14:09:02 +00:00Commented Aug 25, 2017 at 14:09
-
\$\begingroup\$ @EriktheOutgolfer This does handle all formats. \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年08月25日 14:09:06 +00:00Commented Aug 25, 2017 at 14:09
-
1\$\begingroup\$ This fails for invalid dates.
30 February 2014returns2014/03/02. Either by erroring out or returning a consistent falsey value, you choose. (They will however stick to the template formats above) \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年08月25日 14:10:45 +00:00Commented Aug 25, 2017 at 14:10 -
\$\begingroup\$ @Mr.Xcoder That quite ruins it ... \$\endgroup\$Titus– Titus2017年08月25日 14:12:20 +00:00Commented Aug 25, 2017 at 14:12
Python 3 + parsedatetime library, (削除) 152 (削除ここまで) (削除) 139 (削除ここまで) (削除) 155 (削除ここまで) 153 bytes
Saved 13 bytes thanks to Jonathan Allan
Added 16 bytes to handle dates with invalid length days
Saved 2 bytes by removing lambda assignment
lambda s:re.search(f'(^| ){str(h(s)[0].tm_mday)[:2]}[^\d]',s)and time.strftime('%Y/%m/%d',h(s)[0])
import parsedatetime as p,time,re
h=p.Calendar().parse
Does not support bonus dates
-
\$\begingroup\$ Welcome to PPCG! Nice first post. Save 13 bytes by using: the falsey return value of
None;import ...as; & alambdaby reusingparseash. \$\endgroup\$Jonathan Allan– Jonathan Allan2017年08月25日 21:03:37 +00:00Commented Aug 25, 2017 at 21:03
Python 2, 193 bytes
lambda s:time.strftime('%Y/%m/%d',time.strptime(re.sub(r'^(\w+) (\d+)',r'2円 1円',re.sub('^ ','',re.sub('(th|rd|st)|(Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day|,','',s))),'%d %B %Y'))
import re,time
;-; pls halp
-
\$\begingroup\$ ;-; pls halp - 192 bytes by declaring
time. \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年08月25日 15:56:32 +00:00Commented Aug 25, 2017 at 15:56 -
\$\begingroup\$ 186 bytes (remove
f=from the byte count on TiO) by declaringre.sub\$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年08月25日 16:00:52 +00:00Commented Aug 25, 2017 at 16:00
Java (OpenJDK 8), 190 + 26 = 216 bytes
import java.time.format.*;
s->DateTimeFormatter.ofPattern("uuuu/MM/dd").format(DateTimeFormatter.ofPattern("[EEEE, ][d ]MMMM [d, ]uuuu").withResolverStyle(ResolverStyle.STRICT).parse(s.replaceAll("(\\d)[a-z].","1ドル")))
Important note: it was shorter to also validate the day of week instead of ditching it, so that validation is included!
I haven't tried with SimpleDateFormat beyond the obvious cases which all accepted dates like 30 February. So I had to ditch it and I used Java 8's DateTimeFormatter.
Explanation
"[EEEE, ][d ]MMMM [d, ]uuuu"
This format means :
- optional day-of-week followed by comma and space
[EEEE, ](happens inSunday, ...), - followed by optional day with space
[d ], - followed by month in full letters
MMMMand space, - followed by optional day with comma and space
[d, ], - followed by year of era
uuuuto let the parser know we're in Gregorian era.
Code:
import java.time.format.*; // Required for DateTimeFormatter, *and* ResolverStyle
s->DateTimeFormatter.ofPattern("uuuu/MM/dd") // Output format
.format(
DateTimeFormatter.ofPattern("[EEEE, ][d ]MMMM [d, ]uuuu") // Input format
.withResolverStyle(ResolverStyle.STRICT) // Invalidates xxxx-02-30 instead of transforming it into xxxx-02-28
.parse(
s.replaceAll("(\\d)[a-z].","1ドル") // remove st, nd, rd, th
)
)
Credits
- 2 bytes in the regex thanks to Neil.
-
1\$\begingroup\$ Do you need the brackets in the
replaceAllpattern? \$\endgroup\$Neil– Neil2017年08月26日 11:51:07 +00:00Commented Aug 26, 2017 at 11:51 -
\$\begingroup\$ Looks like I don't. Thanks, @Neil! \$\endgroup\$Olivier Grégoire– Olivier Grégoire2017年08月26日 11:55:22 +00:00Commented Aug 26, 2017 at 11:55
JavaScript (ES6), (削除) 124 (削除ここまで) 122 bytes
f=
s=>(d=new Date(s.replace(/.[dht]\b/,'')+' +0')).getDate()==s.match(/\d\d?/)&&d.toISOString().replace(/-(..)(T.*)?/g,'/1ドル')
<input oninput=o.textContent=f(this.value)><pre id=o>
-
\$\begingroup\$ Returns
2015/06/07forJune 8, 2015(UTC issue? I'm in UTC+2) andfalsefor eitherSunday, June 8, 2015orMonday, June 8, 2015. \$\endgroup\$Olivier Grégoire– Olivier Grégoire2017年08月26日 12:35:55 +00:00Commented Aug 26, 2017 at 12:35 -
1\$\begingroup\$ @OlivierGrégoire Thanks for pointing those out. I'd only tried dates in UK outside Summer Time so they were already using UTC, and I'd not tried weekdays ending in
nday. \$\endgroup\$Neil– Neil2017年08月26日 13:24:36 +00:00Commented Aug 26, 2017 at 13:24
20 February 2014are default supported in a lot of date-parsers, but17thandSunday, June 8, 2015are a bit more difficult to parse (depending on the language). \$\endgroup\$Thursday, August 25, 2017be valid? I see submissions ignoring the DOW. \$\endgroup\$