1011011
1011011

Reputation: 61

Android/Java - Calculate date difference shows different results

public long getDays(){
    Date today = new Date ( );
    Calendar cal = Calendar.getInstance (TimeZone.getTimeZone("GMT"));
    // Set as today
    cal.setTime ( today );
    System.out.println ( "Today Cal: "+cal.get ( Calendar.YEAR ) + "Y / " + ( cal.get ( Calendar.MONTH ) + 1 ) + "M / " + cal.get ( Calendar.DATE ) + " D" );
    Calendar cal2 = Calendar.getInstance (TimeZone.getTimeZone("GMT") );
   //Month has offset -1. June = 5
    cal2.set ( 2011, 5, 15 );//YY MM DD
    System.out.println ( "Start Day Cal2: "+cal2.get ( Calendar.YEAR ) + "Y / " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "M / " + cal2.get ( Calendar.DATE ) + " D" );

    long count = 0;
    while ( !cal2.after ( cal ) ) {
        count++;
        //increment date
        cal2.add ( Calendar.DATE, 1 );
    }
    System.out.println ( "Ending Cal2: "+cal2.get ( Calendar.YEAR ) + "Y / " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "M / " + cal2.get ( Calendar.DATE ) + " D" );

    return count;
}

This is the code that I am using to calculate the difference in Days between today and 2011 June 15th.

This always works on Eclipse IDE, but when I implement this on Android, it shows 2 different results by random chance.

Screenshot

Most of the times it shows 2405, but sometimes it shows 2406 (Although the date should not have changed as it is 3 AM in the UK now.)

Console output

This is what is shown on System.out.println. It has the same start date and end date, but by a random chance, while loop counts 1 extra. How?

It only happens on Android. This is the code showing how the textview is being updated as a widget if it helps.

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {

    final int count = appWidgetIds.length;
    //Set Date Text
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.haruhi_widget);
    long days=getDays();
    remoteViews.setTextViewText(R.id.textView, days+context.getString(R.string.days));
    //Set ImageView
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.haruhi1,options);
    remoteViews.setImageViewBitmap(R.id.imageView,bitmap);

    Intent intent = new Intent(context, HaruhiWidgetProvider.class);
    intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    remoteViews.setOnClickPendingIntent(R.id.imageView, getPendingSelfIntent(context, KYON_KUN_DENWA));

    for (int i = 0; i < count; i++) {
      //  System.out.println(count+"appWidgetIds[i]");
        int widgetId = appWidgetIds[i];
        appWidgetManager.updateAppWidget(widgetId, remoteViews);
    }
}

Upvotes: 0

Views: 100

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 338316

tl;dr

ChronoUnit.DAYS.between( 
    LocalDate.of( 2011 , Month.JUNE , 15 ) , 
    LocalDate.now( ZoneId.of( "Africa/Tunis" ) )  
)

Problems

Certainly seems like a time zone issue. We cannot be certain as you have not provided us with enough information such as the time zone being used when your code was run.

More importantly, you are using troublesome old date-time classes that were outmoded years ago by the java.time classes.

And you are trying to work with date-only values using date-with-time-of-day classes.

Solution

calculate difference in Days between today and 2011 June 15th.

The LocalDate class represents a date-only value without time-of-day and without time zone.

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

Always specify your desired/expected time zone explicitly. Omitting the zone means the JVM’s current default time zone is implicitly applied. That default can vary by machine and can even vary during runtime(!). So your results may vary. Instead, always pass the optional ZoneId argument. Doing so has the side benefit of making your intentions clear with more self-documenting code.

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );

Get the date for 2011 June 15th.

LocalDate ld = LocalDate.of( 2011 , Month.JUNE , 15 ) ;

Calculate elapsed days.

long days = ChronoUnit.DAYS.between( ld , today ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

Upvotes: 1

Related Questions