11
\$\begingroup\$

The idea is this: Write a function to print the length of time from now/today's date (at the time the function is called) until a date supplied as an argument.

Assumptions:

  • Input date will always be tomorrow or later, in the future.
  • Input date will never be more than 10 years in the future.

Rules:

  • Output must be in this format: "[z year(s)], [x month(s)], y day(s) until -Input Date-"
  • Output time frame (day/month/year) must be pluralized correctly. i.e. 1 month, not 1 months
  • Input can be in whichever date format you prefer (3/15/12 - March 15, 2012 - 2012.03.15).

Example: Assuming program is run on March 15, 2012:

  • Input date of 3/20/12 = 5 days until 3/20/12
  • NOT Input date of 4/16/12 = 1 month, 1 days until 3/20/12
  • Input date of 2012.04.20 = 1 month, 5 days until 2012.04.20
  • NOT Input date of 2012.04.20 = 36 days until 2012.04.20
  • Input date of 10/31/17 = 5 years, 7 months, 16 days until 10/31/17
  • Input date of 3/15/13 = 1 year until 3/15/13

This is code golf, so shortest length code wins.

I suppose for the sake of having a deadline, I will be selecting an answer on:

March 23, 2012!

(This is my first CG question, so I'll be happy to correct any question errors on my part!)

\$\endgroup\$
  • 3
    \$\begingroup\$ Wolfram|Alpha 10 chars: now until <input time> :p \$\endgroup\$ – Griffin Mar 15 '12 at 22:16
  • 3
    \$\begingroup\$ @Griffin 4 chars: now-<input time> \$\endgroup\$ – PhiNotPi Mar 15 '12 at 22:23
  • 1
    \$\begingroup\$ @PhiNotPi well played, good sir. \$\endgroup\$ – Griffin Mar 15 '12 at 22:24
  • 2
    \$\begingroup\$ Is it okay to say "1 days until 3/16/12"? \$\endgroup\$ – MrZander Mar 15 '12 at 23:32
  • 1
    \$\begingroup\$ How to work with leap yeras in answer? In 10 years then will be 2 days error. How long is month? \$\endgroup\$ – Hauleth Mar 16 '12 at 7:18
3
\$\begingroup\$

R, 99 characters

I know it is sort of cheating, but R is all about its packages and lubridate is so convenient for this kind of tasks!

f=function(x){library(lubridate);cat(show(as.period(interval(mdy("3/15/2012"),mdy(x)))),"until",x)}

Usage:

f("10/31/2017")
[1] 5 years, 7 months and 16 days 
5 years, 7 months and 16 days  until 10/31/2017
\$\endgroup\$
1
\$\begingroup\$

PHP, 315 characters

function p($z)
{
list($d,$m,$y)=explode("/",$z);
$d=$d-date("d");
$n=$m-1;
$m=$m-date("m")-($d<0);
$d=$d+($d<0)*($n>7^$n&1)+27+($n-2?3:($y%4?1:($y%100?2:($y%400?1:2))));
$y=$y-date("Y")-($m<0);
$s="s ";
echo ($y?$y." year".$s[$y<2]:"")." ".($m?$m." month".$s[$m<2]:"")." ".($d?$d." day".$s[$d<2]:"")." until ".$z;
}

Usage:

p("11/03/2006");

Takes dates in a dd/mm/yyyy format. I've used Griffin's month length calculation(again), though I had to stick extra brackets in it to make the precedence work properly. I've also left some line-breaks in to make it a little easier to read.

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

Ruby (213)

takes dates in any format Date.parse accepts. Tried just with yyyy-mm-dd

def u s
t=Date.today
f=Date.parse s
[[0,'year'],[0,'month'],[0,'day']].map{|c,n| while t<f 
c+=1
t=t.send"next_#{n}"
end
c,t=c-1,t.send("prev_#{n}")if t>f
[c,n+(c>1??s:'')]*' 'if c>0}.compact*', '+' until '+s
end

to also get weeks, add:

['prev_','next_'].each{|n|Date.send(:define_method,n+'week'){send n+'day',7}}

and [0,'week'], (between month and day). days will then always be < 7

\$\endgroup\$
  • \$\begingroup\$ which ruby version are you using.... I tried to run your code on ruby1.9.2p0, but it gives me error uninitialized constant Object::Date (NameError)... I think you are using the Rails Date class \$\endgroup\$ – Rohit Mar 22 '12 at 12:09
  • \$\begingroup\$ @Rohit 1.9.3, not using Rails stuff. Date rdoc \$\endgroup\$ – jsvnm Mar 23 '12 at 8:16
  • \$\begingroup\$ I saw the doc earlier.. but was confused on the error I was getting... I am still unable to figure out why I am getting this error. I am on windows 7 64-bit, ruby192p0 \$\endgroup\$ – Rohit Mar 23 '12 at 21:57
  • \$\begingroup\$ @rohit try with 193? \$\endgroup\$ – jsvnm Mar 24 '12 at 10:15
1
\$\begingroup\$

VBA: 766 631 Chars

Thanks to mellamokb for helping shorten up the string creation and IIf.

Function k(i)
e=" month"
g="s"
n=Now()
r=Month(n)
s=Month(i)
t=DateSerial(Year(i),s,1)
u=DateSerial(Year(i),s-1,1)
v=Day(n)
w=Day(i)
x=DateSerial(Year(n),r,1)
d=t-u-v+w
For y=0 To 10
If Year(DateAdd("yyyy",-1*y,i))=Year(n) Then Exit For
Next
y=IIf(s=1,y-1,y)
z=s-r
z=IIf(z<0,z+12,z)
For m=0 To z
If Month(DateAdd("m",-1*m,i))=r Then Exit For
Next
d=IIf(v<=w,w-v,d)
m=IIf(v>w,m-1,m)
If y Then a=y & " year" & Left(g,y-1)
a=IIf((m Or d) And y,a & ",",a)
If m Then b=IIf(d,m & e & Left(g,m-1) & ",",m & e & Left(g,m-1))
If d Then c=IIf(d>1,d & " days",d & " day")
k=Trim(Trim(a & " " & b) & " " & c) & " until " & i & "."
End Function

I know VBA definitely does not lend itself to code golfing as well as some other languages, but it's what I'm good (not expert) at. :-)

