Proper Russian month string translation Java
Asked Answered
I

6

20

I want to convert a Date in to Russian and using the code below

SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,locale).format(date);

where locale is of type Locale The problem is months are not parsed correctly . January is coming as "январь" it should be "января" and February is coming as "февраль" should be "февраля"

and so on...

One idea is to convert incorrect months to proper ones in my logic

Is there any thing by which Java do this automatically ?

Thanks

Incorruptible answered 29/10, 2014 at 23:55 Comment(0)
S
38

On my JDK-6-installation I can reproduce your problem:

Date jud = new SimpleDateFormat("yyyy-MM-dd").parse("2014-02-28");
String month =
    DateFormat.getDateInstance(SimpleDateFormat.LONG, new Locale("ru")).format(jud);
System.out.println(month); // output: 28 Февраль 2014 г.

Java-8 offers you a solution.

It seems that the JDK has changed the internal default from "standalone-style" (nominative) to "format-style" (genitive).

String date =
  DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
  .withLocale(new Locale("ru"))
  .format(LocalDate.of(2014, 2, 28));
System.out.println(date); // output: 28 февраля 2014 г.

If you need to apply standalone textstyle then you have to set up your own DateTimeFormatterBuilder which requires a little bit more effort, else TextStyle.FULL should be the default.

String m = Month.FEBRUARY.getDisplayName(TextStyle.FULL , new Locale("ru")); 
// февраля (first and last char are different)

String s = Month.FEBRUARY.getDisplayName(TextStyle.FULL_STANDALONE , new Locale("ru")); 
// Февраль (this style can be used in DateTimeFormatterBuilder for the month field, too)

Workaround for Java-pre-8 using old style:

Define your own text resources (troublesome)!

Locale russian = new Locale("ru");
String[] newMonths = {
  "января", "февраля", "марта", "апреля", "мая", "июня", 
  "июля", "августа", "сентября", "октября", "ноября", "декабря"};
DateFormatSymbols dfs = DateFormatSymbols.getInstance(russian);
dfs.setMonths(newMonths);
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, russian);
SimpleDateFormat sdf = (SimpleDateFormat) df;
sdf.setDateFormatSymbols(dfs);

Date jud = new SimpleDateFormat("yyyy-MM-dd").parse("2014-02-28");
String month = sdf.format(jud);
System.out.println(month); // output: 28 февраля 2014 г.

Joda-Time does not offer a good solution in a Java-pre-8 environment because it only delegates to JDK. See also a similar issue on Joda-site.

Finally there is also my library Time4J which can solve the problem like Java-8, but uses its own text resources for Russian and understands both forms (old style and standalone-style), so this is a simple solution for older Java-versions (and will of course not be obsoleted by Java-8 due to many other feature enhancements).

System.out.println(
    ChronoFormatter.ofDateStyle(DisplayMode.FULL, new Locale("ru")).format(
        PlainDate.of(2014, Month.FEBRUARY, 28)
    )
); // output: 28 февраля 2014 г.
Solubilize answered 30/10, 2014 at 8:9 Comment(0)
K
26

For Java 8 you can use a new pattern.

In short: The "LLLL" pattern will get a Nominative case:

new SimpleDateFormat("LLLL", Locale.getDefault()).format(date); // январь

The "MMMM" pattern will return a String in Genitive case:

new SimpleDateFormat("MMMM", Locale.getDefault()).format(date); // января

Alternatively, instead of hardcoding Russian months in array (since we have Polish, Ukrainian and other languages), you could use the java.time.Month enum. It contains both months int number and String name.

Kinetic answered 4/8, 2017 at 14:26 Comment(0)
G
5

While an accepted answer of @Meno Hochschild and https://mcmap.net/q/661712/-how-to-format-the-spanish-month-in-sentence-case-using-simpledateformat are correct, I want to add a little.

It's enough to set Locale("ru"), then create and apply sdf.format(date).

public static String formatDate(long date, String format) {
    Locale locale = new Locale("ru");
    SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
    return sdf.format(date);
}

But if you want to customize it, I will show a process.

