Get Day, Month, Year from Java Calendar instance - java

I have an Instant derived from a Java Calendar, e.g. c.toInstant(), and now in a different location convert that to a custom Date object that needs a day of the month, month, and year. I tried:
if (instance.isSupported(ChronoField.DAY_OF_MONTH) && instance.isSupported(ChronoField.MONTH_OF_YEAR) && instance.isSupported(ChronoField.YEAR)) {
return new com.company.common.Date()
.setDay(instance.get(ChronoField.DAY_OF_MONTH))
.setMonth(instance.get(ChronoField.MONTH_OF_YEAR))
.setYear(instance.get(ChronoField.YEAR));
}
But when I try to compile ErrorProne throws:
...impl/utils/DateUtils.java:21: error: [TemporalAccessorGetChronoField] TemporalAccessor.get() only works for certain values of ChronoField.
.setDay(instance.get(ChronoField.DAY_OF_MONTH))
^
I'm not sure why I can't find an answer for this anywhere, but after some searching I came up with nothing helpful -- though I probably missed something.

Instant is only a timestamp - it only provides seconds, millis and nanos.
If you start with a Calendar instance in the first place you should be able to simply use
calendar.get(Calendar.YEAR)
calendar.get(Calendar.MONTH) + 1
calendar.get(Calendar.DAY_OF_MONTH)
directly to fetch the date values and skip the conversion to Instant.
Note that in Calendar month is a zero-based value. You usually have to add one to get to value one would commonly expect.
If you prefer working with the newer time API you can fetch dates and time from a ZonedDateTime like
Calendar calendar = Calendar.getInstance();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
zonedDateTime.getYear();
zonedDateTime.getMonthValue();
zonedDateTime.getDayOfMonth();
I don't see a direct advantage for the example given, beyond getting the "correct" value for month here directly.
It could be useful if you want to do any additional work with the date value beyond just reading its contents.
Generally speaking ZonedDateTime and all other types from the java.time package provide the more robust API and functionality compared to the older Calendar type. Therefore avoid the calendar type for any new code

Related

Get the closest not-future hour of day from GregorianCalendar

I need to set my GregorianCalendar to a specific hour of day, which is the closest but not future.
If the time now is 21:00, and I need set the hour 22, it will be set to yesterday. But if the time now is 23:00, it will be set for today.
LocalTime hour = LocalTime.of(22, 0);
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Indiana/Marengo"));
ZonedDateTime closestHour = now.with(hour);
if (closestHour.isAfter(now)) { // future
closestHour = now.minusDays(1).with(hour);
}
System.out.println(closestHour);
This printed
2018-02-04T22:00-05:00[America/Indiana/Marengo]
The above is a sketch, not code that is ready for production. You need to supply your desired time zone if it didn’t happen to be America/Indiana/Marengo. And the desired clock hour, of course. If the desired time doesn’t exist, typically in the spring transition to summer time (DST), ZonedDateTime will pick a different time, you will need to detect that and act accordingly.
java.time
You asked for a GregorianCalendar, and I will give you one, but allow me to mention that that class is long outdated and poorly designed, so you shouldn’t want one. I recommend you use java.time, the modern Java date and time API instead.
If you need a GregorianCalendar or just a Calendar object for a legacy API that you cannot change or don’t want to change just now, convert like this:
GregorianCalendar cal = GregorianCalendar.from(closestHour);
Link: Oracle tutorial: Date Time

Java Convert Interval of Days to Dates

