Calculate daysAgo return wrong days - android

I'm trying to calculate daysAgo from two dates, the phone date time and my passed date.
this is my code:
int daysAgo = DateUtilities.getTimeAgo(DateUtilities.stringToDateTime(updatedAt, true).getTime());
public static int getTimeAgo(long time) {
if (time < 1000000000000L) {
time *= 1000;
}
long now = System.currentTimeMillis();
if (time > now || time <= 0) {
return 0;
}
final long diff = now - time;
return (int) (diff / DAY_MILLIS);
}
public static Date stringToDateTime(String dateTime, boolean useUtc) throws ParseException {
if (useUtc) {
return new SimpleDateFormat("yyyy-mm-dd'T'HH:mm:ss").parse(dateTime);
} else {
return new SimpleDateFormat("yyyy-mm-dd").parse(dateTime);
}
}
this code as int daysAgo return wrong days for me, i pass this date to calculate: 2017-11-18T20:31:04.000Z and my phone date time as System.currentTimeMillis() is 1511080129979 and then result of returned daysAgo is 305

You must use "MM" to represent the month, not the "mm". It is for minutes. Your code
return new SimpleDateFormat("yyyy-mm-dd'T'HH:mm:ss").parse(dateTime);
return new SimpleDateFormat("yyyy-mm-dd").parse(dateTime);
should be changed to
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(dateTime);
return new SimpleDateFormat("yyyy-MM-dd").parse(dateTime);

The problem over here is pre-optimization.
int daysAgo = DateUtilities.getTimeAgo(DateUtilities.stringToDateTime(updatedAt, true).getTime());
return new SimpleDateFormat("yyyy-mm-dd'T'HH:mm:ss").parse(dateTime);
The above statements are perfect only when you know what they are doing, otherwise, they are impossible to even debug.
These are the situations where we understand the real importance of TDD.
The TDD approach
DateUtilitiesUnitTest
public class DateUtilitiesUnitTest
{
#Test
public void testStringToDateTimeConversion()
{
Calendar expectedCal = Calendar.getInstance();
// Here we set the month as Calendar.NOVEMBER
// As per the Calendar API, month 11 == DECEMBER
expectedCal.set(2017, Calendar.NOVEMBER, 18, 20, 31, 4);
Date actualDate = DateUtilities.stringToDateTime("2017-11-18T20:31:04.000Z");
Calendar actualCal = Calendar.getInstance();
actualCal.setTime(actualDate);
// Date.equals(Date), compares two Dates with the milliseconds precision, and cannot be used reliably
// hence, we have to compare all the individual elements separately
assertEquals("Year should be 2017", expectedCal.get(Calendar.YEAR), actualCal.get(Calendar.YEAR));
assertEquals("Month should be " + expectedCal.get(Calendar.MONTH), expectedCal.get(Calendar.MONTH), actualCal.get(Calendar.MONTH));
assertEquals("Day should be 18", expectedCal.get(Calendar.DAY_OF_MONTH), actualCal.get(Calendar.DAY_OF_MONTH));
// If required, you may go ahead and compare Hours, Minutes and Seconds
}
}
=== Step 1 (Fail the Test) ===
DateUtilities.java
public static Date stringToDateTime(String dateTime)
{
return null;
}
Test Result
java.lang.NullPointerException
=== Step 2 (Just enough to Pass the test) ===
DateUtilities.java
public static Date stringToDateTime(String dateTime)
{
Calendar cal = Calendar.getInstance();
// Here we set the month as Calendar.NOVEMBER
// As per the Calendar API, month 11 == DECEMBER
cal.set(2017, Calendar.NOVEMBER, 18, 20, 31, 4);
return cal.getTime();
}
Test Result
1 Test passed
Failing and then Passing the "pseudo tests" proves that your Test is actually working and that you are in fact testing the correct method.
=== Step 3 (Start Implementation) ===
DateUtilities.java
public static Date stringToDateTime(String dateTime)
{
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd'T'HH:mm:ss");
Date date = null;
try {
date = format.parse(dateTime);
}
catch (ParseException e) {
e.printStackTrace();
}
return date;
}
Test Result
java.lang.AssertionError: Month should be 10
Expected :10
Actual :0
We caught the issue!
Expected month is 10 (Calendar.NOVEMBER)
but, we got 0 (Calendar.JANUARY)
=== Step 4 (Fix it!) ===
DateUtilities.java
public static Date stringToDateTime(String dateTime)
{
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date date = null;
try {
date = format.parse(dateTime);
}
catch (ParseException e) {
e.printStackTrace();
}
return date;
}
Test Result
1 Test passed

