How to make gc.setTime() from GregorianCalendar fixed - java

Here is a part from my code:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(dateFormat.parse(jahr+"-"+monat+"-"+tag));
And now I want to print out some moving easter holidays in Germany.
gc.add(Calendar.DAY_OF_MONTH, -2);
System.out.println("Karfreitag;"+dateFormat.format(gc.getTime()));
gc.add(Calendar.DAY_OF_MONTH, +3);
System.out.println("Ostermontag;"+dateFormat.format(gc.getTime()));
gc.add(Calendar.DAY_OF_MONTH, +38);
To make it a bit clearer.
Eastersunday was on 16.04.2017 this year.
So the first print out is working fine, 'Karfreitag' is two days before eastersunday. So it was the 14.04.2017.
Moving on to eastermonday throws a problem. Eastermonday is the day after eastersunday. Unfortuanately I have to add +3 days because I overwrote the eastersunday date with the 'Karfreitag' date.
So I want to know if it is possible to make the date from eastersunday fix so that I have to change my 3th line into:
gc.add(Calendar.DAY_OF_MONTH, +1);
It think this could be very easy but I have no clue how to change this in a proper way.

As the add method changes the current calendar instance, one solution is to create another one, using the clone() method:
// clone it before changing it
GregorianCalendar other = (GregorianCalendar) gc.clone();
gc.add(Calendar.DAY_OF_MONTH, -2);
System.out.println("Karfreitag;" + dateFormat.format(gc.getTime()));
other.add(Calendar.DAY_OF_MONTH, 1);
System.out.println("Ostermontag;" + dateFormat.format(other.getTime()));
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java 6 or 7, 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 (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
As you're dealing with dates (day/month/year), you can use the LocalDate class. In this new API, classes are immutable, so the methods that add a number of days always create another object:
LocalDate easter = LocalDate.parse("2017-04-16");
// minusDays and plusDays return a new LocalDate, keeping the original unchanged
System.out.println("Karfreitag;" + easter.minusDays(2));
System.out.println("Ostermontag;" + easter.plusDays(1));
The output will be:
Karfreitag;2017-04-14
Ostermontag;2017-04-17
If you have the day, month and year as int values, you can create a LocalDate using the of method:
int tag = 16;
int monat = 4;
int jahr = 2017;
// Easter
LocalDate easter = LocalDate.of(jahr, monat, tag);
Convert from/to GregorianCalendar
If you still need to work with GregorianCalendar, you can easily convert it from/to the new API. In Java 8 there are new methods to do the conversion, while in Java 6/7 ThreeTen Backport there's the org.threeten.bp.DateTimeUtils class:
// Java 8: convert calendar to local date
LocalDate dt = gc.toZonedDateTime().toLocalDate();
// Java 7: convert calendar to local date
LocalDate dt = DateTimeUtils.toZonedDateTime(gc).toLocalDate();
To convert the LocalDate back to GregorianCalendar is a little bit tricky. A LocalDate has only the date fields (day, month and year), while a GregorianCalendar represents a "full date": a date and time in a specific timezone.
So, when converting a LocalDate to a GregorianCalendar, you must make some assumptions about the time (hour, minutes, etc) and the timezone. One example is to set the time to midnight, and use the JVM default timezone:
// Java 8: convert local date to calendar (midnight in JVM default timezone)
GregorianCalendar cal = GregorianCalendar.from(dt.atStartOfDay(ZoneId.systemDefault()));
// Java 7: convert local date to calendar (midnight in JVM default timezone)
GregorianCalendar cal = DateTimeUtils.toGregorianCalendar(dt.atStartOfDay(ZoneId.systemDefault()));
You can also convert to any other time of the day and change the timezone to whatever you want:
// set to 10:30 AM in Berlin timezone
dt.atTime(10, 30).atZone(ZoneId.of("Europe/Berlin"));
Or you can use the ZonedDateTime returned by toZonedDateTime() directly, and extract the LocalDate part when printing:
// convert calendar to ZonedDateTime
ZonedDateTime z = gc.toZonedDateTime();
// print just the LocalDate part
System.out.println("Karfreitag;" + z.minusDays(2).toLocalDate());
System.out.println("Ostermontag;" + z.plusDays(1).toLocalDate());
// get the original calendar back
GregorianCalendar cal = GregorianCalendar.from(z);
This new API has lots of new types and allows you to choose the best for each case.

Start using java.time.LocalDate. It provide a LocalDate.plusDays(long) that return a copy of the instance.
Returns a copy of this LocalDate with the specified number of days added.
Like this :
LocalDate tomorrow = LocalDate.now().plusDays(1);
And you can get an instance using LocalDate.of(int, int, int) like :
LocalDate date = LocalDate.of(year, month, day);
NOTE: This is a shorter version of Hugo's answer, just realise that there were to part in his answer...

You can use DateUtils.addDays like this:
DateUtils.addDays(gc.getDate(), -2).getTime()
It needs a Date object (you can use gc.getDate() for this) and int number of days to add as arguments and also return a Date object without modifying your original gc.
System.out.println("Karfreitag;"+dateFormat.format(DateUtils.addDays(gc.getDate(), -2).getTime()));
System.out.println("Ostermontag;"+dateFormat.format(DateUtils.addDays(gc.getDate(), 3).getTime()));
System.out.println("something else;"+dateFormat.format(DateUtils.addDays(gc.getDate(), 38).getTime()));
In Android its available from API level 3,in Java you'll have to use Apache Commons

Related

How to use Calendar[] array to set the days to disable in setDisabledDays(Calendar[] days) in wdullaer Material DateTime Picker

I'm trying to disable some days using setDisabledDays(Calendar[] days) method of wdullaer's material datetime picker, an alternative datetime picker for Android.
But I don't know how to pass the dates to the method using Calendar[]
abscanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
datePickerDialog = DatePickerDialog.newInstance(MainActivity.this, Year, Month, Day);
datePickerDialog.showYearPickerFirst(false);
datePickerDialog.setMinDate(calendar);
Calendar[] days = new Calendar[3];
days[0] = // I don't know how to do this part
datePickerDialog.setDisabledDays(days);
datePickerDialog.show(getFragmentManager(), "DatePickerDialog");
}
}
I successfully setMinDate() without any errors. I just need to know how to create the dates I will put in the Calendar array.
Note: I'm trying to add the dates manually.
To create the Calendar is easy:
Calendar cal = Calendar.getInstance();
This calendar will have the current date and time, at the JVM default timezone. If you want to set a different day, or month, or whatever, use the set method:
// set to March 5th 2018
cal.set(Calendar.DAY_OF_MONTH, 5);
cal.set(Calendar.MONTH, Calendar.MARCH);
cal.set(Calendar.YEAR, 2018);
In this API, months are zero-based (January is zero, February is 1, etc), so it's better to use the constants, such as Calendar.MARCH, to avoid any off-by-one errors.
This class is mutable, so always create a new instance with getInstance() before assigning it to your array.
Threeten Backport
As said in the comments, you can use this library - much nicer and compatible with the java.time API (this will make a future migration easier, as the java.time classes are available in newer Android API levels). See how to install/configure this lib here.
With this lib, it's even easier to create a specific date:
// March 5th 2018
LocalDate date = LocalDate.of(2018, Month.MARCH, 5);
Or, to get the current date:
LocalDate date = LocalDate.now();
Then, to convert to a Calendar, you must set it to a timezone and then convert:
Calendar cal = DateTimeUtils.toGregorianCalendar(date.atStartOfDay(ZoneId.systemDefault()));
It seems harder at first, but if you study this API, you'll soon see the benefits. Calendar follows a kind of one-size-fits-all design, but it's known to be troublesome and outdated. The new API provides different date/time types for each use case, and you must explicity convert between them to get what you need.
That's why the conversion code above seems so confusing, but once you get the idea, it becomes much easier than using Calendar.

