egervari
egervari

Reputation: 22512

Formatting Date in Freemarker to say "Today", "Yesterday", etc

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

Answers (4)

Ketan Doshi
Ketan Doshi

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

da maddin
da maddin

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

Steven Veltema
Steven Veltema

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

MatBanik
MatBanik

Reputation: 26860

1. Create utility class with following method:

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

2. In your controller add the Class to your model:

modelMap.addAttribute("StringAndDateUtils", new StringAndDateUtils());

3. On your .FTL pages use the method like this:

<#assign date = realDateObject?string("MM/dd/yyyy")/>  
${StringAndDateUtils.yesterdayOrToday(date)}

Upvotes: 3

Related Questions