How to convert two digit year to full year using Java 8 time API
- Debmalya Biswas
- 2018-06-06 12:01
- 5
I wish to remove the Joda-Time library from my project.
I am trying to convert a two digit year to full year. The following code from Joda-Time can fulfil the purpose. Below is the following code of joda-time
DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormat.forPattern("yy"); int year = LocalDate.parse("99"", TWO_YEAR_FORMATTER).getYear(); System.out.println(year);
Output: 1999
This is the output that I expect and that makes sense in my situation. However, when I try the same procedure with java.time API, it produces a DatetimeParseException. Below is the following code of java.time API:
DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormatter.ofPattern("yy"); int year = LocalDate.parse("99", TWO_YEAR_FORMATTER).getYear(); System.out.println(year);
Stacktrace:
Exception in thread "main" java.time.format.DateTimeParseException: Text '99' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {Year=2099},ISO of type java.time.format.Parsed at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017) at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952) at java.base/java.time.LocalDate.parse(LocalDate.java:428) at scratch.main(scratch.java:10) Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {Year=2099},ISO of type java.time.format.Parsed at java.base/java.time.LocalDate.from(LocalDate.java:396) at java.base/java.time.format.Parsed.query(Parsed.java:235) at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948) ... 2 more
I failed to see the reason of the stacktrace. It would be nice if someone could help me out to understand the following scenario and also explain how to convert a two digit year to full year using Java 8 time API.
5 Answers
You can't create a LocalDate
because the String
you give doesn't provide the information needed to fill all required fields.
You can create a Year
though
Year parsed = Year.parse("99", TWO_YEAR_FORMATTER); int year = parsed.getValue();
java datetimeformatter, java.time.format.DateTimeFormatter public final class DateTimeFormatter extends Object Formatter for printing and parsing date-time objects. This class provides the main application entry point for printing and parsing and provides common implementations of DateTimeFormatter : The main date-time classes provide two methods - one for formatting, format(DateTimeFormatter formatter) , and one for parsing, parse(CharSequence text,
daniu
2018-06-06 12:06
Why it didn’t work
java.time
doesn’t supply default values for month and day of month the way it seems that Joda-Time does. The message says that it cannot obtain a LocalDate
from a year alone, or conversely, it is missing month and day (you may supply your own default values, though, as demonstrated in Mikhail Kholodkov’s answer). Generally this behaviour is here to help us: it reminds us to supply all the values needed, and makes it clear from the code if any default values are used, and which.
What to do instead
Just use the Year
class of java.time
. First declare
public static final DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder() .appendValueReduced(ChronoField.YEAR, 2, 2, 1950) .toFormatter();
Then use
int year = Year.parse("99", TWO_YEAR_FORMATTER).getValue(); System.out.println(year);
Output
1999
Insert your desired base value where I put 1950 to specify a year within 99 years (inclusive) from that year. If you want the year to be in the past including this year, you may use:
private static final Year base = Year.now(ZoneId.of("Asia/Kolkata")).minusYears(99); public static final DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder() .appendValueReduced(ChronoField.YEAR, 2, 2, base.getValue()) .toFormatter();
BTW, don’t take my word for it, but I think Joda-Time uses current year minus 30 years as base or pivot. If this is so, using 30 instead of 99 in the last snippet will be the most compatible (so will also give you the 1999 you expected).
simpledateformat, SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text), parsing (text -> date), and normalization. SimpleDateFormat allows you to start by choosing any user-defined patterns for date SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text),
Ole V.V.
2018-06-06 16:06
You need to provide default values for DAY_OF_MONTH
and MONTH_OF_YEAR
DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder() .appendPattern("yy") .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter();
In addition,
Java-8 uses the range 2000-2099 per default, not like SimpleDateFormat the range -80 years until +20 years relative to today.
Full answer
Since you're parsing years only, in order to have '99' as '1999' your code should be like this:
DateTimeFormatter TWO_YEAR_FORMATTER = new DateTimeFormatterBuilder() .appendPattern("") .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2, LocalDate.now().minusYears(80)) .toFormatter();
localdate to date, So to convert the LocalDate to Date, we must append the time and timezone info with the date. Keeping this in mind, the steps for the conversion are as follows: 1. Getting the default time zone so we can append the timezone info with the date util.Date in Java 8. When we're converting an Instant object, it's required to use a ZoneId, because Instant objects are timezone-agnostic –
Mikhail Kholodkov
2018-06-06 12:27
You could parse the year directly using formatter.parse(input, Year::from)
:
import java.time.*; import java.time.format.*; class Main { public static void main(String[] args) { DateTimeFormatter TWO_YEAR_FORMATTER = DateTimeFormatter.ofPattern("yy"); Year year = TWO_YEAR_FORMATTER.parse("99", Year::from); System.out.println(year); } }
Note that this will output 2099
. To output 1999, you should use a specific formatter like the one suggested by Ole V.V. in their answer.
java 8 date comparison, Learn to compare two LocalDate instances to find out which date represents an older date in comparison to second date. LocalDate class is part of java.time package added in Java 8. 1. isAfter(), isBefore() and isEqual() methods. The recommended way to compare two localdate objects is using provided methods which compare both date objects and return a boolean value – true or false. In this tutorial, we'll focus on how to compare dates using the Java 8 Date/Time API. We'll dive into different methods to check whether two
Olivier Grégoire
2018-06-07 07:30
The problem is that you can't parse a year on its own into a LocalDate. A LocalDate needs more information than that.
You can use the
parse
method of the formatter, which will give you aTemporalAccessor
, and then get the year field from that:Addressing the discrepancy between the two: these are two distinct APIs. Yes, they are very similar, and the
java.time
package was informed by design decisions of JodaTime, but it was never intended to be a drop-in replacement for it.See this answer if you would like to change the pivot year (by default '99' will resolve to 2099 and not 1999).
How to convert two digit year to full year using Java 8 time API, The problem is that you can't parse a year on its own into a LocalDate. A LocalDate needs more information than that. You can use the parse The problem is that you can't parse a year on its own into a LocalDate. A LocalDate needs more information than that. You can use the parse
Michael
2018-06-06 12:46