Skip to content
This repository has been archived by the owner on Dec 12, 2020. It is now read-only.

Commit

Permalink
Merge pull request #382 from chuckbjones/289-fix-relative-dates
Browse files Browse the repository at this point in the history
Fix relative dates, closes #289
  • Loading branch information
ginatrapani committed Jul 1, 2013
2 parents bc8a834 + 9fdfc0c commit c643bf4
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 83 deletions.
130 changes: 47 additions & 83 deletions src/com/todotxt/todotxttouch/util/RelativeDate.java
Expand Up @@ -10,72 +10,24 @@
import java.util.Date;
import java.util.GregorianCalendar;

import android.annotation.SuppressLint;
import android.content.Context;

import com.todotxt.todotxttouch.R;
import com.todotxt.todotxttouch.TodoApplication;

@SuppressLint("SimpleDateFormat")
public class RelativeDate {

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
private static Context context = TodoApplication.getAppContetxt();


/**
* This method computes the relative date according to the Calendar being
* passed in and the number of years, months, days, etc. that differ. This
* will compute both past and future relative dates. E.g., "one day ago" and
* "one day from now".
* <p>
* <strong>NOTE:</strong> If the calendar date relative to "now" is older
* than one day, we display the actual date in its default format as
* specified by this class. The date format may be changed by calling
* {@link RelativeDate#setDateFormat(SimpleDateFormat)} If you don't want to
* show the actual date, but you want to show the relative date for days,
* months, and years, you can add the other cases in by copying the logic
* for hours, minutes, seconds.
*
* @param calendar
* @param years
* @param months
* @param days
* @param hours
* @param minutes
* @param seconds
* @return String representing the relative date
*/

private static String computeRelativeDate(Calendar calendar, int years,
int months, int days, int hours, int minutes, int seconds) {

String date = sdf.format(calendar.getTime());

if (years == 0 && months == 0) {
if (days < -1)
return context.getString(R.string.dates_days_ago, Math.abs(days));
else if (days == -1)
return context.getString(R.string.dates_one_day_ago);
else if (days == 0)
return context.getString(R.string.dates_today); } else if (years == 0 || years == -1) {
if (years == -1) {
months = 11 - months
+ Calendar.getInstance().get(Calendar.MONTH);
if (months == 1)
return context.getString(R.string.dates_one_month_ago);
else
return context.getString(R.string.dates_months_ago, months);
} else {
if (months != -1)
return context.getString(R.string.dates_months_ago,Math.abs(months));
else
return context.getString(R.string.dates_one_month_ago);
}
} else {
return date;
}
return date;

}
// Doesn't handle leap year, etc, but we don't need to be very
// accurate. This is just for human readable date displays.
private static final long SECOND = 1000; //milliseconds
private static final long HOUR = 3600 * SECOND;
private static final long DAY = 24 * HOUR;
private static final long YEAR = 365 * DAY;

/**
* This method returns a String representing the relative date by comparing
Expand All @@ -86,20 +38,48 @@ else if (days == 0)
*/

public static String getRelativeDate(Calendar calendar) {
Calendar today = new GregorianCalendar();
today.set(GregorianCalendar.HOUR_OF_DAY, 0);
today.set(GregorianCalendar.MINUTE, 0);
today.set(GregorianCalendar.SECOND, 0);
today.set(GregorianCalendar.MILLISECOND,0);

return getRelativeDate(today, calendar);
}

public static String getRelativeDate(Calendar d1, Calendar d2) {
long diff = d1.getTimeInMillis() - d2.getTimeInMillis();

Calendar now = GregorianCalendar.getInstance();
if (diff < 0 || diff >= YEAR) {
// future or far in past,
// just return yyyy-mm-dd
return sdf.format(d2.getTime());
}

if (diff >= 60 * DAY) {
// N months ago
long months = diff / (30 * DAY);
return context.getString(R.string.dates_months_ago, months);
}

if (diff >= 30 * DAY) {
// 1 month ago
return context.getString(R.string.dates_one_month_ago);
}

if (diff >= 2 * DAY) {
// more than 2 days ago
long days = diff / DAY;
return context.getString(R.string.dates_days_ago, days);
}

int years = calendar.get(Calendar.YEAR) - now.get(Calendar.YEAR);
int months = calendar.get(Calendar.MONTH) - now.get(Calendar.MONTH);
int days = calendar.get(Calendar.DAY_OF_MONTH)
- now.get(Calendar.DAY_OF_MONTH);
int hours = calendar.get(Calendar.HOUR_OF_DAY)
- now.get(Calendar.HOUR_OF_DAY);
int minutes = calendar.get(Calendar.MINUTE) - now.get(Calendar.MINUTE);
int seconds = calendar.get(Calendar.SECOND) - now.get(Calendar.SECOND);
if (diff >= 1 * DAY) {
// 1 day ago
return context.getString(R.string.dates_one_day_ago);
}

return computeRelativeDate(calendar, years, months, days, hours,
minutes, seconds);
// today
return context.getString(R.string.dates_today);

}

Expand All @@ -117,20 +97,4 @@ public static String getRelativeDate(Date date) {
return getRelativeDate(converted);
}

/**
* This method sets the date format. This is used when the relative date is
* beyond one day. E.g., if the relative date is > 1 day, we will display
* the date in the format: h:mm a MMM dd, yyyy
* <p>
* This can be changed by passing in a new simple date format and then
* calling {@link RelativeDate#getRelativeDate(Calendar)} or
* {@link RelativeDate#getRelativeDate(Date)}.
*
* @param dateFormat
*/

public static void setDateFormat(SimpleDateFormat dateFormat) {
sdf = dateFormat;
}

}
140 changes: 140 additions & 0 deletions tests/src/com/todotxt/todotxttouch/util/RelativeDateTest.java
@@ -0,0 +1,140 @@
/**
* This file is part of Todo.txt Touch, an Android app for managing your todo.txt file (http://todotxt.com).
*
* Copyright (c) 2009-2013 Todo.txt contributors (http://todotxt.com)
*
* LICENSE:
*
* Todo.txt Touch is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any
* later version.
*
* Todo.txt Touch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with Todo.txt Touch. If not, see
* <http://www.gnu.org/licenses/>.
*
* @author Todo.txt contributors <todotxt@yahoogroups.com>
* @license http://www.gnu.org/licenses/gpl.html
* @copyright 2009-2013 Todo.txt contributors (http://todotxt.com)
*/
package com.todotxt.todotxttouch.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import android.test.InstrumentationTestCase;

