For the past few days I've been meaning to write up a simple example of how one would do a "There are X days till Christmas" type code block. It is mostly simple in ColdFusion so let's look at a quick example.
First, you have to figure out what you want to do for each of the 3 "states":
- the days leading up to your event
- the day of your event
- the day after your event
For the days leading up to the event you will typically simply print, "There are X days until Y." For the day of the event you may print something like, "Today is Y!". For the day after the event, you may do nothing. Most of all though you want to be sure not to say "There are -X days until Y." (Another alternative is to count the days until next years event.)
So to handle this in ColdFusion you first want to create a date object. This can be done by simply providing the year, month, and day of your event. For this blog post I'll use April 8. (Yes, my birthday. ;)
<cfset day = createDate(2007, 4, 8)>
Next we simply need to figure out how many days away from today that date is. For this we use dateDiff:
<cfset daystill = dateDiff("d", now(), day)>
The first argument tells the function what unit to use in figuring out the difference. As an example, we may want to know how many hours until our event. But for now, we just want the days.
This will return 3 things. If it is a positive number, it is the number of days till my birthday. If it is 0, it means that today is my birthday. If it is a negative number, it means my birthday has passed.
So a real quick check can be done like so:
<cfif daystill gt 0>
<cfoutput>There are #daystill# day(s) my birthday. Plenty of time to visit my wishlist!</cfoutput>
<cfelseif daystill is 0>
<cfoutput>Happy Birthday to me! Did you visit my wishlist?</cfoutput>
<cfelse>
<cfoutput>My birthday passed #abs(daystill)# day(s) ago - did you get my anything?</cfoutput>
</cfif>
In case you are wondering, the abs function simply takes the absolute value of a number. It is a quick way to turn -X into X.
So this works fine and well, until the day before the event. Try running my code and using 2007, 3, 28 for the values. (Obviously if you are not reading this blog entry on March 27th you need to use another value.) The result you get says that today is my birthday. Why?
Well when the date object is created, ColdFusion has to make assumptions for the time of the date object. What time did ColdFusion use? A quick test will show us:
<cfoutput>#timeformat(day)#<P></cfoutput>
If you run this code you will see 12:00AM. So when the date is tomorrow, ColdFusion correctly states that it is not more than 24 hours away.
So there are a few ways we could handle this. One way I found is to simply switch to using the number of hours between the dates:
<cfset daystill = dateDiff("h", now(), day)>
Using the example of tomorrow as the event, this will return some number less then 24, but greater then 0. I can divide this by 24 and round up.
<cfset realdiff = ceiling(daystill/24)>
This will give me a result of 1 for tomorrow. I then simply use realdiff in my conditional:
<cfif realdiff gt 0>
<cfoutput>There are #realdiff# day(s) my birthday. Plenty of time to visit my wishlist!</cfoutput>
<cfelseif realdiff is 0>
<cfoutput>Happy Birthday to me! Did you visit my wishlist?</cfoutput>
<cfelse>
<cfoutput>My birthday passed #abs(realdiff)# day(s) ago - did you get my anything?</cfoutput>
</cfif>
Archived Comments
Is this a subtle reminder to get you something off of your wishlist for your birthday? ;)
Nothing subtle about it. ;)
I think if you Fix() the Now() call, you don't have to worry about the time:
DateDiff( "d", Fix( Now() ), day )
That should strip out the time leaving you with a proper day-diff calculation. Date-math is cool!
4/8 eh? Now, where the heck is that wish list ;)
Couldn't one achive the same by using
<cfset day = CreateDateTime(2007, 4, 8, 23, 59, 59)>
to start with instead of just CreateDate?
side question. Someone had always told me using IS unstead of EQ uses more overhead in evaluating. Any confirmation or dissuation ? :D
I think the IS vs. EQ used to be true back in the day, but now that CF is compiled down into Java bytes code, i am sure there is absolutely no difference. The compiler will take care of all the optimization. I think is comes down to personal preference.
Now...what about timezone differences? If I visit your page served from CST at 11:30pm your time (12:30am my time) then your script will show me the wrong number of days - even with the time stripped.
The time is calculated on the server which is always in the same place and appropriate for Ray... your personal time zone does not alter the time Ray was born ;)
But I know what you are saying. I, however, know nothing about internationalization :(
Look *we* all know the world revolves around Ray (I mean...duh), but I'm thinking there may be a few unenlightened souls out there who might be genuinely confused to see that his day count doesn't match theirs. :-)
I've never had to handle this with dates, but I assume that either the LS functions or UTCOffset() will handle this need nicely. I just wanted to point out that it was missing in Ray's example so no one got confused.
I would definitely be interested to know how that works. I have never taken timezone into account in my apps.
Ray, when is your Bday?
Oh, duh... 4/8! Our birthdays are 4 days apart.
Sometimes I'll do <cfset today=DateFormat(Now())> and then have a compare line like <cfset daystill=dateDiff("d", today, day)>. This also takes care of the time issue.
Joshua, I don't think that does handle the date time issue as the Now() function generates time based upon the server's time, not GMT. I could be wrong, but this is the way I understand it.
Wow, lots of comments here. I'll have to be quick as I'm doing training now. (Notice how low my blog posts are this week? Sorry folks. )
Mark/Ben - your first comments about other fixes - you say "couldn't" as if you didn't try - did you try them and did they indeed work?
is verus eq: ditto ben. no big deal anymore.
timezones: So the quick answer is - at some point you have to make a basic assumption about your audience. So I don't think it is a big deal for a web site to assume an American time zone, especially if it is an American company. Of course, as an American I'm biased. ;) But if you DID know the users TZ, you could simply add that to now(), right?
Joshua (and Ben/Mark), thanks for pointing out simpler solutions. I'll try to post a follow entry tonight since some folks never read the comments. I'll be taking full credit and deleting your comments of course. All part of my master plan!
@Ray: Lol. That would not be very Jedi-like.
@TJ: I was just addressing Ray's post, specifically regarding date arithmetic without time. I wasn't getting into the timezone quagmire. :-)