Difference between 2 dates in days and in double - android

I am working on an app and i need to get the difference between the actual date and a date inserted by the user, in days and in double.
Any idea on how to make this? I've tried some things but without success.

First you must decide if you want to consider the time of the day and the timezone to calculate the difference, because this can lead to different results.
Example: current date (AKA "today") is April 17th or 18th, depending on where in the world you are. Actually, depending on the time of the day, there might be 3 different "todays" in the world, at the same time. What timezone are you using to calculate the difference?
the user will enter a date: only day, month and year? Will it enter the hours? Are you using the user's device's timezone or some specific zone?
the same questions apply to the current date
Depending on the choices you make, you might get a different result.
Anyway, I'd use this lib: http://www.threeten.org/threetenbp/
or java.time classes, if available in your API level. In both API's you can use the following.
To use a date (day-month-year only) and the device's default timezone, I'd choose the LocalDate class:
// current date in device's default timezone
LocalDate now = LocalDate.now();
// some date from input values (May 10th 2018)
LocalDate dt = LocalDate.of(2018, 5, 10);
// difference in days
long diff = ChronoUnit.DAYS.between(now, dt); // 23
If you want to consider the time of the day (hours, minutes, etc), use a LocalDateTime. But in this case, ChronoUnit.DAYS considers a day has passed when the time is >= the other (ex: the difference between April 17th at 10 AM and April 18th 9:59 AM is zero days, because the time of the day didn't reach 10 AM, so it didn't complete 1 day - with LocalDate this doesn't happen because this class doesn't have time-of-the-day fields and considers only the day, month and year).
If you want to consider everything (date, time, and timezone), including Daylight Saving Time transitions, use a ZonedDateTime instead (the code is very similar, the only difference is that you can choose a timezone to work with):
// current date/time in device's default timezone
ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());
// some date from input values (May 10th 2018, 10 AM in New York timezone)
ZonedDateTime dt = ZonedDateTime.of(2018, 5, 10, 10, 0, 0, 0, ZoneId.of("America/New_York"));
// difference in days
long diff = ChronoUnit.DAYS.between(now, dt); // 23
You can choose between the device's default timezone (ZoneId.systemDefault()) or a specific one (ZoneId.of("America/New_York")). You can check all the available timezones with ZoneId.getAvailableZoneIds().
Maybe it doesn't make sense to use current date in one timezone and user's date in another (I'd use the same for both), but that's up to you to decide.

Calendar c = Calendar.getInstance();
Calendar c2 // = what you will get from the user
long diff = c.getTimeInMillis()-c2.
double days = (double) diff/(1000*60*60*24);
that is what i have in mind.
I hope this helps

use this way
public static double getTimeDiffBetweenDate(Date startDateTime, Date finishDateTime) {
long diffInMilliseconds = finishDateTime.getTime() - startDateTime.getTime();
return TimeUnit.MILLISECONDS.toMinutes(diffInMilliseconds) / 60.0;
}

Related

SimpleDateFormat.parse() ignoring timezone?

I am trying to parse date string with timezone using this code for tests:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZZZZZ", Locale.US);
Calendar calendar = Calendar.getInstance();
calendar.setTime(sdf.parse("2017-07-26T06:00-06:00"));
int offset = calendar.getTimeZone().getRawOffset();
I am trying to change timezone from -06 to +09, but offset always contains 10800000.
How to parse date with timezone correctly (I need time and timezone both)?
Note: -06:00 is an offset, not a timezone - those 2 concepts are related, but they are different things (more on that below).
The problem with SimpleDateFormat and Calendar is that they use the system's default timezone, so even though you parse a date with a different offset (like -06:00), the resulting Calendar will have the default timezone (you can check what zone is by calling TimeZone.getDefault()).
That's just one of the many problems and design issues of this old API.
Fortunately, there's a better alternative, if you don't mind adding a dependency to your project (in this case, I think it's totally worth it). In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP to make it work (more on how to use it here).
To work with offsets, you can use the org.threeten.bp.OffsetDateTime class:
// parse the String
OffsetDateTime odt = OffsetDateTime.parse("2017-07-26T06:00-06:00");
This will parse all the fields correctly (date/time and offset). To get the offset value, similar to calendar.getTimeZone().getRawOffset(), you can do:
// get offset in milliseconds
int totalSeconds = odt.getOffset().getTotalSeconds() * 1000;
I had to multiply by 1000 because calendar returns the value in milliseconds, but ZoneOffset returns in seconds.
To convert this to another offset (+09:00), it's straightforward:
// convert to +09:00 offset
OffsetDateTime other = odt.withOffsetSameInstant(ZoneOffset.ofHours(9));
As I said, timezone and offset are different things:
offset is the difference from UTC: -06:00 means "6 hours behind UTC" and +09:00 means "9 hours ahead UTC"
timezone is a set of all the different offsets that a region had, has and will have during its history (and also when those changes occur). The most common cases are Daylight Saving Time shifts, when clocks change 1 hour back or forward in a certain region. All these rules about when to change (and what's the offset before and after the change) are encapsulated by the timezone concept.
So, the code above works fine if you're working with offsets and wants to convert to a different one. But if you want to work with a timezone, you must convert the OffsetDateTime to a ZonedDateTime:
// convert to a timezone
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Asia/Tokyo"));
// get the offset
totalSeconds = zdt.getOffset().getTotalSeconds() * 1000;
The getOffset() method above will check the history of the specified timezone and get the offset that was active in that corresponding instant (so, if you take a date during DST, for example, the offset (and also date and time) will be adjusted accordingly).
The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.

Android Joda DateTime one hour off

I have a TimePickerDialog which lets the user pick a time. The TimePickerDialog has a onTimeSet method that gets called when the user finished picking the time.
I pass the arguments to a second method, setTime(int hour, int minute) which saves the values and displays a formatted time.
Here is a code snippet of the method:
java.text.DateFormat dateFormatter =
java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT, Locale.getDefault());
DateTime dt = new DateTime();
dt = dt.hourOfDay().setCopy(hour);
dt = dt.minuteOfHour().setCopy(minute);
String text = dateFormatter.format(dt.toDate());
The Problem is that (sometimes, not always) the hour value is off by one or maybe even two hours. I think the cause of the problem has something to do with timezones, but I do not know what the exact cause is. I also think that the problem is caused by the Joda DateTime object, since I did not have any issues before I implemented Joda time AND because it also gets saved with one hour off.
Any ideas what happens / how to fix it?
For this answer, I'm using joda-time 2.7 (although it might work with previous versions).
I'm also assuming that your program only cares about hour and minute (I'm not an Android expert, but I saw docs from TimePickerDialog and it seems to be the case).
So, if you're manipulating only hour and minute, you don't need to use DateTime class (actually you shouldn't in this case).
That's because a DateTime object is "aware" of all date fields, including day, month, year and timezone. So, when you create a new DateTime(), it creates a new object with current date and time in your default timezone. And if the current date in default timezone is in summer time (aka daylight saving time), you can have these hour shifts.
(And I believe that Android takes the default timezone from the device's system, so it can vary according to the device running the code - at least that's how it works in computers, so it shouldn't be different for devices).
As you don't need to know day/month/year and timezone, you can use LocalTime class (org.joda.time.LocalTime) which is a class with only hour and minute fields (and seconds, if you want; if you don't care about seconds, they'll be set to zero). And the best part is: this class doesn't care about timezones, so 10:00 AM will always be 10:00 AM.
You also don't need to use java.text.DateFormat, as joda-time has its own formatters. So the code will be like this:
public void setTime(int hour, int minute) {
// shortTime() is equivalent to DateFormat.SHORT
DateTimeFormatter fmt = DateTimeFormat.shortTime().withLocale(Locale.getDefault());
LocalTime time = new LocalTime(hour, minute);
String text = fmt.print(time);
System.out.println(text);
}
Doing some tests (assuming default locale is en_US):
setTime(9, 30); // prints 9:30 AM
setTime(10, 0); // prints 10:00 AM
PS: the output may vary according to your default Locale (which I also believe it comes from the device's system). If you want a fixed format (independent from locales), you can use DateTimeFormat.forPattern("h:mm a"), which also results in the output above (and when you use formatters this way, the default locale doesn't change the output).

Custom the display value of SimpleDateFormat in android

I currently work on a double value that represent the total consumed time
for example, I have a 260 that means 260 second is consumed
To display to user, I would like to format it
for example , it should be something like 0year,0month,0day,1hr,2min,30sec
But I found the SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); is not quite suit my case (seems the "h" in "hr" is conflicted with the hour symbol?)
So , how to change the HH:mm:ss to the case mentioned above?
Thanks for helping
DateFormat is useful to format dates, not an absolute value of time.
To achieve your goal, you can take a look to Formatter
Hope this sample helps you:
String total_consumed_time = String.format("%01d year, %01d month, %01d day, %01d hr, %01d min, %01d sec", time_year, time_month, time_day, time_hour, time_min, time_seg);
I didn't try that code, but I use similar workaround with an absolute time in milliseconds:
long time = 260000; // time in mseg
long time_hour = TimeUnit.MILLISECONDS.toHours(time);
time -= TimeUnit.HOURS.toMillis(time_hour);
long time_min = TimeUnit.MILLISECONDS.toMinutes(time);
time -= TimeUnit.MINUTES.toMillis(time_min);
long time_seg = TimeUnit.MILLISECONDS.toSeconds(time);
String total_time = String.format("%02d:%02d:%02d", time_hour, time_min, time_seg);
With a result of "00:04:20" (4 minutes and 20 seconds).
Accepted answer is in most cases okay for solving your problem, but gives wrong reason why not to use the class SimpleDateFormat. This format class is well suited for objects of type java.util.Date (which are kind of unix timestamps in milliseconds hence absolute value of time, NOT dates). In order to treat letters like "hr" as literals you need to escape them. Example code:
// create timestamp
java.util.Date jud = new java.util.Date(260 * 1000); // milliseconds
// create format for timestamp
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy'year',M'month',d'day',H'hr',m'min',s'sec'");
// otherwise you will get extra offset time (example: in England +1 hour DST)
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
// output: 1970year,1month,1day,0hr,4min,20sec
String formatted = sdf.format(jud);
System.out.println(formatted);
Even with the applied and tricky time zone correction in code you face the problem that you have an output for the year 1970, a point in time. Hereby you can see that SimpleDateFormat does format timestamps well (absolute values in time) but NOT durations (amount resp. length of time). This semantic problem can also not be solved by the approach to use java.util.Formatter as soon as the input increases the day limit of 86400 seconds.
Old JDK and Android don't offer a built-in solution for evaluating time differences expressed in years, months and days. Java 8 does offer (limited) support with new API (class 'Period' only for date part, not time part). External libraries like JodaTime or my own one (actually only as alpha-version) give more support. JodaTime even offers a special PeriodFormatter which is ideal for solving your problem.

Calculate Remaning Date Without Joda Time

I've spent an hour going through stackoverflow trying to find a proper way of calculating the remaining Days, hours, minutes and seconds remaining without using JODA-Time. I wish to keep things simple as possible.
I am seeking to do the following (Please provide declarations of instances, I am not sure as to whether to us Longs, Time or Calendar objects etc):
difference = endingDate-currentTime
Then set a textView to the time remaining with DD:HH:MM:SS format
In other words, what is the best method to use? (Timezone is not important) How can I set the ending date to for example December 31, 2013 and what type is my ending date? Is it a time, date or calendar object? I want to then subtract my current date from my ending date to display the remaining days left until December 31, 2013. In the format of DD:HH:MM:SS
Thank you! The help is much appreciated.
I'll leave you to work out how to divide the difference variable to get days, hours, etc. But this is how I'd do the rest of it.
Calendar endCalendar = new Calendar();
// Set end to 31th Dec 2013 10:15:30 am local time
endCalendar.set(2013, 11, 31, 10, 15, 30);
long localEndTimeInMillis = endCalendar.getTimeInMillis();
long localCurrentTimeInMillis = Calendar.getInstance().getTimeInMillis();
// Convert to UTC.
// Easy way to compensate if the current and end times are in different DST times
utcEndTimeInMillis = getUTCTimeInMillis(localEndTimeInMillis);
utcCurrentTimeInMillis = getUTCTimeInMillis(localCurrentTimeInMillis);
long difference = utcEndTimeInMillis - utcCurrentTimeInMillis;
The method to convert to UTC...
public long getUTCTimeInMillis(long localTimeInMillis) {
return localTimeInMillis - TimeZone.getDefault().getRawOffset() - (TimeZone.getDefault().inDaylightTime(new Date(localTimeInMillis)) ? TimeZone.getDefault().getDSTSavings() : 0);
}

Android inconsistency when dates are stored as longs and the time zone is changed

I have an Android app that is used by people in the UK and Ireland only, and there are no plans for this app to be used overseas.
In the app I store dates for various things, although I never need the full timestamp including the time of day, I only need the date.
So that I can compare dates easily, I've been creating calendar objects and clearing the values of the time, and using the milliseconds of that to store in the database.
public Calendar clearCalTime(long l) {
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setTimeInMillis(l);
cal.clear(Calendar.HOUR);
cal.clear(Calendar.HOUR_OF_DAY);
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);
return cal;
}
The issue has been that if users change the timezone, for some reason the dates start messing up, e.g by saving things to the wrong day. The timezones could be anything, I have no control over what the users set.
I've tried setting the timezone to UTC but this doesn't work either. Is there any way to just disregard the timezones?
Nope. You are going to have to set TimeZone going in and out of your storage.
You'll need to do this:
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
in your code to make it consistent.
See this SO: Java.util.Calendar - milliseconds since Jan 1, 1970
Alternatively use Joda Time when dealing with complicated Date/Time math.

Categories

Resources