Is it possible to get time difference from directly Calendar fields? - java

sorry if the title is confusing. Let me explain clearly. I need to play with days, months and years. In order to do this I use Calendar. Here is my code;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int dayStart=0,monthStart=0,yearStart=0,dayFinish=0,monthFinish=0,yearFinish=0;
Calendar cal = (Calendar) Calendar.getInstance();
cal.set(Calendar.MONTH,Calendar.MAY); //SET MONTH AS MAY
cal.set(Calendar.DATE,1);
cal.set(Calendar.YEAR,2018);
monthStart=(cal.getCalendar.MONTH)+1);
dayStart=cal.get(Calendar.DATE);
yearStart=cal.get(Calendar.YEAR);
System.out.println("STARTING DAY: "+dayStart+" STARTING MONTH: "+monthStart+" STARTING YEAR: "+yearStart);
cal.add(Calendar.MONTH,6); //ADD 6 MONTHS
monthFinish = (cal.get(Calendar.MONTH)+1);
dayFinish = (cal.get(Calendar.DATE));
yearFinish = (cal.get(Calendar.YEAR));
System.out.println("FINISHING DAY: "+dayFinish+" FINISHNG MONTH: "+monthFinish+" FINISHING YEAR: "+yearFinish);
//WHAT I WANT IS printing out the days between 2 dates: 184
}
First, I set the time: 1 5 2018, then I add 6 months and the time becomes 1 11 2018. I need to get day difference as 184 (If I set the month January, it should be 181) Is it possible to do it just converting the corresponding Calendar fields (date,month,year) to secs or milliseconds and subtract millisecond value of (1 5 2018) from the (1 11 2018) and convert back milliseconds to days? There are similar questions but I couldn't find the solution exactly in the way I want.

java.time
LocalDate start = LocalDate.of(2018, Month.MAY, 1);
LocalDate finish = start.plusMonths(6);
long daysBetween = ChronoUnit.DAYS.between(start, finish);
System.out.format("Days between %s and %s: %d%n", start, finish, daysBetween);
IMHO it’s clear and it’s brief. And the bonus, it works correctly. Output is:
Days between 2018-05-01 and 2018-11-01: 184
The Calendar class has design problems and is now long outdated. So I recommend using java.time, the modern Java date and time API, instead. There is a way to have a Calendar count days correctly, but it’s more complicated than you would expect, and there is no reason why you should want to bother. Calculating the days from the milliseconds (which is shown in several answers on Stack Overflow, not only the other answer to this question) will sometime give the correct result, sometimes not. The two issues are: (1) Due to summer time (DST) and other discontinuities a day may be 23, 24 or 25 hours or some number between or even outside this interval. If a day in the interval is shorter than 24 hours, converting from the milliseconds will yield 1 day too little. (2) A Calendar (despite its name) also holds time of day. In your code it will hold the same time of day before and after you add 6 months. In other cases the different time of day may cause you to get 1 day too few, or in rare cases 1 day too many.
Question: Can I use java.time on Android?
Yes, java.time works nicely on Android devices. It just requires at least Java 6.
In Java 8 and later and on new Android devices (from API level 26, I’m told) the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310, where the modern API was first described).
On (older) Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. Make sure you import the date and time classes from package org.threeten.bp and subpackages.
Links
Oracle tutorial: Date Time, explaining how to use 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.

You can try the something similar to this should work for you
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Calendar1 {
public static void main(String args[])
{
Calendar startDate = Calendar.getInstance();
//Setting year, month and day
startDate.set(2018, 5, 1);
Calendar endDate = Calendar.getInstance();
endDate.set(2018, 11, 1);
long end = endDate.getTimeInMillis();
long start = startDate.getTimeInMillis();
System.out.println("Time difference in days " + TimeUnit.MILLISECONDS.toDays(Math.abs(end - start)));
}
}