After many exceptions I realized that weekdays start not from Monday (see http://jexp.ru/index.php/Java_Tutorial/Data_Type/Date_Format#Change_date_formatting_symbols)!

public static String formatDate(long date, String format) {
    //Locale locale = new Locale("fr");
    Locale locale = new Locale("ru");
    DateFormatSymbols dfs = DateFormatSymbols.getInstance(locale);
    String[] months = {
            "января", "февраля", "марта", "апреля", "мая", "июня",
            "июля", "августа", "сентября", "октября", "ноября", "декабря"};
    String[] shortMonths = {
            "янв", "фев", "мар", "апр", "май", "июн",
            "июл", "авг", "сен", "окт", "ноя", "дек"};
    dfs.setMonths(months);
    dfs.setShortMonths(shortMonths);
    String[] weekdays = {"", "Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"};
    String[] shortWeekdays = {"", "вс", "пн", "вт", "ср", "чт", "пт", "сб"};
    dfs.setWeekdays(weekdays);
    dfs.setShortWeekdays(shortWeekdays);

    SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
    sdf.setDateFormatSymbols(dfs);
    return sdf.format(date); // пт, 09 декабря 2016
}
Genisia answered 7/12, 2016 at 12:9 Comment(1)
The DateFormatSymbols is exactly what I wanted. Thank you so much, my friend. You saved my dayApathetic
R
2

In my task, I shoud only get a month from integer, so this code works perfectly for me:

int month=5;//for example
Month.of(month).getDisplayName(TextStyle.FULL_STANDALONE, new Locale("ru"));
Repairer answered 28/12, 2020 at 12:22 Comment(0)
G
1

AFAIK, there's no support for localisation in accusative case in the JDK. I would suggest to use the MEDIUM date format to work around that if it's suitable: 15 Фев 1999

Failing that you may end up having to provide your own localisations for month names.

Gelsenkirchen answered 30/10, 2014 at 0:34 Comment(6)
Choosing just the abbreviated form cannot solve the problem if the first char of russian label for February is slightly different for both cases.Solubilize
It's not the first character, it's the last. Russian would've been a completely crazy mad language if inflections changed the first letter! :-)Gelsenkirchen
Please take a close look again at the characters. The first char is different (codepoint 1092 vs. 1060 according to my analysis) although looking very similar on first glance. I believe it is about capitalization, but not quite sure (russian is not my language). And the last char is different due to inflection. Here we both agree.Solubilize
Russian happens to be my native language and I can confirm that 'Ф' is capitalised 'ф' :-)Gelsenkirchen
Thanks for your information. I am not sure how important the capitalization in russian language is, so maybe choosing the abbreviated russian form is tolerable either capitalized or not (if OP wants at all abbreviations).Solubilize
Russian capitalization is the same as in English, i.e. not very semantically important, unlike for example in German.Gelsenkirchen
I
0

Sorry if my answer would not fully fit the question, but still' I'd like to share my way of solving the issue with translating the Date into Russian format.

Had big headache with dealing with DateTime Locales and so on, I started to simply translate Weekdays and Months in String representation of original DateTime.

String originalDate = "Tue, 22 Nov 2016 01:03:00 +0300";
Log.d("Date in Russian",convertStringDateToRussian(linkText));

public String convertStringDateToRussian(String mDate) {

    String[] engWeek = {
            "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
            "Sun"};
    String[] ruWeek = {
            "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота",
            "Воскресенье"};
    String[] engMonths = {
            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    String[] ruMonths = {
            "января", "февраля", "марта", "апреля", "мая", "июня",
            "июля", "августа", "сентября", "октября", "ноября", "декабря"};
    for (
            int t = 0;
            t < engWeek.length; t++)

    {
        if (mDate.contains(engWeek[t])) {
            mDate = mDate.replace(engWeek[t], ruWeek[t]);
            break;
        }
    }

    for (
            int t = 0;
            t < engMonths.length; t++)

    {
        if (mDate.contains(engMonths[t])) {
            mDate = mDate.replace(engMonths[t], ruMonths[t]);
            break;
        }
    }

    return mDate;
}
Illogical answered 22/11, 2016 at 9:6 Comment(3)
Thanks, you chose a way of translation from English to Russian. It is a different method, however it can be used. But probably an accepted language (Java-8 and Java-pre-8 variants) would work. Also don't forget to lower case of names: not "Февраля", but "февраля".Genisia
Thanks for your reply. This solution could be more useful in Android, where I could not foun "RU" locale for DateTime at all.Illogical
If you wish to use Android, I added a solution for it in this topic.Genisia

© 2022 - 2024 — McMap. All rights reserved.