Bug in Finnish date localization? - java

I'm trying to localize for Finland using this code:
Locale finLocale = new Locale("fi", "FI");
Date today = new Date(2017, 1, 1);
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG, finLocale);
String formattedDate = dateFormat.format(today);
System.out.println(formattedDate);
What I end up getting is "helmikuutata". I would expect "helmikuu" or "helmikuuta", but this just seems wrong.
Is this valid Finnish, or is there a bug in Java? My version is 1.8.0_31

Yes, this was a bug in JDK (See JDK-8074791), wherein an extra 'ta' was appended to the month name. This got fixed from JDK 8u60 version onwards. So, if you upgrade to latest JDK versions like JDK8u131, you will get the correct output.

I am convinced that the answer by Pallavi Sonal is correct. I have already upvoted it and you should probably accept it. I had wanted to keep the following a comment, but it deserves better formatting, so here goes.
java.time
Since you are using Java 8 (and even if you didn’t), you will prefer the modern more programmer friendly API of java.time:
LocalDate today = LocalDate.of(2017, Month.FEBRUARY, 1);
DateTimeFormatter dateFormat = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
.withLocale(finLocale);
String formattedDate = today.format(dateFormat);
On my Java 1.8.0_131 it gives the expected
1. helmikuuta 2017
If someone reading this is using Java 6 or 7, please consider getting the ThreeTen Backport library so you can use the modern date and time API as shown.

Related

java.time.format.DateTimeParseException when parsing year

jdk used : 1.8
Not sure what is the issue, configuredFormat is valid one, inputTime is also valid one, really confused what is the issue.
public class Test {
public static void main(String[] args) {
String configuredFormat = "yyyyMMddHHmmssSSS";
String inputTime = "20200203164553123";
DateTimeFormatter dt = DateTimeFormatter.ofPattern(configuredFormat);
DateTimeFormatter strictTimeFormatter = dt.withResolverStyle(ResolverStyle.STRICT);
try {
LocalTime.parse(inputTime, strictTimeFormatter);
System.out.println("success");
} catch (DateTimeParseException | NullPointerException e) {
e.printStackTrace();
}
}
}
Exception I am Getting :
java.time.format.DateTimeParseException: Text '20200203164553123' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalTime.parse(LocalTime.java:441)
at com.Test.main(Test.java:20)
Lucky for you, there is an exact bug report which uses the exact same pattern that you're trying. Who better to explain than the JDK maintainers?
JDK-8031085
Workaround
DateTimeFormatter dtf = new
DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND,3)
.toFormatter()
Adjacent value parsing is generally a hard problem. It is intended to
handle the case where the first element is variable width (the year)
and all other elements are fixed width (month, day etc). However, the
"S" pattern letter is a fraction, not a value. Specifically, the
fraction can be variable width - more or less than three digits are
possible options. Given the general case of a variable width year and
a variable width millisecond, it is not possible to determine which of
the two fields was intended to be variable.
Having said that, the implementation (and javadoc) have not ended up
as I intended. The description of "fraction" in DateTimeFormatter
describes actions in strict and lenient mode, but there is no way to
access strict or lenient mode when using
DateTimeFormatter.ofPattern(). This is a documentation bug that should
be fixed by removing the discussion of strict vs lenient.
Worse however is that the SSS pattern has therefore ended up using
strict mode when lenient mode would be appropriate. As it currently
stands, DateTimeFormatter.ofPattern("hhmmss.SSS") requires three
digits for milliseconds, when it was originally intended to require 0
to 9 (the lenient behaviour).
I tried changing the whole of the DateTimeFormatter.ofPattern() method
to use lenient parsing, and it broke no tests (which is bad in its own
way). This might be a valid fix, but only if included in JDK 8, as
once people adapt to the strict parsing it will be hard to make it
lenient.
Given that the current implementation requires three digits for SSS,
it is thus very surprising that adjacent value parsing does not apply.
Actually I agree format should be valid... this seems to be confirmed as I tried with both oracle java 8 and 9 runtime, and with java 9 it does not happen. (I tried IBM jre 8 too and it works as well)
System.out.println( System.getProperty( "java.vendor" )+" - "+System.getProperty( "java.version" ) );
String configuredFormat = "yyyyMMddHHmmssSSS";
String inputTime = "20200203164553123";
DateTimeFormatter dt = DateTimeFormatter.ofPattern(configuredFormat);
DateTimeFormatter strictTimeFormatter = dt.withResolverStyle(ResolverStyle.STRICT);
try {
//System.out.println( dt.parse( inputTime ) );
LocalTime.parse(inputTime, strictTimeFormatter);
System.out.println("success");
} catch (DateTimeParseException | NullPointerException e) {
e.printStackTrace();
}
Output
Oracle Corporation - 9.0.4
success
IBM Corporation - 1.8.0_211
success
Oracle Corporation - 1.8.0_172
java.time.format.DateTimeParseException: Text '20200203164553123' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(Unknown Source)
at java.time.format.DateTimeFormatter.parse(Unknown Source)
at java.time.LocalTime.parse(Unknown Source)
at test.Test2.main(Test2.java:19)