This has been a fun exercise for me!

\$\endgroup\$
  • 1
    \$\begingroup\$ It's not entirely VBA's fault, there are some good ways to combine logic in your code :) For example, If y > 0 Then a = y & " year,":If y > 1 Then a = y & " years," could be combined together to a = y & " year" & Left("s", y - 1) & "," \$\endgroup\$ – mellamokb Mar 16 '12 at 14:23
  • \$\begingroup\$ @mellamokb Very good. I'll take a look at that and repost! \$\endgroup\$ – Gaffi Mar 16 '12 at 14:27
  • \$\begingroup\$ I had an issue with some test cases, namely 1 year, 1 month, 1 day. I have corrected this in the answer. It actually made for shorter code! \$\endgroup\$ – Gaffi Mar 16 '12 at 17:39
  • \$\begingroup\$ And after posting the update, I see that I can change If v < w Then d = w - v:If v = w Then d = 0 to If v <= w Then d = w - v for a savings of an additional 20 characters. I'll update the answer if I have a more significant change to post. \$\endgroup\$ – Gaffi Mar 16 '12 at 17:59
  • \$\begingroup\$ I imagine I can do this better with arrays... I will take another look and possibly add another answer... \$\endgroup\$ – Gaffi Mar 18 '12 at 7:09
1
\$\begingroup\$

JavaScript (ES6), 125 bytes

Since the answer by Paolo used an external library, I shall do the same. Node.js is all about NPM packages and moment + HumanizeDuration is so convenient for this task!

Node environments

m=require('moment'),f=d=>console.log(require('humanize-duration')(m(d).diff(m()),{units:['y','mo','d'],round:1})+' until '+d)

Browser environment

Since the libraries declare global variables, it's actually a bit shorter (102 bytes). It's not clear whether I need to include the script tags required to load in the third-party JavaScript, so I will count the Node one officially.

f=d=>console.log(humanizeDuration((m=moment)(d).diff(m()),{units:['y','mo','d'],round:1})+' until '+d)

CoffeeScript, also 125 bytes

f=(d)->console.log require('humanize-duration')((m=require 'moment')(d).diff(m()),{units:['y','mo','d'],round:1})+' until '+d
\$\endgroup\$
1
\$\begingroup\$

PHP, 151 chars

function p($z){$n=date_create(date('Y-m-d'));$d=date_create($z);$i=date_diff($n,$d);print($i->format('%R%y years, %m months, and %a days until '.$z));}
\$\endgroup\$
  • \$\begingroup\$ It is missing the plurals and does not count correctly, because format() does not subtract the days from the months... I had a similar solution with PHP as well. \$\endgroup\$ – powtac May 15 '12 at 22:18
  • \$\begingroup\$ This is my PHP solution, but still lacks of the previously mentioned error: echo date_diff(new DateTime(),new DateTime($argv[1]))->format('%yyears, %mmonths, %a days'); Its 92 chars long, when called on the command line. \$\endgroup\$ – powtac May 15 '12 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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