Just change the date format to
public static Date stringToDateTime(String dateTime, boolean useUtc) throws ParseException {
if (useUtc) {
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(dateTime);
} else {
return new SimpleDateFormat("yyyy-MM-dd").parse(dateTime);
}
}
In date mm denotes to minutes where MM denotes to months.

Related

Determining the latest of two dates, using Calender

I have two instances of Calender, expiryDate and nowDate. The date of expiryDate is set to 16 august 2020, nowDate gets the current date.
Calendar expiryDate = Calendar.getInstance();
Calendar nowDate = Calendar.getInstance();
expiryDate.set(Calendar.DAY_OF_MONTH, 16);
expiryDate.set(Calendar.MONTH, Calendar.AUGUST);
expiryDate.set(Calendar.YEAR, 2020);
What code can determine which instance has the latest date?
First Convert your Calendar to date Object.
Date date1 = calendar.getTime();
then use date compareTo method.
Date class has its own methods for date comparison: compareTo
if (date1.compareTo(date2) > 0) {
Log.i("app", "Date1 is after Date2");
}
Best and easiest, get epoch millis from both and compare the long millis
Calendar expiryDate = Calendar.getInstance();
Calendar nowDate = Calendar.getInstance();
expiryDate.set(Calendar.DAY_OF_MONTH, 16);
expiryDate.set(Calendar.MONTH, Calendar.AUGUST);
expiryDate.set(Calendar.YEAR, 2020);
long nowMillis = nowDate.getTimeInMillis();
long expiryDateMillis = expiryDate.getTimeInMillis();
if(nowMillis>expiryDateMillis){
//now date is after expiry
}else{
//now date is before expiry
}
Simplest way is use milliseconds Kotlin:
if (expiryDate.timeInMillis< nowDate.timeInMillis) {
// Expired
} else {
// Not expired
}
Java
if (expiryDate.getTimeInMillis() < nowDate.getTimeInMillis()) {
// Expired
} else {
// Not expired
}
The implementation of the Calendar.compareTo() function is equivalent to the getTimeInMillis solutions - so why not just use the Calendar's code:
So OP would be:
if (nowDate.compareTo(expiryDate) > 0) {
// expired
} else {
// not expired
}
Note - this does not solve the "same-day" case.
For reference here's the Calendar's implementation of the compareTo:
public int compareTo(Calendar anotherCalendar) {
if (anotherCalendar == null) {
throw new NullPointerException();
}
long timeInMillis = getTimeInMillis();
long anotherTimeInMillis = anotherCalendar.getTimeInMillis();
if (timeInMillis > anotherTimeInMillis) {
return 1;
}
if (timeInMillis == anotherTimeInMillis) {
return 0;
}
return -1;
}

Why my unit test fails altough method works good?

I try to count time interval. I parse String date into Date object for some pattern.
public static float countTimeAgo(String timestamp){
// date pattern
SimpleDateFormat simpleDateFormat
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
simpleDateFormat.setLenient(false);
// time interval
float diff;
try {
// convert timestamp to given pattern
Date timestampDate = simpleDateFormat.parse(timestamp);
// get actual date and convert to pattern
Date date = new Date();
simpleDateFormat.format(date);
// count difference in millis
diff = date.getTime() - timestampDate.getTime();
// convert millis to minutes
diff = diff/(1000*60);
} catch (ParseException e) {
return -1;
}
if (diff < 0)
return -1;
else
return diff;
}
When I put string "2018-03-08 23:28:07.807353" as argument while running my app, method is returning non -1 value. But when I run a test, it fails:
#Test
public void testCountTimeAgo(){
String date = "2018-03-08 23:28:07.807353";
assertTrue(PostTimeProvider.countTimeAgo(date) != -1);
}
AssertionError:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
Does somebody knows why?
In your code -1 can be returned when the parsing fails or if the date was in future. You should check which one is happening in this case. Perhaps your device and the device running the unit tests have different time?

