java类似Outlook的时间分组

用过Outlook的同学都知道在Inbox中如果选择"Arranged By: Date",所有的邮件会按照日期进行排序或者分组。

这样分组后对邮件的大概接收日期范围就比较清晰了。

以下是类似的实现:


import java.util.ArrayList;
import java.util.Calendar;

public class DateGroup {

    public static final int GROUP_INVALID = 0;
    public static final int GROUP_BEYOND_NEXT_MONTH = GROUP_INVALID + 1;
    public static final int GROUP_NEXT_MONTH = GROUP_BEYOND_NEXT_MONTH + 1;
    public static final int GROUP_LATER_THIS_MONTH = GROUP_NEXT_MONTH + 1;
    public static final int GROUP_3_WEEKS_AWAY = GROUP_LATER_THIS_MONTH + 1;
    public static final int GROUP_2_WEEKS_AWAY = GROUP_3_WEEKS_AWAY + 1;
    public static final int GROUP_NEXT_WEEK = GROUP_2_WEEKS_AWAY + 1;
    public static final int GROUP_THIS_WEEK_AFTER_TOMORROW = GROUP_NEXT_WEEK + 1;
    public static final int GROUP_TOMORROW = GROUP_THIS_WEEK_AFTER_TOMORROW + 1;
    public static final int GROUP_TODAY = GROUP_TOMORROW + 1;
    public static final int GROUP_YESTERDAY = GROUP_TODAY + 1;
    public static final int GROUP_THIS_WEEK_BEFORE_YESTERDAY = GROUP_YESTERDAY + 1;
    public static final int GROUP_LAST_WEEK = GROUP_THIS_WEEK_BEFORE_YESTERDAY + 1;
    public static final int GROUP_2_WEEKS_AGO = GROUP_LAST_WEEK + 1;
    public static final int GROUP_3_WEEKS_AGO = GROUP_2_WEEKS_AGO + 1;
    public static final int GROUP_EARLIER_THIS_MONTH = GROUP_3_WEEKS_AGO + 1;
    public static final int GROUP_LAST_MONTH = GROUP_EARLIER_THIS_MONTH + 1;
    public static final int GROUP_OLDER = GROUP_LAST_MONTH + 1;
    
    /**
     * Get the date group for a sorted date list (like outlook inbox):
     * 
     * <pre>
     *      Groups:
     *      beyond next month: yyyy/MM/dd 
     *      next month: yyyy/MM/dd
     *      later this month: yyyy/MM/dd
     *      three weeks away: yyyy/MM/dd
     *      two weeks away: yyyy/MM/dd
     *      next week: MM/dd (week)
     *      this week after tomorrow: HH:mm
     *      tomorrow: HH:mm
     *      today: HH:mm
     *      yesterday: HH:mm
     *      this week before yesterday: HH:mm
     *      last week: MM/dd (week)
     *      two weeks ago: yyyy/MM/dd
     *      three weeks ago: yyyy/MM/dd
     *      earlier this month: yyyy/MM/dd
     *      last month: yyyy/MM/dd
     *      older: yyyy/MM/dd
     * </pre>
     * 
     * @param dateList
     *            - the sorted date list (ASC or DESC)
     * @return
     */
    public static int[] getDateGroup(ArrayList<Calendar> dateList) {
        return getDateGroup(getToday(), dateList);
    }
    
    public static int[] getDateGroup(Calendar today, ArrayList<Calendar> dateList) {
        int size = dateList.size();
        int[] groupArray = new int[size];
        for (int i = 0; i < size; i++) {
            groupArray[i] = getGroupOfDate(dateList.get(i), today);
        }
        return groupArray;
    }

    public static int getGroupOfDate(Calendar date, Calendar today) {
        if (isToday(date, today))
            return DateGroup.GROUP_TODAY;
        if (date.after(today)) {
            if (isBeyondNextMonth(date, today))
                return DateGroup.GROUP_BEYOND_NEXT_MONTH;
            if (isTomorrow(date, today))
                return DateGroup.GROUP_TOMORROW;
            if (isSameWeek(date, today))
                return DateGroup.GROUP_THIS_WEEK_AFTER_TOMORROW;
            if (isNextWeek(date, today))
                return DateGroup.GROUP_NEXT_WEEK;
            if (isTwoWeeksAway(date, today))
                return DateGroup.GROUP_2_WEEKS_AWAY;
            if (isThreeWeeksAway(date, today))
                return DateGroup.GROUP_3_WEEKS_AWAY;
            if (isSameMonth(date, today))
                return DateGroup.GROUP_LATER_THIS_MONTH;
            if (isNextMonth(date, today))
                return DateGroup.GROUP_NEXT_MONTH;
        } else {
            if (isOlder(date, today))
                return DateGroup.GROUP_OLDER;
            if (isYesterday(date, today))
                return DateGroup.GROUP_YESTERDAY;
            if (isSameWeek(date, today))
                return DateGroup.GROUP_THIS_WEEK_BEFORE_YESTERDAY;
            if (isLastWeek(date, today))
                return DateGroup.GROUP_LAST_WEEK;
            if (isTwoWeeksAgo(date, today))
                return DateGroup.GROUP_2_WEEKS_AGO;
            if (isThreeWeeksAgo(date, today))
                return DateGroup.GROUP_3_WEEKS_AGO;
            if (isSameMonth(date, today))
                return DateGroup.GROUP_EARLIER_THIS_MONTH;
            if (isLastMonth(date, today))
                return DateGroup.GROUP_LAST_MONTH;
        }
        return DateGroup.GROUP_INVALID;
    }