Something this you can do. Change the year, Month and Date and set in the calendar.
Use java.time.temporal.ChronoUnit to get the difference.
The sample code is as below.
public void daysBetween() {
Calendar startOfMonth = Calendar.getInstance();
startOfMonth.set(Calendar.YEAR, 2018);
startOfMonth.set(Calendar.MONTH, 10);
startOfMonth.set(Calendar.DAY_OF_MONTH, 1);
Calendar endOfMonth = Calendar.getInstance();
endOfMonth.set(Calendar.YEAR, 2018);
endOfMonth.set(Calendar.MONTH, 10);
endOfMonth.set(Calendar.DAY_OF_MONTH, 30);
System.out.println(ChronoUnit.DAYS.between(startOfMonth.toInstant(),endOfMonth.toInstant()));
}

Related

Get Date of Specific Week

I'm trying to get the start and end date of specific week of a month. However the date is incorrect. Can anyone identify what's the issue ?
public class DateUtils
{
getWeeklyDateList(2020,5, 3);
public static void getWeeklyDateList(int year, int month, int week)
{
Calendar calendar = Calendar.getInstance(Locale.getDefault());
// setting year, month, week
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.WEEK_OF_MONTH,week);
// setting day of week to first --> Sunday
calendar.set(Calendar.DAY_OF_WEEK, 1);
int year1 = calendar.get(Calendar.YEAR);
int month1 = calendar.get(Calendar.MONTH);
int day1 = calendar.get(Calendar.DAY_OF_MONTH);
// setting day of week to last --> Saturday
calendar.set(Calendar.DAY_OF_WEEK, 7);
int year7 = calendar.get(Calendar.YEAR);
int month7 = calendar.get(Calendar.MONTH);
int day7 = calendar.get(Calendar.DAY_OF_MONTH);
Log.e("date_start", String.valueOf(year1) + "-" + String.valueOf(month1) + "-" + String.valueOf(day1));
Log.e("date_end", String.valueOf(year7) + "-" + String.valueOf(month7) + "-" + String.valueOf(day7));
} }
java.time and ThreeTenABP
If you want to use java.time, the modern Java date and time API, it can be done with this simple method:
private static WeekFields wf = WeekFields.of(Locale.forLanguageTag("ne-NP"));
public static void getWeeklyDateList(int year, Month month, int week) {
LocalDate someDateInTheWeek = LocalDate.of(year, month, 10).with(wf.weekOfMonth(), week);
LocalDate start = someDateInTheWeek.with(wf.dayOfWeek(), 1);
LocalDate end = someDateInTheWeek.with(wf.dayOfWeek(), 7);
System.out.println("date_start: " + start);
System.out.println("date_end: " + end);
}
Trying it out with your example arguments:
getWeeklyDateList(2020, Month.JUNE, 3);
Output is:
date_start: 2020-06-14
date_end: 2020-06-20
How it works:
First, weeks are defined differently in different cultures. In Nepal (since you give Kathmandu, Nepal as your location) weeks start on Sunday and are numbered in a way where the 1st of the month is in week 1 of the month. To handle this week scheme I am initializing a WeekFields object for Nepalese culture.
LocalDate is the java.time class for a date without time of day. I don’t think it matters which day of the month I pick as a starting point; I took the 10th. From that date I get a date in the correct week, using the WeekFields object and the supplied week number. From there in turn I get the first and the last day of the week, again according to the Nepalese definition of weeks: from Sunday June 14 through Saturday June 20 2020.
What went wrong in your code I cannot tell. In any case the Calendar class you used is poorly designed and long outdated. It also default uses the default locale of the JVM for its week definition, which may have given you a different week scheme from what you wanted. A final point that may have confused you: Calendar unnaturally numbers months from 0 for January through 11 for December. So when you specified 5, you got June (not May). You printed out the month numbers of your result dates, which probably again printed 5 (not 6) for June.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Question: Why is January month 0 in Java Calendar?
Its because of this line,
calendar.set(Calendar.DAY_OF_WEEK, 1);
this can take month to previous month if week starts in previous one. If there is a month difference then this is the problem.

Convert month and day number to day of year using CALENDAR