Time remaining calculation android always an hour wrong

Im trying to calculate the difference between a time returned to me by an API and the current device time.
The API returns time in this format: "game_start": "2015-09-03 19:00:00"
To calculate the difference I do this:
protected String getTimeToStart(JSONObject jsonObject) {
String time = "";
Calendar startTime;
Calendar current;
startTime = Calendar.getInstance();
current = Calendar.getInstance();
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat format2 = new SimpleDateFormat("HH mm ");
startTime.setTime(format.parse(jsonObject.getJSONObject("data").getJSONObject("game").getString("game_start")));
String[] splited = (format2.format(startTime.getTimeInMillis() - current.getTimeInMillis()).split("\\s+"));
time = splited[0] + "hrs " + splited[1] + "mins";
} catch (ParseException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
if (checkStarted(startTime, current)) {
return time;
} else {
return "League Started";
}
protected boolean checkStarted(Calendar start, Calendar current) {
if (current.before(start)) {
return true;
} else {
return false;
}
}
The problem I have is that the calculation always returns the time remaining as an hour more that it should be, until it gets to the time that it is actually meant to start then it returns that there is no time remaining e.g.
current time = 16:59
time it starts at = 17:00
time remaining that is returned 1hrs 1mins
then
current time = 17:00
time it starts at = 17:00
time remaining that is returned League Started
When parsing date from text you have to take into account the locale and the timezone. See my answer here: Date not printing correct Time Android

Comparing date values

I am using two functions to compare date values where I will be checking to see if start date is greater than/comes after the end date.
The 1st function is used to take in string value and use that string value to initialize the Calendar:
private int getFromCalendar(String strDate,int field)
{
int result = -1;
try
{
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");// this is your date format "12/24/2013" = "MM/dd/yyy"
java.util.Date date = formatter.parse(strDate);//convert to date
Calendar cal = Calendar.getInstance();// get calendar instance
cal.setTime(date);//set the calendar date to your date
result = cal.get(field); // get the required field
return result;//return the result.
}
catch (ParseException e)
{
e.printStackTrace();
}
return result;
}
The 2nd function is used to compare the startDate and endDate (they are both buttons):
public void compareDates(String startDate, String endDate){
Calendar startCheckDate = Calendar.getInstance();
int startmm = getFromCalendar(monitoringDate.getText().toString(), Calendar.MONTH);
int startyy = getFromCalendar(monitoringDate.getText().toString(), Calendar.YEAR);
int startdd = getFromCalendar(monitoringDate.getText().toString(), Calendar.DAY_OF_MONTH);
startCheckDate.set(startyy, startmm, startdd);
Calendar endCheckDate = Calendar.getInstance();
int endmm = getFromCalendar(monitoringEndDate.getText().toString(), Calendar.MONTH);
int endyy = getFromCalendar(monitoringEndDate.getText().toString(), Calendar.YEAR);
int enddd = getFromCalendar(monitoringEndDate.getText().toString(), Calendar.DAY_OF_MONTH);
endCheckDate.set(endyy, endmm, enddd);
if(endCheckDate.after(startCheckDate)){
Toast.makeText(getSherlockActivity(), "End date cannot be smaller than start date", Toast.LENGTH_SHORT).show();
}
}
For some reason the compareDates function does not work at all. Help please
You can easily compare date by changing it to milliseconds since 1900
Date date = new Date();
long dateLong = date.getTime();
Now its easy to compare with any other date
So for your case after doing this get back in date DataType
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");// this is your date format "12/24/2013" = "MM/dd/yyy"
java.util.Date date = formatter.parse(strDate);
do something like
long date1long = date1.getTime();
long date2long = date2.getTime();
if(date2long > date1long)
{
// Do whatever you want
}
This is the easiest way to compare two dates
You are way to verbose. Since you only wanted to know if a given date is after another, or not. Here you go:
public class DateTest {
private static SimpleDateFormat formatter = new SimpleDateFormat(
"MM/dd/yyyy");
public static void main(String[] args) throws ParseException {
Calendar start = createFromString("01/30/2013");
Calendar end = createFromString("06/30/2013");
System.out.println("START: " + start.getTime());
System.out.println("END : " + end.getTime());
System.out.println("IS B4: " + isBefore(start, end));
}
public static Calendar createFromString(String date) throws ParseException {
Calendar c = Calendar.getInstance();
c.setTime(formatter.parse(date));
return c;
}
public static boolean isBefore(Calendar start, Calendar end) {
return start.before(end);
}
}
OUTPUT
START: Wed Jan 30 00:00:00 CET 2013
END : Sun Jun 30 00:00:00 CEST 2013
IS B4 : true
I usesd getTime() in the println() method since, the toString() method (that gets implicitly called) on java.util.Date is more human readable than the one in Calendar.
There is also an after() in Calendar and a compareTo().
in the compareDates() use
if(endCheckDate.compareTo(startCheckDate)<0)
instead of
if(endCheckDate.after(startCheckDate))
for more reference go here

Wrong "week of year" in Android

The number of "week of year" returned from a Date is wrong.
This is my code:
Calendar c = Calendar.getInstance();
c.setTime(my_date);
int num_week = c.get(Calendar.WEEK_OF_YEAR);
If my_date (type Date) is 01/01/2011, I supposed that "week of year" is 1. But it returned 52.
I try to test with these methods but I don't obtain anything:
c.setFirstDayOfWeek(6);
c.setMinimalDaysInFirstWeek(1)
If It's interesting, I'm from Spain, and our week begin on Monday.
Have I to do anything for obtain right results?
Thanks!
This may be Android/Harmony-specific. For example, this works for me with desktop Java:
import java.util.*;
public class Test {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(2011, 0, 1, 0, 0, 0);
System.out.println(calendar.get(Calendar.WEEK_OF_YEAR)); // Prints 52
calendar.setMinimalDaysInFirstWeek(1);
System.out.println(calendar.get(Calendar.WEEK_OF_YEAR)); // Prints 1
}
}
Can you confirm that the exact same code (modulo logging options) logs 52 twice on Android?
Here you can view the reference by oracle
https://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html
And I have placed a quick solution to find the week count of current day. You can alter and optimize as your way. Also set according to your convenient GMT value
public static int getWeeksOfMonth() {
DATESTATUS = false;
VALUESTATUS = false;
int weekCount;
WEEK_OF_MONTH= -1;
// get the supported ids for GMT+04:00 (Pacific Standard Time)
String[] ids = getAvailableIDs(4 * 60 * 60 * 1000);
// if no ids were returned, something is wrong. get out.
if (ids.length == 0)
return WEEK_OF_MONTH;
// create a Pacific Standard Time time zone
SimpleTimeZone pdt = new SimpleTimeZone(4 * 60 * 60 * 1000, ids[0]);
// create a GregorianCalendar with the Pacific Daylight time zone
// and the current date and time
Calendar calendar = new GregorianCalendar(pdt);
Date trialTime = new Date();
calendar.setTime(trialTime);
weekCount = calendar.get(Calendar.WEEK_OF_YEAR);
return recursiveWeekCountCheck(calendar, weekCount);
}
private static int recursiveWeekCountCheck(Calendar calendar, int weekCount) {
if (calendar.get(Calendar.MONTH) == Calendar.DECEMBER && weekCount == 1) {
DATESTATUS = true;
calendar.add(Calendar.DAY_OF_MONTH, -1);
weekCount = calendar.get(Calendar.WEEK_OF_YEAR);
recursiveWeekCountCheck(calendar, weekCount);
}
if (!VALUESTATUS){
VALUESTATUS = true;
if (DATESTATUS) {
weekCount++;
WEEK_OF_MONTH = weekCount;
} else {
WEEK_OF_MONTH = weekCount;
}
}
return WEEK_OF_MONTH;
}
At the end just call the method getWeeksOfMonth();

Categories

Resources