Loop a Task for one Year with GregorianCalendar

I have to write a program which shows a Timeplan about when to send emails.
The User is inputing a Start date and I have to show the timeplan for one year.
How do I loop the Task?
In this example the mails should be sent every 8 days.
if(recipient==0) {
System.out.println("send mail on this day:" +calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),8);
return true;
}
I would like to loop the System.out.println and the calendar.add task until it is one year later.
edit: I have another case where it should send the emails every 16 days but when the day is a saturday or sunday it should send the mail on the following monday.
I did it like this but now I get more dates than I need.
if(empfaenger==1)
{
for (Date d=startDate; d.before(endDate); d.setTime(d.getTime() + (1000 * 60 * 60 * 24 * 8)))
{
if(calendar.get(calendar.DAY_OF_WEEK)==1)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR),1);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR), 16);
}
else if(calendar.get(calendar.DAY_OF_WEEK)==7)
{
calendar.add((GregorianCalendar.DAY_OF_YEAR), 2);
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
else
{
System.out.println("mail will be sent on this day:"+calendar.getTime());
calendar.add((GregorianCalendar.DAY_OF_YEAR),16);
}
//System.out.println(calendar.getTime;)
}
}
Here is a sample using java.time api from java 8 , it's much more easier to understand and use compered to calendar or date classes :
static void sendEveryEightDays(){
LocalDateTime timeToSendEmail= LocalDateTime.now();
LocalDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}
if you want to take the user's time zone into consideration you can use ZonedDateTime instated off LocalDateTime :
static void sendEveryEightDays(ZoneId userTimeZone){
ZonedDateTime timeToSendEmail= ZonedDateTime.now(userTimeZone);
ZonedDateTime afterAYear = timeToSendEmail.plusYears(1);
while(timeToSendEmail.isBefore(afterAYear)){
System.out.println("SendTheEmail "+timeToSendEmail.toString());
timeToSendEmail=timeToSendEmail.plusDays(8);
}
}
I wonder why teachers are still teaching the old API (Date, Calendar and SimpleDateFormat), because they have lots of problems and design issues, and they're being replaced by the new APIs. (Java 8 was released in 2014, btw).
Anyway, if you have a GregorianCalendar, you can convert it to the new java.time classes and do the rest with them.
First, you can use the calendar to create an Instant:
Instant instant = Instant.ofEpochMilli(calendar.getTimeInMillis());
The only problem is that, if you create a Calendar and set the day, month and year, it will have the current time (hour/minute/seconds), so the Instant above will have the current time in UTC. If that's ok, you can convert this instant to your timezone:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime start = instant.atZone(zone);
I used America/Sao_Paulo, but you can change to the timezone that makes sense to your system. 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 if you want (ZoneId.systemDefault()), but note that this can be changed without notice, even at runtime, so it's always better to specify which timezone you're using. If you want to work with dates in UTC, you can use the built-in constant ZoneOffset.UTC.
The code above will create a ZonedDateTime with the calendar's date and time adjusted to the specified timezone. Just reminding that, if you do something like this:
Calendar calendar = new GregorianCalendar();
calendar.set(2017, 7, 12);
The date will be equivalent to August 12th 2017 (because months in the Calendar API start at zero, so month 7 is August), and the time will be the current time when the calendar is created.
If you want to specify the hour, you have some options to adjust it:
// change the hour/minute/second to 10:20:45
start = start.with(LocalTime.of(10, 20, 45));
// change just the hour to 10
start = start.withHour(10);
// set to start of the day
start = start.toLocalDate().atStartOfDay(zone);
With this, you can change the time (and also date) fields accordingly. Check the javadoc and Oracle's tutorial to see all the options available. The method atStartOfDay is better because it takes care of Daylight Saving Time changes (depending on DST shift, the day can start at 1AM instead of midnight, and this method takes care of all the details).
If you don't want to rely on Calendar, you can also create the date directly:
// creating August 12th 2017, at 10:00
start = ZonedDateTime.of(2017, 8, 12, 10, 0, 0, 0, zone);
Note that August is month 8 (one of the best and most obvious improvements from the old API).
Now that you have the starting date, you can loop through a whole year and check the dates according to your rules. I'm using the example of sending the email each 16 days and adjust to next monday if it's a weekend:
ZonedDateTime d = start;
// ends in 1 year - this method already takes care of leap years
ZonedDateTime end = start.plusYears(1);
while (end.isAfter(d)) {
d = d.plusDays(16);
if (d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SATURDAY) {
// weekend, adjust to next monday
d = d.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
// send email
}
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes.
The only difference from Java 8 is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
As #BasilBourque reminded me in the comments, you can also convert a GregorianCalendar to a ZonedDateTime using the toZonedDateTime() method (this will use the calendar's timezone - usually the system's default, if you don't set it). You can also convert it to an Instant using the toInstant() method. The only restriction is that those methods are only available in Java 8 (so, if you're using ThreeTen Backport, just use the way it's described above).

add 1 month from current date using java.sql.Date

Hello i have a problem with the result of java.sql.Date. This is my code with adding 1 week from current date
Date kini = new Date();
java.sql.Date jadwalPengobatan = new java.sql.Date(kini.getTime()+7*24*60*60*1000);
If current date is 2016-02-27, then the result in my MySQL is 2016-03-05.
But if i want to add 1 month (for my case its always 31 days) from current date using this line code
java.sql.Date jadwalPengobatan = new java.sql.Date(kini.getTime()+31*24*60*60*1000);
It should be 2016-03-28 but in my MySQL result is 2016-02-05. Anyone can help me whats wrong with this result??
java.time
The other Answers use the outmoded old date-time classes. After proving to be confusing, troublesome, and flawed, they have been supplanted by the java.time framework in Java 8 and later.
Do not use the java.sql classes in your business logic. They are a messy extension of those old date-time classes, and are a badly-designed hack. Use them only for transferring your data in/out of the database. Convert to java.time types immediately.
To convert, use the new methods added to the old classes.
In the case of java.sql.Date, it is pretending to hold a date-only value without time-of-day nor time zone. The java.time classes include a true date-only value, LocalDate. To convert from java.sql.Date to java.time.LocalDate, call java.sql.Date::toLocalDate.
LocalDate ld = mySqlDate.toLocalDate();
Adding a true month is built-in.
LocalDate monthLater = ld.plusMonths( 1 );
Convert back to java.sql for storage in the database.
java.sql.Date sqlDate = java.sql.Date.valueOf( monthLater );
Hopefully some day we will see the JDBC drivers updated to support the java.time types directly. Then the java.sql types will fade away as old relics of the past. But until then we need to perform these java.sql ↔ java.time conversions.
Update: JDBC 4.2 and later provides for passing java.time types directly with PreparedStatement::setObject, and fetching with ResultSet::getObject. So no need for conversion to java.sql types.
Use Calendar:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, 1);
Date result = cal.getTime();
The problem with your solution is that you are not doing the calculations in long.
You have to replace 31*24*60*60*1000 with 31l*24l*60l*60l*1000l.
Here is the corrected code snippet:
public static void main (String[] args)
{
Date kini = new Date();
java.sql.Date jadwalPengobatan = new java.sql.Date(kini.getTime() + 31l*24l*60l*60l*1000l);
System.out.println(jadwalPengobatan);
}
Please note that this will only fix your calculation where you are adding 31 days to the current date. If you are looking to add a month which can be of 30, 28 or 29 days also then perhaps you should make use of Calendar.
Today's Date:
2016-02-27
Output:
2016-03-29
One solution to your problem would be to alter the date in MySQL using the DATE_ADD() function:
DATE_ADD(yourDate, INTERVAL 1 MONTH)
SimpleDateFormat date= new SimpleDateFormat("dd/MM/yyyy");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.MONTH, 1);
String output= date.format(calendar.getTime());
java.sql.Date jadwalPengobatan = new java.sql.Date(output);
You could do the following, using Calendar:
Date kini = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(kini);
cal.add(Calendar.DATE, 7); // add 10 days, e.g. 1 week
cal.add(Calendar.DATE, 31); // add 31 days, e.g. ~1 month
java.sql.Date jadwalPengobatan = new java.sql.Date(cal.getTime());
Also see this discussion.