Java: Convert date 2011-Jan-01 to format of dd-MM-yyyy

I need to convert date (2011-Jan-01) to any of the simpledateformats.
The eclipse designer uses Java 7.
String pDate = obj.getJSONArray("product").getJSONObject(i).getString("createdDate");
//"2011-Jan-01" - date format.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
try {
Date fDate = format.parse(pDate);
System.out.println("jsonDate: " + fDate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("pDate: " + pDate);//"2011-Jan-01"
errors:
error:java.text.ParseException:Unparseable date:"2011-Jan-01"
error: at java.text.DateFormat.parse(DateFormat.java:348)
I'm getting errors above.
Your parsing format should not include the time (because your input is only the date), and you need another format call to produce your desired output. Something like,
String pDate = "2011-Jan-01";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd");
try {
Date fDate = format.parse(pDate);
System.out.println(new SimpleDateFormat("dd-MM-yyyy").format(fDate));
} catch (ParseException e) {
e.printStackTrace();
}
which outputs
01-01-2011
java.time and ThreeTen Backport
This works on Java 7 (details below):
DateTimeFormatter jsonDateFormatter = DateTimeFormatter.ofPattern("uuuu-MMM-dd", Locale.ENGLISH);
DateTimeFormatter outputDateFormatter = DateTimeFormatter.ofPattern("dd-MM-uuuu");
String pDate = "2011-Jan-01";
LocalDate fDate = LocalDate.parse(pDate, jsonDateFormatter);
pDate = fDate.format(outputDateFormatter);
System.out.println("Formatted date: " + pDate);
Output from the snippet is:
Formatted date: 01-01-2011
Unless you have strong reasons not to, I recommend that you use one of Java’s built-in formats for your user’s locale rather than hardcoding an output format. For example:
DateTimeFormatter outputDateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.UK);
Now the output is:
Formatted date: 01-Jan-2011
Question: Why java.time?
The old datetime classes that you tried to use in the question, Date and SimpleDateFormat are poorly designed, the latter notoriously troublesome. Fortunately they are also long outdated. java.time, the modern Java date and time API, is so much nicer to work with.
Question: Can I use java.time on Java 7? How?
Yes, java.time works nicely on Java 7. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Change SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss"); to SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd");

Calendar.set(..) not working on android 6.0

