4

I have a date from server in the format yyyy-mm-dd HH:mm:ss .I have the current time in millis by System.currentTimeMillis(). I want to compare both dates and see if date received from server is future date and if it is so schedule an alarm for the future date. so my question how to compare this 2 different format dates and how to get remaining time (future- current) so as to schedule the alarm.

Edit: I already tried parsing the date in millis but it doesnt return value as same format as System.currentTimeMillis(). so it fails

JAAD
  • 12,349
  • 7
  • 36
  • 57
  • why was this marked as duplicate , that question doesn't address my concern of comparing two different date format – JAAD Mar 10 '16 at 21:13
  • downvoter care to explain? – JAAD Mar 10 '16 at 21:15
  • @tyczj how is this a duplicate? – JAAD Mar 10 '16 at 21:17
  • because you can easily find how to convert a string datetime to milliseconds by searching – tyczj Mar 10 '16 at 21:18
  • see my edit , i have a different issue – JAAD Mar 10 '16 at 21:19
  • that edit does not make sense, currentTimeMilliseconds gives milliseconds and the string parsing returns a date which you can get milliseconds from – tyczj Mar 10 '16 at 21:22
  • @tyczj the format returned by both in millis are different so comparison is not working – JAAD Mar 10 '16 at 21:23
  • well why would they be the same, one is the current time the other is some other datetime. I still dont understand the problem – tyczj Mar 10 '16 at 21:24
  • @tyczj i am converting the server date to millis and getting currenttimeinmillis from system method but the comparison is not proper , even if server date is after the current date it still return before – JAAD Mar 10 '16 at 21:25
  • 1
    is the server date time in UTC if its not you need to set the timezone of the server time before you parse it – tyczj Mar 10 '16 at 21:27
  • 1
    This has nothing to do with the discussion, but do you consider time zone in your code? E.g. in Tokio right now it's 11 march, 06:26 , while in Los Angeles it's 10 march, 13:26. If your code ignores timezone you can have mismatches – user2340612 Mar 10 '16 at 21:28
  • i tried setting UTC timezone to server date but output still the same – JAAD Mar 10 '16 at 21:29
  • @user2340612 server time is UTC+5:30 INDIAN STANDARD TIME – JAAD Mar 10 '16 at 21:30
  • @ankitagrawal ok so then that is what you have to set your timezone to in your code before you parse your date string – tyczj Mar 10 '16 at 21:31
  • @tyczj df.setTimeZone(TimeZone.getDefault()); like this – JAAD Mar 10 '16 at 21:33
  • Server time is UTF+5:30, but you can assume nothing for what concerns the device. This means that you should **also** retrieve the timezone from the device on which the app is running (this question [has already been answered](http://stackoverflow.com/questions/7672597/how-to-get-timezone-from-android-mobile)) – user2340612 Mar 10 '16 at 21:33
  • Lol I'm always late with comments! :) – user2340612 Mar 10 '16 at 21:34
  • @user2340612 i tried that also with no result , anyway i will post my code as soon as i am my machine and also try your suggestion maybe i am missing something silly – JAAD Mar 10 '16 at 21:36
  • Read this link how to set the timezone before you parse http://stackoverflow.com/questions/14314426/how-to-parse-date-from-gmt-timezone-to-ist-timezone-and-vice-versa-in-android – tyczj Mar 10 '16 at 21:38
  • If you compare the millis from current to the parse, there will always be differences because the parsed time has milliseconds as 000. You can divide both time in millis by 1000 and compare that. – Phyrum Tea Mar 10 '16 at 23:10
  • @tyczj solved issue was hh instead of HH – JAAD Mar 16 '16 at 06:35

2 Answers2

8

You can parse the yyyy-mm-dd HH:mm:ss date thanks to DateFormat class (e.g. the SimpleDateFormat class). This operation will return a Date object.

You can also create a Date object from current time in milliseconds.

When you have both objects you can compare them thanks to compareTo method.

For instance the following code:

try {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date parsed = sdf.parse("2016-03-10 22:05:20");

    Date now = new Date(System.currentTimeMillis()); // 2016-03-10 22:06:10

    System.out.println(parsed.compareTo(now));
} catch (Exception e) {
    e.printStackTrace();
}

will print -1, which means that parsed is before now.

EDIT:

Here it is the code of a simple but useless application that makes use of AlarmManager.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Log.d("TAG", "From intent: "+getIntent().getStringExtra("MyEXTRA"));
}

@Override
protected void onResume() {
    super.onResume();

    try {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long parsedMillis = sdf.parse("2016-03-10 22:54:30").getTime();
        long now = System.currentTimeMillis(); // 22:54:15

        if (parsedMillis > now) {
            Log.d("TAG", "In the future!");

            AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
            Intent intent = new Intent(this, MyActivity.class);
            intent.putExtra("MyEXTRA", "From alarm");
            PendingIntent broadcast = PendingIntent.getActivity(this, 0, intent, 0);
            am.setExact(AlarmManager.RTC_WAKEUP, parsedMillis, broadcast);

        } else {
            Log.d("TAG", "In the past...");
        }


    } catch (Exception e) {
        e.printStackTrace();
    }
}

In the LogCat you will see:

03-10 22:54:20.925    3946-3946/com.example.myapp D/TAG﹕ From intent: null
03-10 22:54:21.227    3946-3946/com.example.myapp D/TAG﹕ In the future!
03-10 22:54:30.513    3946-3946/com.example.myapp D/TAG﹕ From intent: From alarm
03-10 22:54:30.577    3946-3946/com.example.myapp D/TAG﹕ In the past...

The last line is printed because the alarm causes the activity to be relaunched, hence the onResume will be called another time and System.currentTimeMillis() will be greater than the hardcoded time. As you can see, however, the alarm is correctly fired at the scheduled time.

Moreover you should consider edge cases: if parsedMillis is greater than now by only a few milliseconds, you could set an alarm that will never be fired because it is set in the past. This happens because the OS needs some time to execute your code, so you should check that parsedMillis > now + DELTA, where DELTA is a reasonable amout of time that depends on the code you execute between System.currentTimeMillis() and am.setExact(...).

user2340612
  • 10,053
  • 4
  • 41
  • 66
  • what about getting the time difference in millis to schedule an alarm – JAAD Mar 10 '16 at 21:14
  • Well you can call `parsed.getTime()` to get the time in milliseconds. After that it's just a matter of math.. – user2340612 Mar 10 '16 at 21:19
  • i tried setExact but not working, can u post some code that works in alarmManager – JAAD Mar 10 '16 at 21:21
  • You should check if `parsed` is in the future or not (by comparing it to `System.currentTimeMillis()`). If it is in the future and you want to trigger the alarm at that time you should use `parsed.getTime()` as `triggerAtMillis` parameter of `alarmManager.setExact(...)` method. – user2340612 Mar 10 '16 at 21:31
  • 1
    i solved it , it was just a HH issue i was hh that it why time was wrong, since u helped you , i accepted the answer – JAAD Mar 16 '16 at 06:34
2

I recommend you do it using the modern date-time API*.

A simple way to do it using the modern API is to parse the server's date-time string into ZonedDateTime using the server's timezone and convert the resulting object into Instant which you can compare with Instant#now.

Demo:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // An arbitrary date for demo
        String strDateTime = "2021-05-09 10:20:30";

        // Replace JVM's default time zone, ZoneId.systemDefault() with applicable time
        // zone e.g. ZoneId.of("America/New_York")
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH)
                                    .withZone(ZoneId.systemDefault());

        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);

        Instant instantServer = zdt.toInstant();
        Instant now = Instant.now();

        if (instantServer.isBefore(now))
            System.out.println("The server time is before the current time.");
        else if (instantServer.isAfter(now))
            System.out.println("The server time is after the current time.");
        else
            System.out.println("The server time is the same as the current time.");
    }
}

Output when I run it now in my system:

The server time is before the current time.

Learn more about the the modern date-time API* from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110