What is the most efficient way to create Date Object in Java

I am creating Date object in java.
First way:
By using Calender
Date today = Calendar.getInstance().getTime();
Second way:
with Date class
Date today1 = new Date();
Which one is most effective way here?
Since Java 8 you should go for LocalDateTime or LocalDate:
LocalDateTime timePoint = LocalDateTime.now(
); // The current date and time
LocalDate.of(2012, Month.DECEMBER, 12); // from values
LocalDate theDate = timePoint.toLocalDate(); // or
theDate = LocalDate.now(); //
Fromt the documentation:
[For example, the existing classes (such as java.util.Date and
SimpleDateFormatter) aren’t thread-safe, leading to potential
concurrency issues for users—not something the average developer would
expect to deal with when writing date-handling code.
Some of the date and time classes also exhibit quite poor API design.
For example, years in java.util.Date start at 1900, months start at 1,
and days start at 0—not very intuitive.]1
If you have to decide between the two. Take the new Date(). As the Calendar.getInstance().getTime() would create a Calendar instance which you could not use afterwards.
You can use this too!
Date newDate = new GregorianCalendar(year, month, day).getTime();
Within your options, I will prefer the first alternative.

How to generate a Date from just Month and Year in Java?

I need to generate a new Date object for credit card expiration date, I only have a month and a year, how can I generate a Date based on those two? I need the easiest way possible. I was reading some other answers on here, but they all seem too sophisticated.
You could use java.util.Calendar:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
Date date = calendar.getTime();
java.time
Using java.time framework built into Java 8
import java.time.YearMonth;
int year = 2015;
int month = 12;
YearMonth.of(year,month); // 2015-12
from String
YearMonth.parse("2015-12"); // 2015-12
with custom DateTimeFormatter
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM yyyy");
YearMonth.parse("12 2015", formatter); // 2015-12
Conversions
To convert YearMonth to more standard date representation which is LocalDate.
LocalDate startMonth = date.atDay(1); //2015-12-01
LocalDate endMonth = date.atEndOfMonth(); //2015-12-31
Possibly a non-answer since you asked for a java.util.Date, but it seems like a good opportunity to point out that most work with dates and times and calendars in Java should probably be done with the Joda-Time library, in which case
new LocalDate(year, month, 1)
comes to mind.
Joda-Time has a number of other nice things regarding days of the month. For example if you wanted to know the first day of the current month, you can write
LocalDate firstOfThisMonth = new LocalDate().withDayOfMonth(1);
In your comment you ask about passing a string to the java.util.Date constructor, for example:
new Date("2012-09-19")
This version of the constructor is deprecated, so don't use it. You should create a date formatter and call parse. This is good advice because you will probably have year and month as integer values, and will need to make a good string, properly padded and delimited and all that, which is incredibly hard to get right in all cases. For that reason use the date formatter which knows how to take care of all that stuff perfectly.
Other earlier answers showed how to do this.
Like
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM");
Date utilDate = formatter.parse(year + "/" + month);
Copied from Create a java.util.Date Object from a Year, Month, Day Forma
or maybe like
DateTime aDate = new DateTime(year, month, 1, 0, 0, 0);
Copied from What's the Right Way to Create a Date in Java?
The most common sense approach would be to use the Date("YYYY-MM-DD") constructor even though it is deprecated. This is the easiest way to create a date on the fly. Screw whoever decided to deprecate it. Long live Date("YYYY-MM-DD")!!!
Don’t use this answer. Use the answers by Przemek and Ray Toel. As Przemek says, prefer to use a YearMonth for representing year and month. As both say, if you must use a date, use LocalDate, it’s a date without time of day.
If you absolutely indispensably need an old-fashioned java.util.Date object for a legacy API that you cannot change, here’s one easy way to get one. It may not work as desired, it may not give you exactly the date that you need, it depends on your exact requirements.
YearMonth expiration = YearMonth.of(2021, 8); // or .of(2021, Month.AUGUST);
Date oldFashionedDateObject = Date.from(expiration
.atDay(1)
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
System.out.println(oldFashionedDateObject);
On my computer this prints
Sun Aug 01 00:00:00 CEST 2021
What we got is the first of the month at midnight in my local time zone — more precisely, my JVM’s time zone setting. This is one good guess at what your legacy API expects, but it is also dangerous. The JVM’s time zone setting may be changed under our feet by other parts of the program or by other programs running in the same JVM. In other words, we cannot really be sure what we get.
The time zone issue gets even worse if the date is transmitted to a computer running a different time zone, like from client to server or vice versa, or to a database running its own time zone. There’s about 50 % risk that your Date will come through as a time in the previous month.
If you know the time zone required in the end, it will help to specify for example ZoneId.of("America/New_York") instead of the system default in the above snippet.
If your API is lenient and just needs some point within the correct month, you’ll be better off giving it the 2nd of the month UTC or the 3rd of the month in your own time zone. Here’s how to do the former:
Date oldFashionedDateObject = Date.from(expiration
.atDay(2)
.atStartOfDay(ZoneOffset.UTC)
.toInstant());

Categories