Reputation: 22512
Is there a way in freemarker to compare dates to test if the date is today or yesterday... or do I have to write code in Java to do these tests?
I basically want to do this:
<#------------------------------------------------------------------------------
formatDate
------------------------------------------------------------------------------->
<#macro formatDate date showTime=true>
<#if date??>
<span class="Date">
<#if date?is_today>
Today
<#elseif date?is_yesterday>
Yesterday
<#else>
${date?date}
</#if>
</span>
<#if showTime>
<span class="Time">${date?time}</span>
</#if>
</#if>
</#macro>
EDIT: My best guess to implement this is to pass "today" and "yesterday" into the model for the pages that use this function and then compare the date values against these 2 objects in the model. I am out of out of options, but I'd rather not have to do this for every page that uses this macro. Any other options that are nicer?
<#if date??>
<span class="Date">
<#if date?date?string.short == today?date?string.short>
Today
<#elseif date?date?string.short == yesterday?date?string.short>
Yesterday
<#else>
${date?date}
</#if>
</span>
<#if showTime>
<span class="Time">${date?time}</span>
</#if>
</#if>
Upvotes: 4
Views: 10411
Reputation: 121
${houradd(date, 24)?string("yyyy-MM-dd HH:mm:ss")}
${houradd(date, -24)?string("yyyy-MM-dd HH:mm:ss")}
${dayadd(date, 1)?string("yyyy-MM-dd HH:mm:ss")}
Upvotes: 0
Reputation: 149
As the question is quite old i guess the problem vanished but anyhow, I just did it like this:
<#assign diff = (mydate?long / 86400000)?round - (.now?long / 86400000)?round />
.now is a buildin, 86400 is a constant every programmer might know and if you arent put off by ugly looks this gives you a integer diff of days. today is 0, yesterday is -1 etc.
If you would want to make ?is_today work there is a way to extend the freemarker language by implementing a TemplateDirectiveModel as outlined here:
http://freemarker.sourceforge.net/docs/pgui_datamodel_directive.html
but i dont know yet how to actually add it to available options with the ?... notation :-)
Upvotes: 13
Reputation: 2150
You could convert the string to an int (watch out for rollovers!) and compare as per http://sourceforge.net/projects/freemarker/forums/forum/2345/topic/3027925?message=6479650
Be careful not exceed the maximum int value if you add extra digits like milliseconds.
(from the above link)
[#assign Adate = myDateA?string("yyyyMMdd")?number?int ]
[#assign Atime = myDateA?string("HHmmss")?number?int ]
[#assign Bdate = myDateB?string("yyyyMMdd")?number?int ]
[#assign Btime = myDateB?string("HHmmss")?number?int ]
What I did was create a TemplateMethodModel for comparing dates (Note: df is a custom thread safe SimpleDateFormatter with a timezone):
public BooleanModel exec(List args) throws TemplateModelException {
int argcnt = args.size();
if (argcnt != 3) {
throw new TemplateModelException("Wrong arguments. Use \"exec(Date?string(\"yyyyMMddHHmmss\"), " +
"CompareString, Date?string(\"yyyyMMddHHmmss\"))\"," +
" where CompareString is < = > ");
}
String firstDate = (String) args.get(0);
String compareString = (String) args.get(1);
String secondDate = (String) args.get(2);
if (null == firstDate || null == secondDate || null == compareString ||
compareString.length() != 1) {
throw new TemplateModelException("Wrong arguments. Use \"exec(Date?string(\"yyyyMMddHHmmss\"), " +
"CompareString, Date?string(\"yyyyMMddHHmmss\"))\"," +
" where CompareString is < = > ");
}
Date first = null;
Date second = null;
try {
first = df.parse(firstDate);
second = df.parse(secondDate);
} catch (ParseException e) {
throw new TemplateModelException("Wrong arguments. Use \"exec(Date?string(\"yyyyMMddHHmmss\"), " +
"CompareString, Date?string(\"yyyyMMddHHmmss\"))\"," +
" where CompareString is < = > ");
}
if ("<".equals(compareString)) {
return new BooleanModel(first.before(second), BeansWrapper.getDefaultInstance());
}
else if ("=".equals(compareString)) {
return new BooleanModel(first.equals(second), BeansWrapper.getDefaultInstance());
}
else if (">".equals(compareString)) {
return new BooleanModel(first.after(second), BeansWrapper.getDefaultInstance());
}
return new BooleanModel(Boolean.FALSE, BeansWrapper.getDefaultInstance());
}
In the template I call it as follows:
[#if compareDate(now?string("yyyyMMddHHmmss"),"<", program.resStartDateTime?string("yyyyMMddHHmmss"))]
FYI, "now" is a DateModel object added before template processing.
model.put("now", new DateModel(new Date(), BeansWrapper.getDefaultInstance()));
The TemplateMethodModel could be made more general by passing in a parsing string as an argument and creating the date formatter on execution.
Upvotes: 1
Reputation: 26860
import org.joda.time.format.*;
...
public class StringAndDateUtils {
public static String yesterdayOrToday(String date) {
DateTime dateTime = DateTimeFormat.forPattern("MM/dd/yyyy").parseDateTime(date);
DateTime today = new DateTime();
DateTime yesterday = today.minusDays(1);
if (dateTime.toLocalDate().equals(today.toLocalDate())) {
return "Today " ;
} else if (dateTime.toLocalDate().equals(yesterday.toLocalDate())) {
return "Yesterday " ;
} else {
return date;
}
}
}
modelMap.addAttribute("StringAndDateUtils", new StringAndDateUtils());
<#assign date = realDateObject?string("MM/dd/yyyy")/>
${StringAndDateUtils.yesterdayOrToday(date)}
Upvotes: 3