How long until this date?

11

0

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

Gaffi

Posted 2012-03-15T21:27:17.837

Reputation: 3 411

3Wolfram|Alpha 10 chars: now until <input time> :p – Griffin – 2012-03-15T22:16:57.720

3@Griffin 4 chars: now-<input time> – PhiNotPi – 2012-03-15T22:23:38.093

1@PhiNotPi well played, good sir. – Griffin – 2012-03-15T22:24:41.453

2Is it okay to say "1 days until 3/16/12"? – MrZander – 2012-03-15T23:32:32.283

@MrZander No. I'll update the question. If the number is 1, then there should be no pluralization. – Gaffi – 2012-03-15T23:53:05.257

Welcome to CodeGolf.SE. Every question should be tagged to indicate the class of challenge that is being presented (i.e. if you mean the least characters you want [code-golf]), because we entertain other types of challenges as well, as long as they have an objective winning standard. I'll do this one for you. BTW--Nicely specified.

– dmckee --- ex-moderator kitten – 2012-03-16T00:50:20.787

1How to work with leap yeras in answer? In 10 years then will be 2 days error. How long is month? – Hauleth – 2012-03-16T07:18:37.213

The month is as long as the calendar month. i.e. February 2012 has 29 days, February 2013 has 28. – Gaffi – 2012-03-16T10:36:46.433

Answers

3

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

Paolo

Posted 2012-03-15T21:27:17.837

Reputation: 696

1

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!

Gaffi

Posted 2012-03-15T21:27:17.837

Reputation: 3 411

1It'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) & "," – mellamokb – 2012-03-16T14:23:49.413

@mellamokb Very good. I'll take a look at that and repost! – Gaffi – 2012-03-16T14:27:53.090

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! – Gaffi – 2012-03-16T17:39:57.517

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. – Gaffi – 2012-03-16T17:59:24.637

I imagine I can do this better with arrays... I will take another look and possibly add another answer... – Gaffi – 2012-03-18T07:09:29.863

I think that you could rewrite this using the DateDiff function to drastically lower your bytecount – Taylor Scott – 2017-05-31T15:24:59.147

1

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.

Gareth

Posted 2012-03-15T21:27:17.837

Reputation: 11 678

1

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

jsvnm

Posted 2012-03-15T21:27:17.837

Reputation: 441

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 – Rohit – 2012-03-22T12:09:35.960

@Rohit 1.9.3, not using Rails stuff. Date rdoc

– jsvnm – 2012-03-23T08:16:05.437

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 – Rohit – 2012-03-23T21:57:16.350

@rohit try with 193? – jsvnm – 2012-03-24T10:15:50.150

1

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

rink.attendant.6

Posted 2012-03-15T21:27:17.837

Reputation: 2 776

1

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

Conor

Posted 2012-03-15T21:27:17.837

Reputation: 11

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. – powtac – 2012-05-15T22:18:55.863

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. – powtac – 2012-05-15T22:23:03.440