I have a dates in format such as:
- dd. - dd.MM.yyyy
Based on this information I want to receive from date and to date.
Naive implementation in pseudo code is:
Split the date into first part and second part
Create a SimpleDateFormat for second part
Take a look, whether the number in the first part is higher than the number in a second part.
If it is:
Decrement month for the first date
Create from date which will contain the dd from the first part, decremented month from the second part and year from the second part.
If it isn't:
Create from date which will contain the dd from the first part and month and year from second part.
This solution would probably work most of the time, but it feels rather awkward. Isn't there any better solution?
I'd suggest you to check the package
org.joda.time
In particular the following classes
DateTime
Period
java.time
The java.time framework is built into Java 8 and later. Much of that functionality is back-ported to Java 6 & 7 and to Android.
I provide some scraps of example code here, but untested – never run. Should get you going in the right direction.
Two tricky parts to this problem:
YearThe Question says to assign the year. That is not the case for a stop date in January with a start date that turns out to be in previous month, December. You want the previous year in such a case. Solution is to let java.time subtract a month and handle the Jan-to-Dec math for you.
Month lengthVarious months have different lengths, different number of days, obviously. Keep mind that you cannot try to put day-of-month 31 on to month of April. If your input data is always clean and valid, and our algorithm below is correct, this should be a non-issue. Nevertheless, I would certainly add some exception-catching code to my example code below to trap any attempt to form an invalid date.
I'll skip the string-splitting part, and assume you have a number (the day-of-month) from the first part, and a string of the date from the second part.
long dayOfMonth = Long.longValue( "31" );
That date is not in standard format, so we must specify a formatting pattern. A LocalDate represents a date-only value without time-of-day and without time zone.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd.MM.yyyy" );
LocalDate stop = LocalDate.parse( "21.05.2016" , formatter );
We can extract the day-of-month to compare.
LocalDate start = null;
int d = localDate.getDayOfMonth();
Do the comparison.
if( dayOfMonth >=d ) { // If start is in previous month…
start = stop.minusMonths( 1 ).withDayOfMonth( dayOfMonth );
} else if (dayOfMonth < d ) { // If start is in same month…
start = stop.withDayOfMonth( dayOfMonth );
} else {
// FIXME: handle impossible condition as error. The 'if' statements are flawed.
}
By the way, the format of this input data is awkward and, frankly, silly. This kind of precious “cleverness” creates extra work, gives opportunity for confusion and errors, is completely needless without providing any benefits, and drives me nuts. If you have any control of this input data I strongly suggest either of two possible changes.
First, if exchanging data within your app, do not use strings. Use objects. Above you have seen the LocalDate object. You could pass those around. Or even define your own class LocalDateRange to house a pair of LocalDate objects. Or see this Question and especially this Answer that talks about using the Google Guava class Range to hold the pair of LocalDate objects.
Secondly, when you must serialize date-time values to strings, use the standard ISO 8601 formats. Such use is simple as the java.time classes by default use these formats when parsing/generating strings. A date-only value should be in YYYY-MM-DD order. A date range interval is a pair of those strings mated with a slash (SOLIDUS) or alternatively a pair of hyphens when a slash is inappropriate (such as file or folder naming within a Unix-related file system).

Why is the Calendar before() method returning true for equal dates

I am setting a color field based on how the dueDate field compares to the current date. dueDate is an SQL Date type. My problem is when I pass in the current date the Calendar.before() method says the date is before the current date. My code is:
private String getDateDueColor(Date dateDue) {
Calendar today = Calendar.getInstance();
today.setTime(new java.sql.Date(Calendar.getInstance().getTime().getTime()));
Calendar dueDate = Calendar.getInstance();
dueDate.setTime(dateDue);
if(dueDate.before(today)){
return RED;
}else{
return NORMAL;
}
}
I have set a breakpoint and compared dueDate and today and all of the information in the cdate field for each object looks identical, but the dueDate.before(today) still returns true. Any help would be appreciated!
Are you sure they are equal? Method equals for Date and Calendar means they represents the same time value (millisecond offset from the Epoch). See the javadocs for Calendar.equals method:
Compares this Calendar to the specified Object. The result is true if and only if the argument is a Calendar object of the same calendar system that represents the same time value (millisecond offset from the Epoch) under the same Calendar parameters as this object.
The before method docs states that compareTo is used to decide if a calendar instance is before another. And again, compareTo is using millisecond precision. From the docs:
Compares the time values (millisecond offsets from the Epoch) represented by two Calendar objects.
The alternatives are:
If you have to use Calendar, create new instances, use clear method on them and then set values (year, month, hourOfDay, minute, second) using the set method.
Use the new java.time API and choose some type that better represents what you want (maybe java.time.LocalDate)
Use Joda Time if you can't go to Java 8.
The answer by marcospereira is correct. I'll add some general suggestions about revamping the code shown in the Question, and show the use of java.time.
Use java.sql only for database transfer
Do not pass around java.sql types and perform business logic on them. Use java.sql only for transferring data in and out of the database. For java.sql.Timestamp/.Date/.Time immediately convert them to java.time objects. Then proceed with your business logic.
LocalDate due = myJavaSqlDate.toLocalDate();
Avoid old date-time classes
Avoid the old date-time classes bundled with the earliest versions of Java such as java.util.Date/.Calendar. They are confusing, poorly designed, and troublesome.
java.time
In Java 8 and later, the old date-time class have been supplanted by the java.time framework. These new classes are a vast improvement. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
Date-only Value
The code in the Question suggests that you want to work with date-only values such as java.sql.Date pretends to be. Yet you mix it with java.util.Calendar which represents a date and a time-of-day.
Above in this Answer you can the java.time.LocalDate class. This class represents a date-only value without time-of-day nor time zone.
Time Zone
Time zone is crucial when dealing with date-only values. A date-only (without time-of-day) is inherently ambiguous. The date is not the same around the world at any given moment. A new day dawns earlier in the east. Minutes after midnight in Paris is still “yesterday” in Montréal.
So to determine “today” requires a time zone. If not specified, your JVM’s current default time zone is implicitly applied. Not good. Results may vary at runtime depending on settings of the host operating system and of the JVM. The default time zone can even be changed during runtime by any code in any thread of any app within the JVM.
So, better to specify the desired/expected time zone explicitly.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
Now compare to see if the due date has passed.
if( today.isAfter( due ) ) {
// Overdue.
}
Another way is to compare yyyy, mm, dd fields. If they are the same - dont use .after() nor .before()
Simon Franz

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());