I need to set calendar to next week's monday. My code works on Android 9.0 but on Android 6.0 it works only while debugging.
Problem is with Calendar.set(..) functions, they just don't work. For example calendar.set(Calendar.WEEK_OF_YEAR, 17) won't change calendar week to 17, but when it is debugging it will change it to 17.
Here is my code:
Calendar mcurrentTime = Calendar.getInstance(Locale.GERMANY);
if(AppHelper.getInstance().getNextWeek() != 0){
mcurrentTime.set(Calendar.WEEK_OF_YEAR,
AppHelper.getInstance().getNextWeek());
mcurrentTime.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
}
weekNumberTv.setText(mcurrentTime.get(Calendar.WEEK_OF_YEAR)+"");
Android 9.0 weekNumberTv shows 17
Android 6.0 weekNumberTv shows 16
If start debugging mode
Android 6.0 weekNumberTv shows 17
To do time calculations in versions prior to 7.0 sadly you will have to use JavaTime package or its backport.
Implement ThreeTen Android Backport library:
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.0'
https://github.com/JakeWharton/ThreeTenABP
Then initialize it in onCreate method.
AndroidThreeTen.init(this)
Make sure that these libraries are included and not Java 8 ones.
import org.threeten.bp.LocalDate
import org.threeten.bp.temporal.ChronoUnit
import org.threeten.bp.temporal.WeekFields
import com.jakewharton.threetenabp.AndroidThreeTen
Code to finish work
var mCurrentTime = LocalDate.now()
val weekFields = WeekFields.of(Locale.GERMANY)
val currentDayOfWeek = mCurrentTime.get(weekFields.dayOfWeek())
//subtract day of week to monday
mCurrentTime=mCurrentTime.minus((currentDayOfWeek.toLong()-1),ChronoUnit.DAYS)
//add week starting from monday
mCurrentTime=mCurrentTime.plus(1,ChronoUnit.WEEKS)
//get weekOfYear
val weekOfCurrentTime=mCurrentTime.get(weekFields.weekOfYear())
show_week_in_year.text=weekOfCurrentTime.toString()
Sorry for Kotlin. Java is on vacation.

DateFormatSymbol's behavior is different between Android and JRE 1.7

I've made a jar for parsing a dateformat from text for JRE and Android.
Mostly It worked well. but when I try to parsing the following Chinese chars, It fails on Android and works on JRE. '五月' is May in Chinese.
"06 五月 2014"
I used the following code to parse it
String input = "06 五月 2014"
SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy", Locale.CHINESE);
Date date = df.parse(input);
So, i started narrowing down the problems and got the following test cases.
on Android,
DateFormatSymbols dfs = new DateFormatSymbols(Locale.CHINA);
String[] months = dfs.getMonths();// months[0] = 1月, months[1] = 2月 ...
String[] ampm = dfs.getAmPmStrings(); // ampm[0] = AM ampm[1] = PM
on JRE 1.7,
DateFormatSymbols dfs = new DateFormatSymbols(Locale.CHINA);
String[] months = dfs.getMonths();// months[0] = 一月, months[1] = 二月 ...
String[] ampm = dfs.getAmPmStrings(); // ampm[0] = 上午 ampm[1] = 下午
Why this happens? is this normal operation or am i missing something ?
Ignoring the difference between Java and Android, your code is not even guaranteed to work on different Java VMs. The API documentation does not cover a formal specification of the different date formatters and you are not guaranteed that the formatted output from one Java VM can be parsed by another Java VM.
In this case, the localization database in the Oracle VM uses "五月" as the Chinese word for the month of May (literary: "fifth moon"). Your Android localization database uses "5月" (literary: "5th moon"), which is just as correct, but different.

SimpleDateFormat different behaviour depending on java version

In the netty framework there is the following code:
final class CookieDateFormat extends SimpleDateFormat {
private static final long serialVersionUID = 1789486337887402640L;
CookieDateFormat() {
super("E, d-MMM-y HH:mm:ss z", Locale.ENGLISH);
setTimeZone(TimeZone.getTimeZone("GMT"));
}
}
The issue I am having is that the above's output varies depending on the version of the jvm when I run it.
on java 1.6 I get: Wed, 22-May-13 09:11:41 GM
on java 1.7 I get: Wed, 22-May-2013 09:11:14 GMT
Is there any way to change the behavior on java 1.6 to match the output of 1.7 without having to alter the code (since I would prefer not having to change code in netty).
Try to use d-MMM-yyyy instead of d-MMM-y. I hope that difference in seconds (41 vs 14) is your typing mistake. Otherwise I cannot explain this difference.

Categories

Resources