I have two numbers.
First would be the month number.
Second would be the day number.
I also know the year.
How can I take those two number, month and day and make it into a single number DAY_OF_YEAR?
I'm using Java 1.7 and the Calendar functions.
java.time through ThreeTen Backport
int year = 2019;
int monthNumber = 9;
int dayNumber = 28;
LocalDate date = LocalDate.of(year, monthNumber, dayNumber);
int dayOfYear = date.getDayOfYear();
System.out.println("Day of year is " + dayOfYear);
Output from this snippet is:
Day of year is 271
Tested on Java 1.7.0_79 using ThreeTen Backport 1.3.6 and importing org.threeten.bp.LocalDate.
Consider avoiding the Calendar class
Four lines of the currently accepted answer creating and setting the Calendar object are substituted by just one line here. It’s typical for code using Calendar to be so wordy, which we shouldn’t want. Also despite the name a Calendar object is more than a calendar date, it also carries with it a time of day, a time zone and more, so I do not consider it a good fit for the job at hand. The code using Calendar will give a different result if the default locale is Thai, which will surprise most. The Calendar class is poorly designed and long outdated.
Instead I am using LocalDate of java.time, the modern Java date and time API.
Question: Can I use java.time on Java 7?
I'm using Java 1.7 …
java.time works nicely on Java 7. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Just using calendar and assuming by number of month you mean the zero-indexed one where 0 means January, here is an example for May 13th 2019:
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH);
c.set(Calendar.YEAR, 2019);
c.set(Calendar.MONTH, 4);
c.set(Calendar.DAY_OF_MONTH, 13);
System.out.println(c.get(Calendar.DAY_OF_YEAR));
Edit: As Ole V.V.'s answer pointed out you get a Calendar object with the system's timezone if you call 'Calendar.getInstance()', so I changed it that way that you explicitly specify the timezone and Locale to be used. The latter is important if you e.g. want to get a date's week number where the rules differ in different regions of the world.
You can concat your parts into a String, and use a SimpleDateFormatter like:
int year = 2019;
int month = 1;
int day = 23;
String string = "" + year + "-" + month + "-" + day;
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse(string);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
The example is for 2019 January 23.

Convert seconds since 01-01-1900 to timestamp in Brazil