import com.todotxt.todotxttouch.R;

public class RelativeDateTest extends InstrumentationTestCase {

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

private String res(int resId) {
return getInstrumentation().getTargetContext().getString(resId);
}

private String res(int resId, int val) {
return getInstrumentation().getTargetContext().getString(resId, val);
}

private Calendar date(String str) {
try {
Date d = sdf.parse(str);
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(d);
return calendar;
} catch (ParseException e) {
e.printStackTrace();
fail();
return null;
}
}

public void testNow() {
Calendar today = new GregorianCalendar();
today.set(GregorianCalendar.HOUR_OF_DAY, 0);
today.set(GregorianCalendar.MINUTE, 0);
today.set(GregorianCalendar.SECOND, 0);
today.set(GregorianCalendar.MILLISECOND,0);
String actual = RelativeDate.getRelativeDate(today, today);
assertEquals(res(R.string.dates_today), actual);
}

public void test1DayFromNow() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2013-01-02");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals("2013-01-02", actual);
}

public void testToday() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2013-01-01");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_today), actual);
}

public void test1DayAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-12-31");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_one_day_ago), actual);
}

public void test2DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-12-30");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_days_ago, 2), actual);
}

public void test29DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-12-03");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_days_ago, 29), actual);
}

public void test30DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-12-02");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_one_month_ago), actual);
}

public void test59DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-11-03");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_one_month_ago), actual);
}

public void test60DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-11-02");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_months_ago, 2), actual);
}

public void test364DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-01-03");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals(res(R.string.dates_months_ago, 12), actual);
}

public void test365DaysAgo() {
Calendar d1 = date("2013-01-01");
Calendar d2 = date("2012-01-02");
String actual = RelativeDate.getRelativeDate(d1, d2);
assertEquals("2012-01-02", actual);
}

}

0 comments on commit c643bf4

Please sign in to comment.