16
\$\begingroup\$

The formatting order of dates is one of the most complex and divisive issues the world faces today. Some of us vehemently argue that Month/Day/Year is appropriate, considering that's how we say dates out loud. Others loudly proclaim that Day/Month/Year is best, because it puts the terms in ascending order of the duration they represent.

Enough is enough. Computers can resolve this dispute simply and fairly. Your code, a complete function or program, will take a date string delimited by slashes, e.g. 12/1/2015. Note this is the exact format, without leading zeroes and with a four-digit year at the end.

  • If it's definitely Month/Day/Year, e.g. 10/31/1998, output a text representation of that date in this exact format, with the full month name, day, and year: October 31, 1998
  • If it's definitely Day/Month/Year, e.g. 25/12/1989, output the same sort of text representation: December 25, 1989.
  • If it's ambiguous whether it's Month/Day/Year or Day/Month/Year, output a date that resolves the ambiguity by combining the two possible dates as follows:
    1. Create a new month name by taking the first half of the name of the earlier month and append the second half of the later month. For months with odd length, the first half gets the extra letter. To be explicit, the first halves of the months are Janu, Febr, Mar, Apr, Ma, Ju, Ju, Aug, Septe, Octo, Nove, and Dece and the second halves are therefore ary, uary, ch, il, y, ne, ly, ust, mber, ber, mber, and mber.
    2. Calculate the day by averaging the two possible days, taking the floor when the average is not an integer.
    3. Output the text representation of this date, e.g. for 10/8/2011, output Augber 9, 2011.

If the input date cannot be Month/Day/Year or Day/Month/Year (e.g. 13/13/2013 or even 2/30/2002), any behavior is acceptable. This code golf, shortest code wins!

Test cases:

10/31/1998 gives October 31, 1998

25/12/1989 gives December 25, 1989

10/8/2011 gives Augber 9, 2011

8/5/1957 gives Maust 6, 1957

9/12/2012 (oddly enough) gives September 10, 2012

1/1/2000 gives January 1, 2000

\$\endgroup\$
5
  • \$\begingroup\$ Related - codegolf.stackexchange.com/questions/33033/has-my-milk-expired \$\endgroup\$ Dec 2, 2015 at 19:02
  • 20
    \$\begingroup\$ For what it's worth, a lot of those who argue for day-month-year also say dates in that order. (Of course, Real Programmers argue for year-month-day). \$\endgroup\$ Dec 2, 2015 at 19:34
  • \$\begingroup\$ Just to be sure: without leading zeroes and with a four-digit year at the end implies year >= 1000 \$\endgroup\$
    – edc65
    Dec 3, 2015 at 22:15
  • \$\begingroup\$ That's correct. \$\endgroup\$
    – Luke
    Dec 3, 2015 at 23:22
  • 1
    \$\begingroup\$ +∞ for September 10, 2012 \$\endgroup\$
    – user46167
    Dec 3, 2015 at 23:48

7 Answers 7

3
\$\begingroup\$

Mathematica 341 304 298 288 293 bytes

This uses a pure or anonymous function, that is, a function without its own name.

DateString returns an error message if the date is ambiguous. Checkcatches the ambiguity and sends the offending date to DateList, which transforms it into list of 3 integers (which it believes to be {year, month, day}). The month and day integers are sorted by size and used to determine the month and day as per the OP's instructions.

Quiet silences error printing.