Require help for SWT DateTime in Java

I retrieve a Date from the database using the ResultSet rsExpid.
Date joindate = rsExpid.getDate("join_date_ad");
System.out.println(joindate);
int year = joindate.getYear();
System.out.println(year);
int month =joindate.getMonth();
System.out.println(month);
int day = joindate.getDay();
System.out.println(day);
dateTimeJoin4.setDate(year, month, day);
When I print joindate to the console it shows correctly as 2011-08-03, but when I print the year to the console I was amazed to see 111. Similarly printing the month produced 7 and the day resulted in 3.
The variable dateTimeJoin4 is my SWT DateTime. It is not setting any value and it is also not giving any error message. Could please anybody help me on this?
Chances are you haven't read the documentation for Date.getYear and Date.getMonth:
Returns a value that is the result of subtracting 1900 from the year that contains or begins with the instant in time represented by this Date object, as interpreted in the local time zone.
and
Returns a number representing the month that contains or begins with the instant in time represented by this Date object. The value returned is between 0 and 11, with the value 0 representing January.
respectively. Likewise Date.getDay returns the day of the week, not the day of the month - you want Date.getDate() for that (or preferrably a different API entirely, either Calendar or Joda Time).
This has nothing to do with SWT's DateTime type - after all, you only use that in the last line. When something behaves unusually, your first port of call should be the documentation. SWT's DateTime.setDate method is documented to require a year between 1752 and 9999, so 111 will be confusing it. Admittedly it would have been nice if it had thrown an exception, but even so...
The fact that you're calling deprecated methods should have been a hint to you, although Calendar also uses 0-11 for its months.
Personally I would strongly encourage you to use Joda Time for as much of your date and time work as you can. It's a far superior date and time API to the one built into Java. It's not immediately clear whether it's worth you using it here (if this is all you have to do) but if you're doing anything at all significant (including parsing, formatting or any kind of arithmetic) you should be using it.
I tried using this method and it worked correctly so this method can be useful to other.
Calendar startCal = Calendar.getInstance();
startCal.setTime(joindate);
int months= startCal.get(Calendar.MONTH);
int years= startCal.get(Calendar.YEAR);
int days= startCal.get(Calendar.DAY_OF_MONTH);
System.out.println(months+1);
System.out.println(years);
System.out.println(days);
dateTimeJoin4.setDate(years, months+1, days);
getDay() return the position of the day not the date like suppose today is Monday it will return 1, it start from the sunday with 0 value.
as well as the getMonth() return the position as starting value is 0 for january at now you getting the 7 instead of 8.
for getting date you can use the SimpleDateFormat or DateFormat by passing the format string in that you can get it
example links
http://www.roseindia.net/java/javadate/date-format.shtml
http://www.java-examples.com/java-simpledateformat-class-example

Categories