使用类似于“今天”、“昨天”、“明天”等字符串格式化日期的正确方法是什么?

28

我有一个日期文本视图,其中包含形如2011.09.17的日期字符串。我仍然希望保留这个日期字符串,但也想为某些特定的日期添加一些更加用户友好的信息,比如今天或昨天。例如,如果今天是2011.09.17,我希望我的文本视图显示昨天的值而不是2011.09.16,并且显示今天的值而不是2011.09.17。

我已经成功实现了这个功能,但是用了很多if/else语句,代码很丑陋。如果我想添加新的规则,例如如果日期超过一年,我想放置类似于去年之类的字符串...我就必须再次添加很多不美观的逻辑。

我的问题是,有没有更好的方法来解决这个问题?是否有类似于设计模式的东西可以使用?建议采用哪种方法来实现这个功能?我相信许多人都遇到过这样的问题。

是否有比成千上万个if语句更好的方法?如果没有,那么无论如何感谢你,至少我不会再寻找更优秀的解决方案了。

如果有任何建议、代码片段等,将不胜感激。

谢谢


请在此处检查我的答案 https://dev59.com/AWUq5IYBdhLWcg3wN90t#46086798 - thanhbinh84
这个帖子的最后一个答案不应该标记为正确答案吗? - JP Ventura
请查看此链接 https://dev59.com/nYXca4cB1Zd3GeqPHWLN#60861554 - Affa Musaffa
6个回答

53

10
public class RelativeWeekday {                
    private final Calendar mCalendar;                

    public RelativeWeekday(Calendar calendar) {                
        mCalendar = calendar;                
    }                

    @Override                
    public String toString() {                
        Calendar today = Calendar.getInstance(Locale.getDefault());
        int dayOfYear = mCalendar.get(Calendar.DAY_OF_YEAR);
        if (Math.abs(dayOfYear - today.get(Calendar.DAY_OF_YEAR)) < 2) {
            return getRelativeDay(today);
        }              

        return getWeekDay();                
    }                

    private String getRelativeDay(Calendar today) {                
        return DateUtils.getRelativeTimeSpanString(                
                mCalendar.getTimeInMillis(),                
                today.getTimeInMillis(),                
                DateUtils.DAY_IN_MILLIS,                
                DateUtils.FORMAT_SHOW_WEEKDAY).toString();                
    }                

    private String getWeekDay() {                
        SimpleDateFormat dayFormat = new SimpleDateFormat("EEEE");                
        return dayFormat.format(mCalendar.getTimeInMillis());                
    }                
}

9

我通常使用这个方便的Java库来进行相对时间格式化。 Prety Time Library


3
网址打开空白页面。 - Furqan
我知道这是一个非常老的答案,但是更多地介绍库并包括其他可能性不会有害。很多人不想将库作为默认选项。虽然这取决于@Lukap选择此作为最佳答案... - NoHarmDan

0

试试这个,我使用joda-datatime2.2.jar和java SimpleDateFormat实现了它。

