在Freemarker中格式化日期为“今天”、“昨天”等

4
有没有一种在freemarker中比较日期的方式来测试日期是否是今天或昨天...还是我必须编写Java代码来执行这些测试?
我想做的基本上是这样的:
<#------------------------------------------------------------------------------
 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>

编辑: 我最好的猜测是为使用此功能的页面将“今天”和“昨天”传递到模型中,然后将日期值与这两个对象在模型中进行比较。我已经没有其他选项了,但我不想为每个使用此宏的页面都这样做。还有其他更好的选择吗?

<#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>

请记住,Freemarker只是一种模板语言...任何超出最简单逻辑的东西都会让它过度紧张。 - skaffman
@skaffman:是的,我知道。我真的很喜欢它。但对我来说,我真的希望它可以做这样的事情 - 即使作为内置功能 - 因为这是演示逻辑类型的东西,而不是业务逻辑。将这种类型的内容放在控制器中实际上会使它们变得臃肿。 - egervari
4个回答

13

由于这个问题很老了,我猜问题已经消失了,但是无论如何,我就是这样做的:

<#assign diff = (mydate?long / 86400000)?round - (.now?long / 86400000)?round />

.now 是一个内置函数,86400 是所有程序员都可能知道的常量,如果你不介意丑陋的外观,这将给你带来一些整数天的差异。 今天是0,昨天是-1等。

如果你想让 ?is_today 工作,可以通过实现 TemplateDirectiveModel 来扩展 freemarker 语言,如此处所述:

http://freemarker.sourceforge.net/docs/pgui_datamodel_directive.html

但我还不知道如何使用 ?... 符号将其添加到可用选项中 :-)


1
我认为你应该使用 ?floor 而不是 ?round,因为 ?round 会在中午而不是午夜时更改日期。 - cherouvim

3

1. 创建以下方法的实用类:

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. 在您的控制器中将类添加到模型:

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

3. 在您的.FTL页面上使用以下方式:

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

比将逻辑放在控制器中并通过模型传递变量更加简洁。 - Nick Spacek

1

你可以将字符串转换为整数(注意溢出!),然后按照以下方式进行比较: http://sourceforge.net/projects/freemarker/forums/forum/2345/topic/3027925?message=6479650

如果添加额外的数字,如毫秒,请注意不要超过最大整数值。

(来自上面的链接)

[#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 ]

我所做的是创建一个TemplateMethodModel来比较日期(注意:df是一个自定义线程安全的SimpleDateFormatter,带有时区):
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());

}

在模板中,我这样调用它:

[#if compareDate(now?string("yyyyMMddHHmmss"),"<", program.resStartDateTime?string("yyyyMMddHHmmss"))]

顺便提一下,“now”是在模板处理之前添加的DateModel对象。

model.put("now", new DateModel(new Date(), BeansWrapper.getDefaultInstance()));

通过将解析字符串作为参数传递并在执行时创建日期格式化程序,可以使TemplateMethodModel更加通用。


0

${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")}

这段代码与编程有关。

我在文档中找不到这个... 它是一个扩展还是什么? - DanielBlazquez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接