Get the same day from this year - java

I need get the same day in this year.
Example: Now is 2019 year and the variable contains value 15 July 2022, so I need to get 15 July 2019 then. It works for all dates except February when it has an extra day in one year and doesn't have this day in this year, example: 29 February 2020 will return me the next day: 1 March 2019, but I need in this case to return the previous day: 28 February 2019. How I can adjust my logic so that it will work in this way?
public static java.util.Date getThisDateInThisYear(java.util.Date date) {
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
Date today = new Date();
GregorianCalendar gcToday = new GregorianCalendar();
gcToday.setTime(today);
gc.set(GregorianCalendar.YEAR, gcToday.get(GregorianCalendar.YEAR));
return gc.getTime();
}

first calc the difference of years and add the result to date
public Date getThisDateInThisYear(Date date) {
Calendar c = Calendar.getInstance();
int thisYear = c.get(Calendar.YEAR)
c.setTime(date);
int diff = thisYear - c.get(Calendar.YEAR);
c.add(Calendar.YEAR, diff);
return c.getTime();
}
I tested with 2016-02-29 and 2020-02-29, and both return 2019-02-28.

tl;dr
Use modern java.time classes. Never use Date/Calendar.
29 February 2020 will return me next day: 1st March 2019
LocalDate // Represent a date-only value, without time-of-day and without time zone.
.of( 2020 , Month.FEBRUARY , 29 ) // Specify a date. Here, Leap Day of 2020. Returns a `LocalDate` object.
.minusYears( 1 ) // Intelligently move backwards in time one year. Returns another `LocalDate` object, per immutable objects pattern.
.toString() // Generate text representing the value of this date, in standard ISO 8601 format of YYYY-MM-DD.
When run at IdeOne.com:
2019-02-28
Avoid legacy date-time classes
You are using terrible date-time classes that are now legacy, supplanted entirely by the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 2020 , 2 , 29 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety. Ditto for Year & YearMonth.
LocalDate ld = LocalDate.of( 2020 , Month.FEBRUARY , 29 ) ;
Date-time math
You can do date-time math in a few ways with *java.time. One way is by calling plus or minus and passing a Period or Duration. Another way is calling the convenience methods such as plusYears or minusYears.
The LocalDate class seems to give just the behavior you want with these methods.
To be clear:
2020 is a Leap Year. So 2020-02-29 is a valid date.
2018, 2019, and 2021 are not. The 29th is not a valid date in these years.
See the examples below run live at IdeOne.com.
From leap year
Let's start on Leap Day, the 29th, then add a year and subtract a year. We expect to see 28th on both.
LocalDate leapDay2020 = LocalDate.of( 2020 , Month.FEBRUARY , 29 );
LocalDate yearBeforeLeap = leapDay2020.minusYears( 1 );
LocalDate yearAfterLeap = leapDay2020.plusYears( 1 );
System.out.println( "leapDay2020.toString(): " + leapDay2020 );
System.out.println( "yearBeforeLeap.toString(): " + yearBeforeLeap );
System.out.println( "yearAfterLeap.toString(): " + yearAfterLeap );
Indeed that is what we get.
leapDay2020.toString(): 2020-02-29
yearBeforeLeap.toString(): 2019-02-28
yearAfterLeap.toString(): 2021-02-28
From non-Leap Year
Now let's start in a non-Leap Year on the 28th of February, then add & subtract a year. We expect to see 28th in all three. The 29th in the Leap year of 2020 is ignored.
LocalDate nonLeap2019 = LocalDate.of( 2019 , Month.FEBRUARY , 28 );
LocalDate yearBeforeNonLeapIntoNonLeap = nonLeap2019.minusYears( 1 );
LocalDate yearBeforeNonLeapIntoLeap = nonLeap2019.plusYears( 1 );
System.out.println( "nonLeap2019.toString(): " + nonLeap2019 );
System.out.println( "yearBeforeNonLeapIntoNonLeap.toString(): " + yearBeforeNonLeapIntoNonLeap );
System.out.println( "yearBeforeNonLeapIntoLeap.toString(): " + yearBeforeNonLeapIntoLeap );
nonLeap2019.toString(): 2019-02-28
yearBeforeNonLeapIntoNonLeap.toString(): 2018-02-28
yearBeforeNonLeapIntoLeap.toString(): 2020-02-28
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Also you can check if year is leap year based on that you can subtract the date
public static boolean isLeapYear(int year) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
}