import java.text.SimpleDateFormat;
import java.util.Date;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Days;
public class SmartDateTimeUtil {
private static String getHourMinuteString(Date date){
    SimpleDateFormat hourMinuteFormat = new SimpleDateFormat(" h:m a");
    return hourMinuteFormat.format(date);
}

private static String getDateString(Date date){
    SimpleDateFormat dateStringFormat = new SimpleDateFormat("EEE',' MMM d y',' h:m a");
    return dateStringFormat.format(date);
}

private static boolean isToday (DateTime dateTime) {
       DateMidnight today = new DateMidnight();
       return today.equals(dateTime.toDateMidnight());
}

private static boolean isYesterday (DateTime dateTime) {
       DateMidnight yesterday = (new DateMidnight()).minusDays(1);
       return yesterday.equals(dateTime.toDateMidnight());
}

private static boolean isTomorrow(DateTime dateTime){
    DateMidnight tomorrow = (new DateMidnight()).plusDays(1);
       return tomorrow.equals(dateTime.toDateMidnight());
}
private static String getDayString(Date date) {
        SimpleDateFormat weekdayFormat = new SimpleDateFormat("EEE',' h:m a");
        String s;
        if (isToday(new DateTime(date)))
            s = "Today";
        else if (isYesterday(new DateTime(date)))
            s = "Yesterday," + getHourMinuteString(date);
        else if(isTomorrow(new DateTime(date)))
            s = "Tomorrow," +getHourMinuteString(date);
        else
            s = weekdayFormat.format(date);
        return s;
}

public static String getDateString_shortAndSmart(Date date) {
        String s;
        DateTime nowDT = new DateTime();
        DateTime dateDT = new DateTime(date);
        int days = Days.daysBetween(dateDT, nowDT).getDays();   
        if (isToday(new DateTime(date)))
            s = "Today,"+getHourMinuteString(date);
        else if (days < 7)
            s = getDayString(date);
        else
            s = getDateString(date);
        return s;
}

}

使用和测试Util类的简单示例:

import java.util.Calendar;
import java.util.Date;

public class SmartDateTimeUtilTest {
    public static void main(String[] args) {
        System.out.println("Date now:"+SmartDateTimeUtil.getDateString_shortAndSmart(new Date()));
        System.out.println("Date 5 days before :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(-5)));
        System.out.println("Date 1 day before :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(-1)));
        System.out.println("Date last month:"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureMonth(-1)));
        System.out.println("Date last year:"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDate(-1)));
        System.out.println("Date 1 day after :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(1)));
    }
    public static Date getFutureDate(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.YEAR, numberOfYears); 
        return c.getTime();
    }
    public static Date getFutureMonth(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, numberOfYears); 
        return c.getTime();
    }

    public static Date getFutureDay(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.DATE, numberOfYears); 
        return c.getTime();
    }
}

只是注意到DateMidnight已被弃用。在较新的Joda-Time版本中,使用LocalDate替换DateMidnight应该可以正常工作。 - dabarnard

0

getRelativeTimeSpanString 自API级别3开始添加

getRelativeTimeSpanString(long time,                 long now,                 long minResolution)

返回一个字符串,描述“time”相对于“now”的时间。

过去的时间跨度格式为“42分钟前”。未来的时间跨度格式为“在42分钟内”。 您可以在此处找到更多信息:

https://developer.android.com/reference/android/text/format/DateUtils

    Calendar now = Calendar.getInstance();
    return DateUtils.getRelativeTimeSpanString(time, now.getTimeInMillis(), DateUtils.DAY_IN_MILLIS);

4
虽然这段代码可能回答了问题,但提供关于它如何解决问题以及为什么能够解决问题的额外背景信息会提高答案的长期价值。 - Nic3500

-2

在 Android 中,在 build.gradle 文件中使用 JodaTime 库:

compile 'net.danlew:android.joda:2.9.9'

public static String formateddate(String date) {
    DateTime dateTime = DateTimeFormat.forPattern("dd-MMM-yyyy").parseDateTime(date);
    DateTime today = new DateTime();
    DateTime yesterday = today.minusDays(1);
    DateTime twodaysago = today.minusDays(2);
    DateTime tomorrow= today.minusDays(-1);

    if (dateTime.toLocalDate().equals(today.toLocalDate())) {
        return "Today ";
    } else if (dateTime.toLocalDate().equals(yesterday.toLocalDate())) {
        return "Yesterday ";
    } else if (dateTime.toLocalDate().equals(twodaysago.toLocalDate())) {
        return "2 days ago ";
    } else if (dateTime.toLocalDate().equals(tomorrow.toLocalDate())) {
        return "Tomorrow ";
    } else {
        return date;
    }
}

此解决方案不支持本地化。 - Pierre-Olivier Dybman

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