Reputation: 75
I am currently working on modifying an existing function, by Ray, that checks the time elapsed and remaining:
Here is the function:
function ago(date){
var interval = "";
var offset = 0;
var result = 0;
if (isDate(arguments.date)){
var formattedDate = dateFormat(arguments.date, "dddd dd mmmm yyyy");
var k = datediff('d',arguments.date,now());
//writedump(k);
//abort;
if(k contains '-') {
if (dateDiff("s", now(), arguments.date) < 60){
// less than 1 minute show interval in seconds
offset = dateDiff("s", now(),arguments.date);
interval= offset == 1 ? "second":"seconds";
result = "#offset# #interval# left";
}else if (dateDiff("n",now(),arguments.date) < 60){
// less than 1 hour show interval in minutes
offset = dateDiff("n", now(),arguments.date);
interval= offset == 1 ? "minute":"minutes";
result = "#offset# #interval# left";
}else if (dateDiff("h",now(),arguments.date) < 24){
// less than 24 hours display interval in hours
offset = dateDiff("h", now(), arguments.date);
interval = offset == 1 ? "hour":"hours";
result = "#offset# #interval# left";
}else if (dateDiff("d",now(),arguments.date) < 2){
// less than 2 days display yesterday
result = "Tommarrow";
}else if (dateDiff("d", now(), arguments.date) < 7){
// less than 7 days display day
result = dayOfWeekAsString( dayOfWeek( arguments.date ));
}else if (dateDiff("w", now(), arguments.date)){
offset = dateDiff("w",now(), arguments.date);
interval = offset == 1 ? "week":"weeks";
result = "#offset# #interval# left";
}else if (dateDiff("m", now(), arguments.date)){
offset = dateDiff("m",now(), arguments.date);
interval = offset == 1 ? "month":"months";
result = "#offset# #interval# left";
}else if (dateDiff("yyyy", now(), arguments.date)){
offset = dateDiff("yyyy", now(), arguments.date);
interval = offset == 1 ? "year":"years";
result = "#offset# #interval# left";
}
else{
// otherwise display date
result = formattedDate;
}
}
else {
if (dateDiff("s", arguments.date, now()) < 60){
// less than 1 minute show interval in seconds
offset = dateDiff("s", arguments.date, now());
interval= offset == 1 ? "second":"seconds";
result = "#offset# #interval# ago";
}else if (dateDiff("n", arguments.date, now()) < 60){
// less than 1 hour show interval in minutes
offset = dateDiff("n", arguments.date, now());
interval= offset == 1 ? "minute":"minutes";
result = "#offset# #interval# ago";
}else if (dateDiff("h", arguments.date, now()) < 24){
// less than 24 hours display interval in hours
offset = dateDiff("h", arguments.date, now());
interval = offset == 1 ? "hour":"hours";
result = "#offset# #interval# ago";
}else if (dateDiff("d", arguments.date, now()) < 2){
// less than 2 days display yesterday
result = "yesterday";
}else if (dateDiff("d", arguments.date, now()) < 7){
// less than 7 days display day
result = dayOfWeekAsString( dayOfWeek( arguments.date ));
}else if (dateDiff("w", arguments.date, now())){
offset = dateDiff("w", arguments.date, now());
interval = offset == 1 ? "week":"weeks";
result = "#offset# #interval# ago";
}else if (dateDiff("m", arguments.date, now())){
offset = dateDiff("m", arguments.date, now());
interval = offset == 1 ? "month":"months";
result = "#offset# #interval# ago";
}else if (dateDiff("yyyy", arguments.date, now())){
offset = dateDiff("yyyy", arguments.date, now());
interval = offset == 1 ? "year":"years";
result = "#offset# #interval# ago";
}
else{
// otherwise display date
result = formattedDate;
}
}
interval = "<abbr title='" & formattedDate & "'>" & result & "</abbr>";
}
return interval;
}
The result is "1 week left" or "2 weeks ago". But rather than "2 weeks", it should show me "1 week 4 days", or whatever the days remaining are, unless it is exactly "2 weeks".
Upvotes: 0
Views: 408
Reputation: 1069
Wow that is a lot of if statements, probably better to look for a calculated approach like the following:
<cfset date1 = CreateDate(2014,07,07)>
<cfset date2 = CreateDate(2014,07,19)>
<cfset dateDifference = dateDiff("d",date1,date2)>
<cfset weeks = int(dateDifference/7)>
<cfset days = dateDifference MOD 7>
<cfoutput>
#weeks# weeks and #days# days ago
</cfoutput>
Then if you need to do it the other way around, e.g. weeks and days until, you can to that as well, just change the output text. All you need to do is make sure that date1 is always before (in time) than date2.
UPDATE After looking at this again and based on what your where looking for I found this blog post from Steve Withington:
I then took his code and turned it into a function that I think should do what you want, or pretty close to it:
<cfscript>
function timeUntil(dateStart, dateEnd) {
var compareGivenDates = DateCompare(arguments.dateStart, arguments.dateEnd, "s");
var rightNow = DateFormat(now(), "mm/dd/yyyy") & " " & TimeFormat(now(), "hh:mm:ss tt");
var compareNow = DateCompare(rightNow, arguments.dateStart, "s");
switch (compareNow) {
case -1:
throw(message="End date must be after start date", detail="The end date must be after the start date otherwise the calculations will not be possible.");
case 1:
var arguments.dateStart = rightNow;
}
var returnTimeRemaining="";
var dateStart = DateFormat(arguments.dateStart, "mm/dd/yyyy") & " " & TimeFormat(arguments.dateStart, "hh:mm:ss tt");
var dateEnd = DateFormat(arguments.dateEnd, "mm/dd/yyyy") & " " & TimeFormat(arguments.dateEnd, "hh:mm:ss tt");
var hdif = Abs(DateDiff("h", dateEnd, dateStart));
var ndif = Abs(DateDiff("n", dateEnd, dateStart));
var sdif = Abs(DateDiff("s", dateEnd, dateStart));
var years2go = Abs(DateDiff("yyyy", dateEnd, dateStart));
var months2go = Abs(DateDiff("m", dateEnd, dateStart));
var weeks2go = Abs(DateDiff("ww", dateEnd, dateStart));
var days2go = Abs(DateDiff("d", dateEnd, dateStart));
if (DatePart('h', now()) LT 12 OR days2go EQ 1) {
var h = 'h';
} else {
var h = 'H';
}
var hours2go = TimeFormat(dateEnd-dateStart, h);
var min2go = TimeFormat("#dateEnd-dateStart#", "m");
var sec2go = TimeFormat("#dateEnd-dateStart#", "s");
var newmonths = months2go-(years2go*12);
var tempDate = dateadd("m", months2go, arguments.dateStart);
var newweeks = Abs(DateDiff("ww", arguments.dateEnd, tempDate));
var tempdays = Abs(DateDiff("d", arguments.dateEnd, tempDate));
var newdays = tempdays-(newweeks*7);
var comparison = DateCompare(dateStart, dateEnd, "s");
switch (comparison) {
case -1:
if (years2go GTE 1) {
returnTimeRemaining = returnTimeRemaining & "#years2go#y ";
}
if (newmonths GTE 1) {
returnTimeRemaining = returnTimeRemaining & "#newmonths#m ";
}
if (newweeks GTE 1) {
returnTimeRemaining = returnTimeRemaining & "#newweeks#w ";
}
if (newdays GTE 1) {
returnTimeRemaining = returnTimeRemaining & "#newdays#d ";
}
if (ndif GTE 60) {
returnTimeRemaining = returnTimeRemaining & "#hours2go#h ";
}
if (sdif GTE 60) {
returnTimeRemaining = returnTimeRemaining & "#min2go#m ";
}
if (sdif GTE 1) {
returnTimeRemaining = returnTimeRemaining & "#sec2go#s";
} else {
returnTimeRemaining = "0s";
}
break;
case 0:
returnTimeRemaining = false;
break;
case 1:
returnTimeRemaining = false;
break;
}
return returnTimeRemaining
}
</cfscript>
<cfoutput>
#timeUntil(CreateDateTime(2013, 7, 19, 0, 0, 0), now())#
</cfoutput>
Apart from converting it to script and making it a function, there are a few changes in here from Steve's original to get it to not return the months, weeks, days, etc... when they are 0. I've run a load of test dates through it and it appears to work ok for all the cases I have tried. Still feel there is far more code there then should be necessary but I don't have the time to spend refactoring it down.
UPDATE 2
Used this code in a programming hack session today and refactored it and improved it to the following:
<cfscript>
public string function timeDifferenceFormattedString(
required date dateStart,
date dateEnd = Now()
) {
// Is datestart actually after dateend?
switch (DateCompare(arguments.dateStart,arguments.dateEnd)) {
case 1:
var suffix = 'since';
var currentLowerDate = arguments.dateEnd;
var currentUpperDate = arguments.dateStart;
break;
case 0:
return 'The dates are the same';
break;
case -1:
var suffix = 'until';
var currentLowerDate = arguments.dateStart;
var currentUpperDate = arguments.dateEnd;
break;
}
var arrDateParts = [ 'yyyy' , 'm' , 'ww' , 'd', 'h', 'n', 's' ];
var arrDatePartsHuman = [ 'year' , 'month' , 'week' , 'day', 'hour', 'minute', 'second' ];
var arrDateDiffs = [];
for ( var i = 1; i<=ArrayLen(arrDateParts);i++ ) {
var thisDiff = Int(DateDiff( arrDateParts[i] , currentLowerDate, currentUpperDate ));
if (
thisDiff > 0
) {
arrDateDiffs.add( thisDiff & ' ' & arrDatePartsHuman[i] & ( thisDiff > 1 ? 's' : '' ) );
currentLowerDate = DateAdd( arrDateParts[i] , thisDiff, currentLowerDate );
}
}
arrDateDiffs.add(suffix);
return ArrayToList(arrDateDiffs,' ');
}
</cfscript>
<cfoutput>
<p>#timeDifferenceFormattedString(CreateDateTime(2013, 7, 10, 0, 0, 0), now())#</p>
<p>#timeDifferenceFormattedString(CreateDateTime(2013, 7, 10, 0, 0, 0), CreateDateTime(2013, 7, 10, 0, 0, 0))#</p>
<p>#timeDifferenceFormattedString(now(),CreateDateTime(2013, 7, 10, 0, 0, 0))#</p>
</cfoutput>
To take this further again you could pass in the "human" output values and suffixes as well to make the string formatting even more flexible.
Upvotes: 2