I'm managing devices that report their system clock as seconds since midnight 01-01-1900.
I need to convert this into a timestamp.
So far, I'm doing this as follows:
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class TestTime
{
// Pass seconds since 01-01-1900 00:00:00 on the command line
public static void main(String[] args)
{
// ---------------------
// Create time formatter
// ---------------------
SimpleDateFormat format;
format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// ---------------------------
// Compose 01-01-1900 00:00:00
// ---------------------------
Calendar cal;
cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1900);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// -------------------
// Show what we've got
// -------------------
System.out.println(format.format(cal.getTime()));
// ---------------------------------------------
// Add the seconds as passed on the command line
// ---------------------------------------------
long secs = Long.parseLong(args[0]);
while (secs > Integer.MAX_VALUE)
{
cal.add(Calendar.SECOND, Integer.MAX_VALUE);
secs -= Integer.MAX_VALUE;
}
cal.add(Calendar.SECOND, (int)secs);
// -------------------
// Show what we've got
// -------------------
System.out.println(args[0] + " corresponds to " + format.format(cal.getTime()));
} // main
} // class TestTime
When running this on my local PC (Italy, Windows 7), I get the following:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 10:13:20
This is perfectly correct.
I get the same results when running this on a Linux machine (still in Italy).
However, running the very same program on a Linux machine in Brazil, I get different results:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 11:19:48
Whatever value I pass on the commandline, the difference is always 01:06:28.
Any idea where this difference is coming from?
BTW, I'm not concerned about the timezone. I just need a timestamp
Update 1:
The very same thing happens also when using Java 6 (which is the actual version used within our production environment in Brazil).
So, the problem does not depend on the java version
Update 2:
The problem does not occur when entering a number of seconds below 441763200 (which corresponds to 01-01-1914 00:00:00)
The question remains why we get a difference for Brazil?
java.time
A solution is to make sure you do your conversion in UTC:
Instant base = LocalDate.of(1900, Month.JANUARY, 1)
.atStartOfDay(ZoneOffset.UTC)
.toInstant();
String secsSince1900String = "3752388800";
long secsSince1900 = Long.parseLong(secsSince1900String);
Instant target = base.plusSeconds(secsSince1900);
System.out.println(target);
Output (independent of JVM time zone):
2018-11-28T10:13:20Z
The trailing Z in the output means UTC. I have tested while setting my JVM’s default time zone to America/Sao_Paulo, it made no difference. If you want, you can formate the date and time to your liking, for example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = target.atOffset(ZoneOffset.UTC).format(formatter);
System.out.println(formattedDateTime);
2018-11-28 10:13:20
What went wrong when running in Brazil?
There are a number of time zones across Brazil. I took São Paulo as an example and reproduced your output readily. At the turn of the century in 1900, São Paulo was at offset -03:06:28 from GMT. Your Calendar uses the JVM’s default time zone, so you really set its time of day to 03:06:28 GMT, which explains the difference.
That said, the date-time classes you were using — SimpleDateFormat and Calendar — have design problems and have fortunately been replaced by java.time, the modern Java date and time API, with Java 8 nearly 5 years ago. One trait of the modern API is we more naturally make time zone explicit, which makes it easier to avoid issues like yours, and also to fix them if we run into them anyway.
Question: Our production Java version is Java 6. Can I use java.time?
Yes, java.time works nicely on Java 6. It has been backported.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Have a look at this site: https://www.timeanddate.com/time/zone/brazil/sao-paulo and navigate to Time zone changes for: 1900-1924. There you can see an offset of -03:06:28 to UTC before 01-01-1914. It is exactly the same reason as in Why is subtracting these two times (in 1927) giving a strange result?
On Jan 1st, 1914 Brazil changed the time and added 6 minutes and 28 seconds to their time moving from LMT to BRT (see Time Changes in São Paulo Over the Years, 1900-1924).
The additional one hour of difference is probably that Brazil spans 3 time zones (UTC-4, UTC-3, UTC-2) and you didn't set the time zone in your code, depending on the JVM system time zone.

check if a date is equal independently of the year

I use javaSE 1.6 and I need to compare two dates and check if they are the same. this check needs to be independent of the year.
for example, i need to identify if today is the B-day of someone, and I need this code to be reused in the coming years.
so I need to perform the check, not on the year, not even on the day-of-the-year (issue with Leap year) but I can only rely on the day-of-the-month and the month number itself.
my input data, the birthday day of the person, it is in the Java class "Date"
is there any method of javaSE 1.6 that could help me?
I checked classes "Date" and "Calendar", but so far I couldn't find any hint to solve my issue.
ThreeTen Backport
public static MonthDay toMonthDay(Date utilDate) {
Instant inst = DateTimeUtils.toInstant(utilDate);
ZonedDateTime dateTime = inst.atZone(ZoneId.systemDefault());
return MonthDay.from(dateTime);
}
The MonthDay class of java.time is what you need, it’s a date without year, or conversely, a month and a day-of-month. Birthdays and other days to remember are the prime example for its use.
Like this:
Date birthday = // ...
Date today = new Date();
if (toMonthDay(today).equals(toMonthDay(birthday))) {
System.out.println("It’s her birthday");
} else {
System.out.println("It’s not her birthday");
}
On Java 6 you need to use the ThreeTen-Backport, the backport of java.time to Java 6 and 7.
I am hesitatingly using ZoneId.systemDefault() to use the JVM’s time zone setting for the conversion. On one hand the Date would normally assume this time zone; on the other hand this is fragile because the setting can be changed at any time from other parts of your program or other programs running in the same JVM. If you know better, by all means give a time zone like for example ZoneId.of("America/Adak")
If using Java 8 or later and the built-in java.time, the conversion is a little bit simpler:
ZonedDateTime dateTime = utilDate.toInstant().atZone(ZoneId.systemDefault());
return MonthDay.from(dateTime);
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I found the way to call the Month and date-of-month in class Calendar.
here is my solution, I didn't find any other example on this topic, so I'll paste, maybe could help someone in the future.
if you have a more stylish solution, please let me know.
I'll be glad to learn :)
// date of the B-day 31st December
int month = Calendar.DECEMBER;
int date = 31;
boolean status = false;
// Class Date already filled with the date we wanna check.
Date beginDate;
Calendar c = Calendar.getInstance();
c.setTime(beginDate);
int dayOfMonthToCompare = c.get(Calendar.DAY_OF_MONTH);
int monthToCompare = c.get(Calendar.MONTH);
//perform check on day and Month
if(dayOfMonthToCompare == date && monthToCompare == month){
status = true;
}