    public static Calendar getToday() {
        return Calendar.getInstance();
    }

    private static Calendar getDate(Calendar date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date.getTime());
        return c;
    }

    private static Calendar getDate(long date) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(date);
        return c;
    }

    private static Calendar getYesterday(Calendar today) {
        Calendar date = getDate(today);
        date.add(Calendar.DATE, -1);
        return date;
    }

    private static Calendar getTommorow(Calendar today) {
        Calendar date = getDate(today);
        date.add(Calendar.DATE, 1);
        return date;
    }

    private static Calendar getNextNWeek(int weeksAway, Calendar today) {
        Calendar date = getDate(today);
        date.add(Calendar.WEEK_OF_YEAR, weeksAway);
        return date;
    }

    private static Calendar getNextNMonth(int monthsAway, Calendar today) {
        Calendar date = getDate(today);
        date.add(Calendar.MONTH, monthsAway);
        return date;
    }

    private static boolean isSameDay(Calendar date1, Calendar date2) {
        return date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR)
                && date1.get(Calendar.MONTH) == date2.get(Calendar.MONTH)
                && date1.get(Calendar.DATE) == date2.get(Calendar.DATE);
    }

    private static boolean isSameMonth(Calendar date1, Calendar date2) {
        return date1.get(Calendar.YEAR) == date2.get(Calendar.YEAR)
                && date1.get(Calendar.MONTH) == date2.get(Calendar.MONTH);
    }

    private static boolean isSameWeek(Calendar date1, Calendar date2) {
        return date1.get(Calendar.WEEK_OF_YEAR) == date2.get(Calendar.WEEK_OF_YEAR);
    }

    private static boolean isBeyondNextMonth(Calendar date, Calendar today) {
        Calendar nextMonth = getNextNMonth(1, today);
        int nextMonthYear = nextMonth.get(Calendar.YEAR);
        int dateYear = date.get(Calendar.YEAR);
        if (nextMonthYear == dateYear) {
            return date.get(Calendar.MONTH) > nextMonth.get(Calendar.MONTH);
        }
        return dateYear > nextMonthYear;
    }

    private static boolean isNextMonth(Calendar date, Calendar today) {
        return isSameMonth(getNextNMonth(1, today), date);
    }

    private static boolean isThreeWeeksAway(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(3, today));
    }

    private static boolean isTwoWeeksAway(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(2, today));
    }

    private static boolean isNextWeek(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(1, today));
    }

    private static boolean isTomorrow(Calendar date, Calendar today) {
        return isSameDay(getTommorow(today), date);
    }

    private static boolean isToday(Calendar date, Calendar today) {
        return isSameDay(today, date);
    }

    private static boolean isYesterday(Calendar date, Calendar today) {
        return isSameDay(getYesterday(today), date);
    }

    private static boolean isLastWeek(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(-1, today));
    }

    private static boolean isTwoWeeksAgo(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(-2, today));
    }

    private static boolean isThreeWeeksAgo(Calendar date, Calendar today) {
        return isSameWeek(date, getNextNWeek(-3, today));
    }

    private static boolean isLastMonth(Calendar date, Calendar today) {
        return isSameMonth(getNextNMonth(-1, today), date);
    }

    private static boolean isOlder(Calendar date, Calendar today) {
        Calendar nextMonth = getNextNMonth(-1, today);
        int nextMonthYear = nextMonth.get(Calendar.YEAR);
        int dateYear = date.get(Calendar.YEAR);
        if (nextMonthYear == dateYear) {
            return date.get(Calendar.MONTH) < nextMonth.get(Calendar.MONTH);
        }
        return dateYear < nextMonthYear;
    }

}


在日常的生活中我们最经常使用的距离毫无疑问应该是欧式距离,但是对于一些特殊情况,欧氏距离存在着其很明显的缺陷,比如说时间序列,举个比较简单的例子,序列A:1,1,1,10,2,3,序列B:1,1,1,2,10,3,如果用欧氏距离,也就是distance[i][j]=(b[j]-a[i])*(b[j]-a[i])来计算的话,总的距离和应该是128,应该说这个距离是非常大的,而实际上这个序列的图像是十分相似的,这种情况下就有人开始考虑寻找新的时间序列距离的计算方法,然后提出了DTW算法,这种方法在语音识别,机器学习方便有着很重要的作用。 这个算法是基于动态规划(DP)的思想,解决了发音长短不一的模板匹配问题,简单来说,就是通过构建一个邻接矩阵,寻找最短路径和。 还以上面的2个序列作为例子,A中的10和B中的2对应以及A中的2和B中的10对应的时候,distance[3]以及distance[4]肯定是非常大的,这就直接导致了最后距离和的膨胀,这种时候,我们需要来调整下时间序列,如果我们让A中的10和B中的10 对应 ,A中的1和B中的2对应,那么最后的距离和就将大大缩短,这种方式可以看做是一种时间扭曲,看到这里的时候,我相信应该会有人提出来,为什么不能使用A中的2与B中的2对应的问题,那样的话距离和肯定是0了啊,距离应该是最小的吧,但这种情况是不允许的,因为A中的10是发生在2的前面,而B中的2则发生在10的前面,如果对应方式交叉的话会导致时间上的混乱,不符合因果关系。 接下来,以output[6][6](所有的记录下标从1开始,开始的时候全部置0)记录A,B之间的DTW距离,简单的介绍一下具体的算法,这个算法其实就是一个简单的DP,状态转移公式是output[i] [j]=Min(Min(output[i-1][j],output[i][j-1]),output[i-1][j-1])+distance[i] [j];最后得到的output[5][5]就是我们所需要的DTW距离.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值