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
Related
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.
I have an Azure Mobile Service which returns date to an Android Client in this format
"Sat Sep 27 22:48:48 PDT 2014"
I want to calculate the difference between this returned date and today's date. After much iterations here is my current function.
public String calculateDayDifference(String DateFromAzure){
SimpleDateFormat AzureDateFormat = new SimpleDateFormat("EEE MMM dd H:m:s yyyy");
Calendar cal = Calendar.getInstance(Locale.getDefault());
String result;
try {
String currentDate = AzureDateFormat.format(System.currentTimeMillis() * 1000L);
Date presentDate = AzureDateFormat.parse(currentDate);
Date billDueDate = AzureDateFormat.parse(DateFromAzure);
long diff = billDueDate.getTime() - presentDate.getTime();
result = Long.toString(diff);
} catch (ParseException e) {
result = Long.toString(- 1);
//e.printStackTrace();
}
return result;
}
And here is how I call this function from my Adapter's getView() method
viewHolder.txtNumberDays.setText(mDateFunctions.calculateDayDifference(
viewHolder.billSummary.getBillDueDate().toString()))
And here is the Java class field that maps to the date column in the Mobile Service table.
#SerializedName("billDueDate")
private Date BillDueDate;
No matter how I tweak it, it give me negative result like so. How can I re-write the method above to return the difference between today's date and the date returned from Azure Mobile Service table?
Ok, from the AMS Android SDK source code I can see that the SDK handles formatting and parsing of dates automatically so what is returned is a valid java.util.date object.
https://github.com/Azure/azure-mobile-services/blob/master/sdk/android/src/sdk/src/com/microsoft/windowsazure/mobileservices/DateSerializer.java
With this realization I just called getTime() method on the returned date so I can compare it again current date which can be obtained from System.CurrentTimeMillis(). I then converted the result to int and that was with. Long learning experience. Its not the most efficient way to handle this but it works for. Here is the code
mBillDueDateService.mBillTable
.execute(new TableQueryCallback<Bill>() {
#Override
public void onCompleted(List<Bill> result, int count,
Exception exception, ServiceFilterResponse response) {
if (exception == null){
for (Bill bill : result){
long timeInLong = bill.getBillDueDate().getTime();
long currentTime = System.currentTimeMillis();
long diffTime = timeInLong - currentTime;
long diffDays = diffTime / (1000 * 60 * 60 * 24);
int daysdiff = (int) diffDays;
Log.i(TAG, "Bill Name " + bill.getBillName() + "" + "Due in " + daysdiff + "days");
bill.setDaysBeforeDueDate(daysdiff);
mUpcomingBillAdapter.add(bill);
}
I have a time interval - 12:00 PM to 11:59 PM.
When the user enters the time as "06:15 PM", check against that interval.
If the time falls into that interval, return true else return false.
I searched for thisin Google, but I didn't get the correct solution.
Can anyone help me to solve this issue?
String From = "12:00 PM";
String to = "11:59 PM";
String user_given_input = "06:15 PM";
You could parse it into a Date object using a SimpleDateFormatter.
After you've done that you can use fromDate.before(user_given_input_date) && toDate.after(user_given_input_date).
assuming fromDate, toDate & user_given_input_date are Date objects
Try this code, it should work.
static boolean checkTimeInterval(String s) {
String From = "12:00 PM";
String to = "11:59 PM";
SimpleDateFormat d = new SimpleDateFormat("hh:mm a");
boolean isLie = false;
try {
Date from = d.parse(From);
Date too = d.parse(to);
Date input = d.parse(s);
if (input.before(too) && input.after(from)) {
isLie = true;
}
} catch (ParseException e) {
System.out.println("Check input string format");
e.printStackTrace();
}
return isLie;
}
You may call this function as
checkTimeInterval("06:15 PM")
I have converted date format in milliseconds and time format in milliseconds. I am getting current time in more than 13 digits. CurrentTime= 1357755780000, StartingTime=1357602840, EndingTime=1357756140
But when I do comparison in below code, the if part is not executed, only the else part is executed.
Is there any mistake in my code? I want to make currentTime in 10 digits. So I think, conversion of date format to milliseconds is wrong.
String toParse = getDateorTime(1) + " " + getDateorTime(2);
long currentTime=0,startingTime=0,endingTime=0,milliseconds=0;
try
{
dateFormater = new SimpleDateFormat("yyyy/MMM/dd hh:mm");
Date date = null;
try {
date = dateFormater.parse(toParse);
date.setTime(milliseconds);
}catch (Exception e) {
System.out.println("\n Error in date parsing"+e.toString());
}
currentTime = (date.getTime());
start=Long.parseLong((cursor.getString(5).trim()));
end=Long.parseLong((cursor.getString(6).trim()));
}catch (ParseException pe) {
pe.printStackTrace();
}
if((currentTime>=startingTime)&&(currentTime<=endingTime))
{
//
}
Based on your examples, you actually have startingTime and endingTime in SECONDS, while you're comparing it to currentTime in MILLISECONDS. Simply multiply the second-times by 1,000, like so:
if((currentTime>=startingTime*1000L)&&(currentTime<=endingTime*1000L))
Simply divide by 1000
Calendar cal = Calendar.getInstance();
System.out.println(cal.getTimeInMillis()/1000);
Convert the long values to string and if length is >10 simply substring the value (0,10) and then you can use string .equals too or covert them back to long for comparison .
I have in my preferences some strings that represent a start time and and ending time.
I wrote this function to determine if the current time is within the start and ending time. The format of the date strings is "HH:mm". The function takes the strings that are from the preferences.
I'm sure I'm missing some code for the comparing because my parsing returns a something like this:
Thu Sep 29 12:24:33 EDT 2011
But all I need is to get this:
12:24
Here is the function. Can you help me correct the coding?
Thanks.
Truly,
Emad
public static boolean currentTimeIsWithinStartAndEnd(String startTime,
String endTime) {
String pattern = "HH:mm";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
boolean booleanValueToReturn = false;
try {
Date startTimeToCompare = sdf.parse(startTime);
Date endTimeToCompare = sdf.parse(endTime);
/*
* These are for the current time in date format.
*/
Date currentTime = new Date(System.currentTimeMillis());
Log.w("Emad", "Current Time: " + currentTime + " Start Time is: "
+ startTimeToCompare + " End Time is : "
+ endTimeToCompare);
/*
* Check if current time is equal or greater than the start time.
*/
if (currentTime.compareTo(startTimeToCompare) == 0
|| currentTime.compareTo(startTimeToCompare) == 1) {
booleanValueToReturn = true;
/*
* Now check if the current time is equal or less than the end
* time.
*/
if (currentTime.compareTo(endTimeToCompare) == 0
|| currentTime.compareTo(endTimeToCompare) == -1) {
booleanValueToReturn = true;
} else {
booleanValueToReturn = false;
}
} else {
booleanValueToReturn = false;
}
} catch (java.text.ParseException e) {
}
return booleanValueToReturn;
You are using SimpleDateFormat Incorrectly.
String pattern = "HH:mm" should be format in which your input Date String is. otherwise how is SimpleDateFormat going to know which portion represents what.
Create two SimpleDateFormat, f1 (with Input String Format) and f2 ( with output String Format) ;
Use f1.parse() to get Date object for Input String.
Then use f2.format() on this Date Object to get Output String representation.
Refer to SimpleDateFormat for details on how to specify date Format.
public static boolean currentTimeIsWithinStartAndEnd(String startTime,
String endTime) {
// assuming input date string is of format MM/dd/yyyy. Change it according to your needs.
String inputPattern = "MM/dd/yyyy";
String outputPattern = "HH:mm";
SimpleDateFormat inputFormatter = new SimpleDateFormat(inputPattern);
SimpleDateFormat outputFormatter = new SimpleDateFormat(outputPattern);
Date startTimeToCompare = inputFormatter.parse(startTime);
String dateInRequiredFormat = outputFormat.format(startTimeToCompare);