Discrepancy in Java Calendar set Day Of Month vs Get Day Of Month

I am setting a Calendar day of month with an int value but when I check the value again the day of month from the created calendar it is 1 more than I set it to. And I am not sure why?
Here is an example:
System.out.println("DEBUG: Reminder day of month = " + reminder.getReminderDayofMonth());
calendar.set(Calendar.YEAR, reminder.getReminderYear());
calendar.set(Calendar.MONTH, reminder.getReminderMonth());
calendar.set(Calendar.DAY_OF_MONTH, reminder.getReminderDayofMonth());
calendar.set(Calendar.HOUR, reminder.getReminderHour());
calendar.set(Calendar.MINUTE, reminder.getReminderMinute());
System.out.println("DEBUG: Calendar day of month = " + calendar.get(Calendar.DAY_OF_MONTH));
I did the println so you can see the value in and the value out. I would expect that calling calander.get(Calander.DAY_OF_MONTH) would return the same value as I put into it. But it doesn't, I get:
DEBUG: Reminder day of month = 18
DEBUG: Calendar day of month = 19
I am sure it is probably something simple but I have no idea why they would be different and I can't find anything in the docs to explain the discrepancy
What is the problem?
Thanks for your help
TL:DR
LocalDateTime ldt = LocalDateTime.of(
reminder.getReminderYear(),
reminder.getReminderMonth() + 1, // Add one to adjust from zero-based counting.
reminder.getReminderDayofMonth(),
reminder.getReminderHour(),
reminder.getReminderMinute()
);
java.time
I suggest you put an end to using the very old and long outmoded Calendar class. Today we have so much better in java.time, the modern Java date and time API also known as JSR-310. The above code gives you the equivalent of what I think you were trying. I assumed getReminderMonth() returned 0-based month, so added 1 since the modern API numbers months from 1 just as humans do. If you can, I recommend you use an OffsetDateTime or ZonedDateTime to make the point on the time line unambiguous.
Question: Can I use the modern API with my Java version?
If using at least Java 6, you can.
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR-310; link below).
On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. See the linked question below.
What went wrong in your code
I think the observed date increment happens when both of the following conditions are met:
Your code is running in the afternoon, that is at 12 noon or later in the Calendar’s time zone (typically the JVM’s time zone, in turn typically your local time zone).
getReminderHour() returns an hour in the afternoon, that is, 12 or later.
I cannot be 100 % sure since you haven’t shown us the code that produced your bug. But very likely your Calendar instance 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 calendar.set(Calendar.HOUR, reminder.getReminderHour()), this tries to set the hour within PM, but since the hour is 12 or greater, this overflows into AM of the following day. An hour of 14 (PM), for example, becomes 2 AM the next day.
If I am correct, the problem may seem solved not because you moved the creation of the calendar object inside your if statement, but because either you ran your program in the morning or the reminder hour was in the morning (before 12 noon). And your bug may surface again next time both the above-mentioned conditions apply,
Links
Oracle tutorial trail: Date Time
Question: How to use ThreeTenABP in Android Project
ThreeTen Backport home page
Java Specification Request (JSR) 310, where the modern API was first defined

Categories