I don't see any problem with java.util.Calendar. In JDK 1.8 this Java class got a major rework. So the following example code works fine:
SimpleDateFormat sf = new SimpleDateFormat("dd MMM yyyy");
Date date=sf.parse("29 Feb 2020");
System.out.println("date="+date);
Calendar calendar=Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.YEAR, -1);
System.out.println("date="+calendar.getTime());
calendar.add(Calendar.YEAR, 1);
System.out.println("date="+calendar.getTime());
It gives the same result as Basil Bourque wants it to have:
date=Sat Feb 29 00:00:00 CET 2020
date=Thu Feb 28 00:00:00 CET 2019
date=Fri Feb 28 00:00:00 CET 2020
Basically the Java class now uses the same ZoneInfo etc.. classes as the new classes also do.

Related

Date.toString() adds an hour around epoch in London

How can I get Date.toString() to produce an output that SimpleDateFormat can parse correctly for Dates around 1 Jan 1970 (I assume this applies to winter of 1968 and 1969 as well)
If I run the following,
System.out.println(TimeZone.getDefault());
Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Date date2 = sdf.parse(date.toString());
System.out.println("date: " + date);
System.out.println("date2: " + date2);
Date date3 = sdf.parse(date2.toString());
System.out.println("date3: " + date3);
This prints
sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
date: Thu Jan 01 01:00:00 GMT 1970
date2: Thu Jan 01 02:00:00 GMT 1970
date3: Thu Jan 01 03:00:00 GMT 1970
The problem is that London was in BST on 1 Jan 1970. So the correct date should be either
date: Thu Jan 01 01:00:00 BST 1970
or
date: Thu Jan 01 00:00:00 GMT 1970
but it seems a confusion of the two.
And while I would love to not support java.util.Date, it's not an option for me.
tl;dr
Your input is invalid as BST (British Summer Time) was not in effect during the winter.
BST cannot be reliably parsed, as it is a non-standard non-unique pseudo-zone.
There is no need to mess around with SimpleDateFormat. Let the modern java.time classes do the heavy lifting.
And while I would love to not support java.util.Date, it's not an option for me.
At the edges of your code, convert to-from the legacy and modern classes.
// Convert from legacy to modern.
Instant instant = myJavaUtilDate.toInstant() ;
// Convert from modern to legacy.
java.util.Date myJavaUtilDate = Date.from( instant ) ;
No BST in winter
Apparently the “B” in your BST is meant to be British. But BST in that context means British Summer Time. This means Daylight Saving Time (DST) which is engaged in the summer time, not the winter. So your input string of a January date combined with BST is nonsensical.
Double-Summertime
There is a further complication to your example of a moment in 1970 with a British time zone.
The practice of DST in Britain using an offset of one hour ahead of UTC (+01:00) in summer, and an offset of zero (+00:00) in the winter for Standard Time is current practice. That has not always been the case.
Back in 1970, Britain was trialling a “double-summertime”. In that experiment of 1968-1971, winter time was one hour ahead of UTC rather than zero, and summer time was two hours ahead of UTC instead of the one hour used nowadays. This put British time more in common with continental Europe and was hoped to reduce accidents.
So if we adjust a moment in January of 1970, we expect to jump to one hour ahead for time zone Europe/London. Whereas a moment in January of 2019, we expect no jump, the time-of-day in Britain will be the same as UTC (an offset-from-UTC of zero hours-minutes-seconds).
Avoid pseudo-zones
Avoid these 2-4 character pseudo-zones such as BST. They are not standardized. They are not even unique! So BST can be interpreted to be the time zone Pacific/Bougainville just as well as British Summer Time.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as BST or EST or IST as they are not true time zones, not standardized, and not even unique(!).
Convert
You can convert between the legacy and modern date-time classes easily. New conversion methods have been added to the old classes. Look for from, to, and valueOf methods, per the naming conventions.
java.util.Date ⇄ java.time.Instant
java.util.GregorianCalendar ⇄ java.time.ZonedDateTime
java.sql.Date ⇄ java.time.LocalDate
java.sql.Timestamp ⇄ java.time.Instant
Converting
Your input string of 00:00 on January 1, 1970 happens to be the epoch reference date used by both the legacy and modern date-time classes. We have a constant for that value.
Instant epoch = Instant.EPOCH ;
instant.toString(): 1970-01-01T00:00:00Z
See that same moment through your time zone of Europe/London.
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = epoch.atZone( z ) ;
zdt.toString(): 1970-01-01T01:00+01:00[Europe/London]
Notice that above-mentioned Double-Summertime experiment in effect then. If we try the same code for 2019, we get an offset-from-UTC of zero.
ZonedDateTime zdt2019 =
Instant
.parse( "2019-01-01T00:00Z" )
.atZone( ZoneId.of( "Europe/London" ) )
;
zdt2019.toString(): 2019-01-01T00:00Z[Europe/London]
To convert to a java.util.Date, we need an java.time.Instant object. An Instant represents a moment in UTC. We can extract an Instant from our ZonedDateTime object, effectively adjusting from a zone to UTC. Same moment, different wall-clock time.
Instant instant = zdt.toInstant():
We should now be back where we started, at the epoch reference date of 1970-01-01T00:00:00Z.
instant.toString(): 1970-01-01T00:00:00Z
To get the java.util.Date object you may need to interoperate with old code not yet updated to java.time classes, use the new Date.from method added to the old class.
java.util.Date d = Date.from( instant ) ; // Same moment, but with possible data-loss as nanoseconds are truncated to milliseconds.
d.toString(): Thu Jan 01 00:00:00 GMT 1970
By the way, be aware of possible data-loss when converting from Instant to Date. The modern classes have a resolution of nanoseconds while the legacy classes use milliseconds. So part of your fractional second may be truncated.
See all the code above run live at IdeOne.com.
To convert the other direction, use the Date::toInstant method.
Instant instant = d.toInstant() ;
ISO 8601
Avoid using text in custom formats for exchanging date-time values. When serializing date-time values as human-readable text, use only the standard ISO 8601 formats. The java.time classes use these formats by default.
Those strings you were experimenting with parsing are a terrible format and should never be used for data-exchange.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I may cite https://bugs.openjdk.java.net/browse/JDK-6609362?jql=text%20~%20%22epoch%20gmt%22:
Please use Z to format and parse historical time zone offset changes
to avoid confusions with historical time zone name changes.
public class Test {
public static void main(String[] args) throws ParseException {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
SimpleDateFormat f = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
Date d = new Date(0);
for (int i = 0; i < 10; i++) {
String s = f.format(d);
System.out.println(s);
d = f.parse(s);
}
} } ```
This is why I hate the Date Library.
As implied, BST should be used during the summer, and the calendar defines it as such.
sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
Except, for, TIL of The adventures of year-round British Summer Time!
A further inquiry during 1966–67 led the government of Harold Wilson to introduce the British Standard Time experiment, with Britain remaining on GMT+1 throughout the year. This took place between 27 October 1968 and 31 October 1971, when there was a reversion to the previous arrangement.
If you test dates around this period you will find the dates drifting off by an hour each parse, up to the switchover points.
The time code for Europe/London is GMT, with daylight savings using BST.
The toString method of Date "normalizes" the output by removing daylight savings time to pick what time zone to print. The options are GMT and BST. The Europe/London time of 01:00:00 printed as 01:00:00 GMT even though it is operating on GMT+1 time. So in other words, date.toString()does not work properly for this swath of time around the epoch because it uses GMT as a time zone for a time zone that is ostensibly not GMT/CET. The time itself is correct, but not the time zone.
The "simplest" solution I can come up with is relatively nasty from a sanity checkpoint, but can probably be made more elegant.
private static final Date experimentEnd = new Date(1971-1900, 11-1, 11);
private static final Date experimentStart = (new Date(1968-1900, 10-1, 26));
private static boolean bstExperimentTime(Date date) {
return date.after(experimentStart) && date.before(experimentEnd);
}
public static String forDateParsing(Date date) {
if(bstExperimentTime(date))
return date.toString().replace("GMT", "CET");
return date.toString();
}
public static String forDatePrinting(Date date) {
if(bstExperimentTime(date))
return date.toString().replace("GMT", "BST");
return date.toString();
}
Any date you need to parse with default "Europe/London" time zone needs to be passed through the parse formatter to convert GMT -> CET, which is the correct GMT+1.
Any date you need to print with default "Europe/London" time zone needs to be passed through the parse formatter to convert GMT -> BST, which is the correct display.

Java 8 LocalDate- determining the year of a yearless Feb-29 date?

My colleague and I have an interesting problem. We work with an old system that only returns date data in the format ddMMM. If the day/month is in the past for the current year, then we are to assume this date applies to next year. Otherwise it applies to the current year.
So today is 4/30/2015. If the system returned records with 12MAR, then that date translates to 3/12/2016. If the date reads 07MAY, then it translates to 5/7/2015.
However, it is unclear how to determine the year for 29FEB since it is a leap year. We cannot instantiate it with a year without the possibility of it throwing an error. We relied on a try/catch when trying to create a LocalDate off it for the current year. If it catches, we assume it belongs to next year.
Is there a more kosher way to do this?
Parse the value as a MonthDay, as that's what you've got.
If the month-day is not February 29th, just handle it as normal
If it is February 29th, you need to special-case it:
Determine whether the current year is a leap year with Year.isLeap(long)
If it is:
If it's currently on or before Feb 29th, then the result is Feb 29th of this year
If it's currently after Feb 29th, you need rules to apply - you could choose March 1st of next year or Feb 28th of next year
If it's not (a leap year this year)
If it's currently on or before Feb 28th, again you need to rules to apply, probably returning March 1st or Feb 28th of this year
If it's currently after Feb 28th, then the date logically belongs to next year...
If next year is a leap year, the result is presumably Feb 29th of next year
If next year is not a leap year, again you need a rule
That's hopefully outlined the three "odd" conditions you need to account for - we don't have enough information to tell you what to do in those conditions.
java.time
The modern way is with the java.time classes. Specifically, MonthDay in your case.
Note that you should always specify a Locale to determine the human language to use in translation of name of month.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "ddMMM" , Locale.ENGLISH );
String input = "29FEB";
MonthDay md = MonthDay.parse( input , f );
You can apply this to a year to get a LocalDate object, a date-only value of year-month-day.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
If we are looking at February 29, check for Leap Year. If this is not a Leap Year, then you said you want to move to next year. But what if next year is also not a Leap Year? You need to keep going until you reach a Leap Year.
int yearNumber today.getYear();
LocalDate ld = null;
if( md.equals( MonthDay.of( 2 , 29 ) && ( ! Year.of( today ).isLeap() ) ) {
// If asking for February 29, and this is not a leap year, move to next year, per our business rule.
… keep adding years until you find a year that *is* a leap year.
ld = md.atYear( yearNumber + x );
} else {
ld = md.atYear( yearNumber );
}
Fall back to 28th
This Question had a special business rule about jumping to the following year if the month-day is February 29 in a non-Leap Year. But for other folks be aware the default behavior in java.time is to simply fall back to February 28 when asking for the 29th a non-Leap Year. No exception is thrown.
LocalDate february28 =
MonthDay.of( 2 , 29 )
.atYear( myNonLeapYearNumber ); // 29th becomes 28th.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

get month of year from Calendar class of java

I wrote simple java program in which I get day of month, days in month and month
see below code :
//Calendar calendar = Calendar.getInstance();
Calendar calendar = new GregorianCalendar();
log.info("day of month: "+calendar.get(Calendar.DAY_OF_MONTH));
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
log.info("days in month: "+calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
log.info("month: "+calendar.get(Calendar.MONTH));
Running above code I get this output:
day of month: 7
days in month: 31
month: 2
But when I put below statement
log.info("month: "+calendar.get(Calendar.MONTH));
before
log.info("day of month: "+calendar.get(Calendar.DAY_OF_MONTH));
I get this output: (which is what I want)
day of month: 7
days in month: 31
month: 5
Can any body help me understand why I get month: 2 ?
Youre setting the Calendar field to Calendar.MONTH (value 2) here
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
^
You can do this
calendar.set(2014, Calendar.JUNE, 1);
although the Month 5 is June (since month field starts from 0 for Calendar) which only has 30 days
Look at the source code of Calendar.java of JDK.
public final static int MONTH = 2;
Here, Calendar.MONTH = 2, Calendar.YEAR=1 and Calendar.DAY_OF_MONTH = 5. You set these constant value to calender using set method like.
calendar.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH);
| | |
1 2 5
tl;dr
LocalDate.now()
.getDayOfMonth()
…and…
YearMonth.from(
LocalDate.now()
).lengthOfMonth() // .getMonthValue() .getYear()
java.time
The modern approach uses the industry-leading java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Parts
Interrogate for the parts as needed.
int dayOfMonth = ld.getDayOfMonth() ;
int month = ld.getMonthValue() ;
int year = ld.getYear() ;
YearMonth
To work with the month as a whole, use YearMonth class.
YearMonth ym = YearMonth.from( ld ) ;
Ask for length of month.
int lengthOfMonth = ym.lengthOfMonth() ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Calendar Class problems

I am having problems with the Calendar Class.
Calendar cal = Calendar.getInstance ();
int iYear = cal.get (Calendar.YEAR); // get the current year
int iMonth = cal.get (Calendar.MONTH); // month...
int iDay = cal.get (Calendar.); // current day in the month
This... No Workie!! :-(
I used the debugger and found that the YEAR and the DAY_OF_MONTH are correct,
however, the MONTH is 1 (January) when it SHOULD BE 2 (February).
Here is where it gets even more WEIRD:
I then tried cal.clear ();
followed by cal.set (2014, 2, 27); // Today's Date - Feb 27, 2014
and the month was still 1 (i.e. January)
I set the date to days in January, (2014, 1, 1), (2014, 1, 16),etc
It correctly gave me a 1 for the month
After reading and trying many things (and pulling my hair out..)
I set it to a date in the future, my Birthday (2014, 5, 23) and other days.
For those dates, Month was correctly set to 5 (May)
Month in Calendar begins at 0, which means 0 is January, 1 is February, etc.
Java Date and Time API sucks. Use Joda-Time instead.
use constants in Calendar for month: Calendar.JANUARY etc
For example:
cal.set(2014, Calendar.FEBRUARY, 27);
Please see the description provided for MONTH Constant in Calendar Class.
Calendar.MONTH
public static final int MONTH
Field number for get and set indicating the month. This is a calendar-specific value. The first month of the year in the Gregorian and Julian calendars is JANUARY which is 0; the last depends on the number of months in a year.
So if you want to set the date in calendar than use below code snippet.
cal.set(2014, Calendar.FEBRUARY, 28);
I think it will help you.
tl;dr
LocalDate.now()
.getYear()
java.time
The modern approach uses the industry-leading java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Parts
Interrogate for the parts as needed.
int dayOfMonth = ld.getDayOfMonth() ;
int month = ld.getMonthValue() ;
int year = ld.getYear() ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Let try this simple program:
import java.util.Calendar;
class CalendarExample {
public static void main(String args[]) {
Calendar calendar = Calendar.getInstance();
System.out.println("Current Date : " + calendar.get(Calendar.DATE));
System.out.println("Current Month : " + calendar.get(Calendar.MONTH));
System.out.println("Current Year : " + calendar.get(Calendar.YEAR));
System.out.print("Current Time : ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
System.out.print(calendar.get(Calendar.SECOND));
}
}
You get the o/p:
Current Date : 28
Current Month : 1
Current Year : 2014
Current Time : 11:18:3
In Calender class Jan as constant int is 0 , Feb is 1 ... .month constant int value is from 0,1,2..

Java - GregorianCalendar

I'm using the GregorianCalendar in Java, and I am wondering how I can use this to check whether or not a date is valid (E.g.: to check if Feb 29th is only in leap year, to check if the date is no sooner than the current data, etc).
I have created a GregorianCalendar object and passed it the values of the data I would like to check as follows:
GregorianCalendar cal1 = new GregorianCalendar(day,month,year);
If the date is valid, I'd like to return true. How could I do this?
Basic Idea: if you try to set the invalid date to Calendar instance, it would make it correct one,
For example if you set 45 as date it would not be the same once you set and retrieve
public boolean isValid(int d, int m, int y){
//since month is 0 based
m--;
//initilizes the calendar instance, by default the current date
Calendar cal = Calendar.getInstance();
//resetting the date to the one passed
cal.set(Calendar.YEAR, y);
cal.set(Calendar.MONTH, m);
cal.set(Calendar.DATE, d);
//now check if it is the same as we set then its valid, not otherwise
if(cal.get(Calendar.DATE)==d &&cal.get(Calendar.MONTH) ==m && cal.get(Calendar.YEAR) ==y){
return true;
}
//changed so not valid
return false;
}
Check that after creation, the day, month and year is still the same as the original values you passed. If the original values are incorrect, the date will get adjusted accordingly. E.g.. if you pass (29, 1, 2011) - note that the month value is 0-based so 1 is for February -, you will get back (1, 3, 2011).
tl;dr
java.time.LocalDate.of( 2018 , 2 , 31 )
➙ catch DateTimeException for invalid day-of-month number.
java.time
The GregorianCalendar class has been supplanted by the ZonedDateTime class as part of java.time built into Java 8 and later. A new method has been added to the old class for conversion.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
You want a date-only value, so use LocalDate, without time-of-day and without time zone.
You can extract a LocalDate from a ZonedDateTime time.
LocalDate ld = zdt.toLocalDate() ;
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Valid value
to check if Feb 29th is only in leap year
The documentation for `LocalDate.of( year , month , day ) says:
The day must be valid for the year and month, otherwise an exception will be thrown.
So catch the DateTimeException.
try {
LocalDate ld = LocalDate.of( 2018 , 2 , 31 ) ; // Invalid, February never has 31 days.
return Boolean.TRUE ;
} catch ( DateTimeException e ) {
return Boolean.FALSE ;
}
Leap Year
Yes, LocalDate checks for Leap Year to handle February 29 correctly.
try {
LocalDate ld = LocalDate.of( 2018 , 2 , 29 ) ; // Invalid, as 2018 is a common year.
return Boolean.TRUE ;
} catch ( DateTimeException e ) {
return Boolean.FALSE ;
}
false
…
LocalDate ld = LocalDate.of( 2020 , 2 , 29 ) ; // Valid, as 2020 is a leap year.
…
true
Compare dates
to check if the date is no sooner than the current data
I assume you meant "current date".
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Compare with isBefore, isAfter, and isEqual.
boolean b = ld.isBefore( today ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Categories

Resources