t=StringSplit;v=ToString;x=t[#,"-"]&/@t["Janu-ary Febr-uary Mar-ch Apr-il Ma-y Ju-ne Ju-ly Aug-ust Septe-mber Octo-ber Nove-mber Dece-mber"];
Quiet@Check[#~DateString~{"MonthName"," ","DayShort",", ","Year"},
{m,n,o}=DateList@#;{p,q}=Sort@d[[2;;3]];x[[p,1]]<>x[[q,2]]<>" "<>v@Floor@Mean@{n,o}<>", "<>v@d[[1]]]&

t=StringSplit;v=ToString;x=t[#,"-"]&/@t["Janu-ary Febr-uary Mar-ch Apr-il Ma-y Ju-ne Ju-ly Aug-ust Septe-mber Octo-ber Nove-mber Dece-mber"];
Quiet@Check[#~DateString~{"MonthName"," ","DayShort",", ","Year"},
{m,n,o}=DateList@#;{p,q}=Sort@d[[2;;3]];x[[p,1]]<>x[[q,2]]<>" "<>v@Floor@Mean@{n,o}<>", "<>v@d[[1]]]& /@ 
{"10/31/1998","25/12/1989", "10/8/2011", "8/5/1957", "9/12/2012", "1/1/2012"}

{"October 31, 1998", "December 25, 1989", "Augber 9, 2011", "Maust 6, 1957", "September 10, 2012", "January 1, 2012"}

\$\endgroup\$
2
  • \$\begingroup\$ I personally would love to see you eliminate that 0, but I'll let the votes fall as they may. \$\endgroup\$
    – Luke
    Dec 3, 2015 at 0:13
  • \$\begingroup\$ It now returns "January 1, 2012" as requested. \$\endgroup\$
    – DavidC
    Dec 3, 2015 at 2:48
3
\$\begingroup\$

Javascript (ES6), 311 295 282 274 246 238 bytes

a=>(a=a.split`/`,b=c=>e(c).length+1>>1,d=' ',e=f=>new Date(99,a[+f]-1).toLocaleString('en',{month:'long'}),g=+a[0],h=+a[1],i=g>h,j=g>12,k=h>12,(j&&!k?e(1)+d+g:k&&!j?e(0)+d+h:e(i).slice(0,b(i))+e(1-i).slice(b(1-i))+d+((g+h)>>1))+', '+a[2])

Edit: Uses toLocaleString to generate month names. Change the locale to get results using month names in different locales!

Edit 2: Now generates two month names instead of all 12!

Ungolfed:

func = inp => (
    inp = inp.split `/`,
    get = arg => months(arg).length + 1 >> 1,
    space = ' ',
    months = key => new Date(99, inp[+key] - 1).toLocaleString('en', { month: 'long' }),
    tmp1 = +inp[0],
    tmp2 = +inp[1],
    first = tmp1 > tmp2,
    t1greater = tmp1 > 12,
    t2greater = tmp2 > 12,
    (t1greater && !t2greater ?
        months(1) + space + tmp1
    :
        t2greater && !t1greater ?
            months(0) + space + tmp2
        :
            months(first).slice(0, get(first)) + months(1 - first).slice(get(1 - first)) + space + ((tmp1 + tmp2) >> 1)
    )
    + ', ' + inp[2]
)

Example:

console.log(
    func('10/31/1998') + '\n' +
    func('25/12/1989') + '\n' +
    func('10/8/2011') + '\n' +
    func('8/5/1957') + '\n' +
    func('9/12/2012') + '\n' +
    func('1/1/2000')
);

Thanks to:
@user81655, 274 => 246 bytes
@edc65, 246 => 238 bytes

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I haven't looked very thoroughly but here's a few improvements you could make: change Math.ceil(e[c].length/2) to (r=e[c].length/2)+r%1, Array(2).fill().map((_,f)=>...) to f=>... and every e[n] to e(n), i=+(g>h) to i=g>h and e[i] to e[+i], remove the unnecessary brackets in the last ternary operator, Also, newDate should be new Date. \$\endgroup\$
    – user81655
    Dec 3, 2015 at 5:03
  • 1
    \$\begingroup\$ Avoid Math.ceil using b=c=>e(c).length+1>>1 \$\endgroup\$
    – edc65
    Dec 3, 2015 at 22:26
2
\$\begingroup\$

JavaScript ES6, 204

x=>(s=x=>x.split`/`,[a,b,y]=s(x).sort((a,b)=>a-b),(c=b)>12?c=a:b=a- -b>>1,s('/Janu/Febr/Mar/Apr/Ma/Ju/Ju/Aug/Septe/Octo/Nove/Dece')[a]+s('/ary/uary/ch/il/y/ne/ly/ust/mber/ber/mber/mber')[c]+` ${b}, `+y)

Test snippet:

F=x=>(
  s=x=>x.split`/`,
  [a,b,y]=s(x).sort((a,b)=>a-b),
  (c=b)>12?c=a:b=a- -b>>1,
  s('/Janu/Febr/Mar/Apr/Ma/Ju/Ju/Aug/Septe/Octo/Nove/Dece')[a]
  +s('/ary/uary/ch/il/y/ne/ly/ust/mber/ber/mber/mber')[c]+` ${b}, `+y
)

console.log=x=>O.innerHTML+=x+'\n'

;['10/31/1998','25/12/1989','10/8/2011','8/5/1957','9/12/2012','1/1/2000']
.forEach(x=>console.log(x+' -> '+F(x)))
<pre id=O></pre>

\$\endgroup\$
2
\$\begingroup\$

Python 3 (290 bytes)

Similar to Ashwin Gupta's answer, but taking advantage of Python's calendar module to avoid writing out all of the month names.

import calendar as C
M,I,P,S,L,A=C.month_name,int,print," ",len,", "
def d(i):
 w=i.split("/")
 f,s,y=I(w[0]),I(w[1]),w[2]
 if(f>12):P(M[s]+S+w[0]+A+y)
 elif(s>12):P(M[f]+S+w[1]+A+y)
 else:l,h=min(f,s),max(f,s);P(M[l][:I(L(M[l])/2+.5)]+M[h][I(L(M[h])/2+.5):]+S+str(I((f+s)/2))+A+y)

Python 2 should trim a few bytes with integer division and losing the parentheses for print.

\$\endgroup\$
1
\$\begingroup\$

Pyth - 156 bytes

Really bad code, and will need to use packed strings, but its something.

Kc"January February March April May June July August September October November December"dJhM.g>k12=GsMcz\/?<eJ32++@KthJdtP`,eJeGss[@VCcL2KStMPGdPt`,s.OPGeG

Test Suite.

\$\endgroup\$
1
\$\begingroup\$

Python, 558 554 bytes

A really, really, really horribly golfed example of how to do this in python. Sorry, I'm super bad at this golfing stuff D: . It works though. I'm sure there are plenty of ways to simplify this so let me know in the comments. Golfed:

import math
def d(i):
 l=["","January","February","March","April","May","June","July","August","September","October","November","December"]
 w=i.split('/')
 f=int(w[0])
 s=int(w[1])
 S=" "
 y=w[2]
 if(f>12):
  e=int(w[1])
  print(l[e]+S+w[0]+", "+y)
  elif(f<=12 and s>12):
   e=int(w[0])
   print(l[e]+S+w[0]+", "+y)
   else:
    if(f<s):
     o=l[f]
     t=l[s]
    else:
     o=l[s]
     t=l[f]
    o=o[0:int(math.ceil(len(o)/2))]
    t=t[int(math.ceil(len(t)/2)):len(t)]
    print(o+t+S +  str(math.floor((f + s)/2)) + ", " + y)

Ungolfed

import math
def d(i):
    l = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    w = i.split('/')
    f = int(w[0])
    s = int(w[1])
    y = w[2]
    if(f > 12):
        e = int(w[1])
        print(l[e] + " " + w[0] + ", " + y)

    elif(f <= 12 and s > 12):
         e = int(w[0])
         print(l[e] + " " + w[0] + ", " + y)
    else:
         if(f < s):
            o=l[f]
            t=l[s]
         else:
            o=l[s]
            t=l[f]
         o = o[0:int(math.ceil(len(o)/2))]
         t = t[int(math.ceil(len(t)/2)):len(t)]
         print(o+t+" " +  str(math.floor((f + s)/2)) + ", " + y)

Screenshot: enter image description here

\$\endgroup\$
11
  • \$\begingroup\$ put S=" " at the top, then replace every instance of " " with S -- that will shave off some bytes \$\endgroup\$
    – cat
    Dec 3, 2015 at 12:25
  • \$\begingroup\$ there's a few unnecessary spaces after assignments (e= int[..., o = o...). also, it might prove adventageous to set often-used calls like int to single-letter uppercase vars \$\endgroup\$
    – cat
    Dec 3, 2015 at 12:28
  • 1
    \$\begingroup\$ Here's 447 bytes: from math import* I=int S=" " C="," L=len P=print def d(i): l=["","January","February","March","April","May","June","July","August","September","October","November","December"];w=i.split('/');f=I(w[0]);s=I(w[1]);y=w[2] if f>12:e=I(w[1]);P(l[e]+S+w[0]+C+S+y) elif f<13and s>12:e=I(w[0]);P(l[e]+S+w[0]+C+S+y) else: if f<s:o=l[f];t=l[s] else:o=l[s];t=l[f];o=o[0:I(ceil(L(o)/2))];t=t[I(ceil(L(t)/2)):L(t)] P(o+t+S+str(floor((f+s)/2))+C+S+y) \$\endgroup\$
    – cat
    Dec 3, 2015 at 15:06
  • 1
    \$\begingroup\$ @sysreq ok my mind is officially blown. I didn't know you could store functions to a variable. Thank you. I will edit that in. Also, could you do me a favor and try running my code (golfed one) and see if it's working like it should because Luke seems to be getting different results than me so I just want to see. \$\endgroup\$ Dec 3, 2015 at 15:11
  • 1
    \$\begingroup\$ @sysreq yeah idk. Why it's different for him. Anyways, thanks again for the tips, it really helps not only for golfing but in general since I'm still new to Python. Also, I just realized I can remove my initial assignments of o and t and save 4 bytes by putting he array element directly in my splitter. I will make all of these changes this afternoon. Thanks to you the new byte count will be significantly less! \$\endgroup\$ Dec 3, 2015 at 15:20
0
\$\begingroup\$

PHP, 301 294 bytes

function r($t){$e='return date("F",mktime(0,0,0,$o));';list($a,$b,$c)=explode('/',$t);$o=min($a,$b);$m=eval($e);$o=max($a,$b);$n=eval($e);echo(($a|$b)<13)?substr($m,0,ceil(strlen($m)/2)).substr($n,ceil(strlen($n)/2))." ".floor(($a+$b)/2).", $c":date("F j, Y",strtotime(($a>12)?"$b/$a/$c":$t));}

I thought I could compete with the Javascript answer. Oh well.

I think I could make it smaller and I don't like the code I used for the ambiguous dates. I think there is a better way to do it.

Ungolfed:

function r($t){
    // Eval'd code to reduce char count
    $e='return date("F",mktime(0,0,0,$o));';
    
    // Split the date
    list($a,$b,$c)=explode('/',$t);
    
    // Get the earliest month
    $o=min($a,$b);
    $m=eval($e);
    
    // Get the latest month
    $o=max($a,$b);
    $n=eval($e);
    
    // If ambiguous
    if ($a<13 && $b<13) {
        print substr($m,0,ceil(strlen($m)/2)).substr($n,ceil(strlen($n)/2))." ".floor(($a+$b)/2).", $c";
    }
    else {
        print date("F j, Y",strtotime(($a>12)?"$b/$a/$c":$t));
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.