I have a bunch of data containing a time value, e.g. 09:30am, and a duration, either 15,30,45 or 60. What would be the best way of getting the end time from these values? Will it be some use of a Date / Calendar or would just a custom function be quicker to do?
The Joda Time library (http://www.joda.org/joda-time/) is popular, easy to work with, and handles these kinds of calculations in a straight-forward manner.
DateTime start = new DateTime(2013, 10, 15, 9, 30); // create a DateTime representing Oct 15, 2013 at 9:30
Duration dur = Duration.standardMinutes(15); // create a duration of 15 minutes
DateTime calc = start.plus(dur); // add; result is 9:45 on 10/15/2013
The standard java/android way for this is to use a calendar:
final Calendar c = Calendar.getInstance(); // now
c.add(Calendar.DAY_OF_MONTH, 10); // add 10 days
There are other constants if you want to add minutues, years, seconds, ....
Check out this solution: Java string to date conversion
You may need to change the "MMMM d, yyyy" portion to fit your data set.
Here is the Javadoc: http://developer.android.com/reference/java/text/SimpleDateFormat.html
edit: For the second part of your question, there are several questions on here about how to add to a Date/Calendar object.
Related
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;
}
I have a small application which simply sets the time and date of a Calendar and then retrieves it.
Currently when using my application on devices up to API24 its retrieves the correct date which was originally set. But if you run the application on a device higher than API 24 then the date returned is one day later than the desired result.
My code as below
Setting the date of the calendar....
myCalendar.set(Calendar.YEAR, 2018 );
myCalendar.set(Calendar.DAY_OF_MONTH, 3);
myCalendar.set(Calendar.MONTH, 0);
myCalendar.set(Calendar.HOUR, 18);
myCalendar.set(Calendar.MINUTE, 30);
Retrieving the date
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
String dates = sdf.format(myCalendar.getTime());
StringTokenizer revDate = new StringTokenizer(dates, "/");
String txtDays = revDate.nextToken();
String txtMonths = revDate.nextToken();
String txtYears = revDate.nextToken();
String reversedDate = txtDays + txtMonths + txtYears;
On phones below API 24 we receive the correct date 03/01/2018 on API 24 above I receive 04/01/2018
I've tested my application on multiple virtual devices and real phones, all using the same time zone its only when using API 24 above that this strange issue occurs.
Thanks
I should like to contribute the modern version of your code. Barns’ answer is correct and should make sure your code behaves as it should. But I prefer:
LocalDateTime myDateTime = LocalDateTime.of(2018, Month.JANUARY, 3, 18, 30);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("ddMMuuuu");
String reversedDate = myDateTime.format(dtf);
This produces a reversedDate of 03012018 to denote 3 January 2018. If you needed the order of day-of-month, month and year reversed somehow, just modify the order in the format pattern string, for example uuuuMMdd or MMdduuuu.
I recommend the modern classes. Even though on not-too-brand-new Android devices, Calendar and SimpleDateFormat are what you get built-in, those classes are long outmoded and the latter in particular notoriously troublesome. So in my snippet I am assuming you have added ThreeTenABP to you Android project to allow you to use JSR 310, also known as java.time, the modern Java date and time API. This is so much nicer to work with. Import org.threeten.bp.LocalDateTime, org.threeten.bp.Month and org.threeten.bp.format.DateTimeFormatter. Also StringTokenizer is a legacy class. Its documentation says “It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.”
What went wrong in your code?
You haven’t given us a complete and reproducible example, so I cannot be sure, but strongly I suspect that you see the incorrect date when your code is running in the afternoon, that is at 12 noon or later in the myCalendar’s time zone (typically the JVM’s time zone, in turn typically your local time zone). Very likely myCalendar was created with the current time (Calendar.getInstance() and new GregorianCalendar(), for example, do this). In the afternoon it is obviously created with a time in PM. Then when you call myCalendar.set(Calendar.HOUR, 18), this tries to set the hour within PM, but since the hour is 18, this overflows into AM of the following day, becoming 6 AM the next day.
Links
Oracle tutorial: Date Time, explaining how to use JSR-310/java.time.
ThreeTen Backport project
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Java Specification Request (JSR) 310, where the modern date and time API was first described.
You should use "HOUR_OF_DAY" instead of "HOUR" when you set the time and you are using 24-hr system.
Try this:
myCalendar.set(Calendar.YEAR, 2018 );
myCalendar.set(Calendar.DAY_OF_MONTH, 3);
myCalendar.set(Calendar.MONTH, 0);
myCalendar.set(Calendar.HOUR_OF_DAY, 18);
myCalendar.set(Calendar.MINUTE, 30);
According to JAVA Docs:
HOUR_OF_DAY
public static final int HOUR_OF_DAY
Field number for get and set indicating the hour of the day.
HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM
the HOUR_OF_DAY is 22.
HOUR
public static final int HOUR
Field number for get and set indicating the hour of the morning or
afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and
midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the
HOUR is 10.
I think you should use getInstance() method of calendar class because Calendar.getInstance() method gets a calendar using the specified time zone and specified locale.
for eg:
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
Date dat = Calendar.getInstance().getTime();
String s3 = df.format(dat);
this works perfectly fine with my program and gives me desired result along with manipulation of date in the desired format.
I'm using Joda library in my android application to calculate the duration between two given dates. Using this application to calculate a person's age.
The following code gives this output : 23 years 11 months and 6 days
DateTime from_readable_dateTime = new DateTime(from_date_dt);
DateTime to_readable_dateTime = new DateTime(to_date_dt);
Period period = new Period(from_readable_dateTime, to_readable_dateTime);
from_date_dt in this case is 1990/01/06 and to_date_dt is 2014/09/15. (date format is yyyy/mm/dd). As I mentioned earlier the output of this piece of code with the given inputs must be 24 years, 7 months and 20 days while I get 23 years 11 months and 6 days. What's the problem? Am I doing something wrong or Joda is faulty?
UPDATE-1
I get 3 numbers as year, month and day from 3 number pickers I make a single string as date(start date variable is named from_date_string and end date is named to_date_string), I convert these two strings to date variables (from_date_dt and to_date_dt):
from_date_dt = null;
to_date_dt = null;
diff_dt = null;
dateFormat = new SimpleDateFormat("yyyy/mm/dd");
try {
from_date_dt = dateFormat.parse(from_date_string);
to_date_dt = dateFormat.parse(to_date_string);
} catch (ParseException e) {
e.printStackTrace();
}
BTW, I'm working with Persian calendar. Since I can't use the default date picker, I'm using number pickers as date pickers.
The standard period type which you implicitly use contains weeks. The class Period has another constructor with 3 arguments where you can specify PeriodType.yearMonthDay() as third argument.
LocalDate d1 = new LocalDate(1990, 1, 6);
LocalDate d2 = new LocalDate(2014, 9, 15);
Period p = new Period(d1, d2, PeriodType.yearMonthDay());
System.out.println(p); // output: P24Y8M9D
To explain the result in fine-granular steps:
[1990-01-06] + 24 years = [2014-01-06]
[2014-01-06] + 8 months = [2014-09-06]
[2014-09-06] + 9 days = [2014-09-15]
Another thing to consider, don't use DateTime if your input is just a plain date format. Do you really want to take into account timezone effects? And why do you use SimpleDateFormat although JodaTime has its own formatters?
UPDATE after updated question of OP:
Now the question has become a lot clearer.
First to note generally, if you use number pickers then your original input for year, month and day-of-month are just integers. In that case I would normally not use a formatter at all, but just pass the numbers to the constructor of LocalDate. This constructor will also verify the input automatically. The complex conversion you try is very error-prone (number to string, then string concatenation to a date string, then parsing it with your default timezone and then passing java.util.Date to DateTime-ctor). It can be completely avoided.
Second to note and most important: You write that you use a persian calendar. Then the reason why you cannot use the default date picker is simply that this default date picker does not support the calendrical rules of persian calendar. Is my speculation right? And here the very bad news for you: Jodas classes do NOT support the persian calendar, too, especially LocalDate or DateTime are only designed for the ISO-8601-standard which is based on the modern proleptic gregorian calendar. Month lengths for example are different in gregorian calendar and in persian calendar, hence a completely different calendar arithmetic is required which is not supported by Joda-Time.
So your strange period results are probably explainable by the fact that you tried to let the user define persian year, month and day. And then you try to parse this input leniently (otherwise Joda-Time would immediately complain about odd day-values for example). But the last step - period calculation - must fail because it is based on ISO-8601 in Joda-Time and not persian calendar rules.
Am I right? Or have I misinterpreted your updated question?
A work-around is difficult. If you really want to have period calculation for a persian calendar then you have to build it from the scratch. As far as I know there is actually no library which supports this feature. A guideline for writing a persian solution can be the algorithm discussed in this SO-post however.
UPDATE indicating a solution:
Meanwhile I have implemented the Persian calendar in Time4A, see also this SO-post. So if you are able to use Time4A and combine the PersianCalendar with the algorithm for a multi-unit-period mentioned above then this will solve your problem. Time4A-v3.15-2016a explicitly supports special Persian calendar units which use different rules than gregorian calendar units.
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.
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);
}