26

I have this.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String monthName = br.readLine();

How to get month number which contain in monthName variable? Thanks!

Dmitry
  • 321
  • 1
  • 3
  • 10
  • 1
    tokenize it. use split. can you plz add more info ? – Kick Buttowski Jun 22 '14 at 20:36
  • Do you mean that the only token on the line is the month name? In that case you should just use a switch/case control flow (if you're in 1.7+) with the case statements being names and the returns being months. If not, do what @KickButtowski said and then do this – k_g Jun 22 '14 at 20:40
  • 1
    Are you trying to parse a number or a month name? Can you give an example? – Peter Lawrey Jun 22 '14 at 20:40
  • Probably you could use a `Map` to store the names (in your preferred language) to the number of months (`0` or `1` based; `Calendar` is `0` based) – Gábor Bakos Jun 22 '14 at 20:42
  • 1
    It would help if you gave a few examples of the input you're expecting. There are lots of possibilities. For example, will it just be whole names in English? Or perhaps you need support for abbreviations? What about other languages? – Matt Johnson-Pint Jun 22 '14 at 20:57

6 Answers6

36

Use Java's Calendar class. It can parse any given string into a valid calendar instance. Here is an example (assuming that the month is in english).

Date date = new SimpleDateFormat("MMMM", Locale.ENGLISH).parse(monthName);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
println(cal.get(Calendar.MONTH));

You can specify the language in SimpleDateFormat:

String monthName = "März"; // German for march
Date date = new SimpleDateFormat("MMMM", Locale.GERMAN).parse(monthName);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
println(cal.get(Calendar.MONTH));

By default, Java uses the user's local to parse the string.

Keep in mind that a computer starts counting at 0. So, January will be 0. If you want a human readable date, you should format the calendar instance:

SimpleDateFormat inputFormat = new SimpleDateFormat("MMMM");
Calendar cal = Calendar.getInstance();
cal.setTime(inputFormat.parse(monthName));
SimpleDateFormat outputFormat = new SimpleDateFormat("MM"); // 01-12
println(outputFormat.format(cal.getTime()));
Vikcen
  • 153
  • 2
  • 9
Matt3o12
  • 4,192
  • 6
  • 32
  • 47
  • 4
    [deprecated](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html#getMonth--) javadocs states what to use instead – A4L Jun 22 '14 at 20:46
  • Well, it works fine in Java 6 but I'll update the answer for Java 8+. – Matt3o12 Jun 22 '14 at 20:50
  • 1
    *Deprecated. **As of JDK version 1.1**, replaced by Calendar.get(Calendar.MONTH).* its kept there only for backward compatibility and may be removed in a future release! – A4L Jun 22 '14 at 20:53
  • 3
    The fact that *works* doesn't mean it is valid code. You're still using `Date#getMonth` which is **deprecated** (it means: **don't use it**). Use a `Calendar` instead to retrieve the month. Or if you're using Java 8, use the new [Date Time API](http://docs.oracle.com/javase/tutorial/datetime/) to do the job. – Luiggi Mendoza Jun 22 '14 at 20:54
  • 1
    Also - it returns 0-11 for the month number, where you might expect 1-12. – Matt Johnson-Pint Jun 22 '14 at 20:55
  • The code was updated, but you missed to update the text that explains the code... – Luiggi Mendoza Jun 22 '14 at 21:10
  • FYI, the troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Apr 19 '18 at 07:39
18

Solution in Java 8 for English month names.

private int getMonthNumber(String monthName) {
    return Month.valueOf(monthName.toUpperCase()).getValue();
}
Yuriy Tumakha
  • 1,450
  • 17
  • 21
4

Another approach using java.text.DateFormatSymbols is this:

public static int monthAsNumber(
  String  month,
  Locale  locale,
  boolean abbreviated,
  boolean caseInsensitive
) {
  DateFormatSymbols dfs = new DateFormatSymbols(locale);
  String[] months = (abbreviated ? dfs.getShortMonths() : dfs.getMonths());

  if (caseInsensitive) {
    for (int i = 0; i < 12; i++) {
      if (months[i].equalsIgnoreCase(month)) {
        return i; // month index is zero-based as usual in old JDK pre 8!
      }
    }
  } else {
    for (int i = 0; i < 12; i++) {
      if (months[i].equals(month)) {
        return i; // month index is zero-based as usual in old JDK pre 8!
      }
    }
  }
  return -1; // no match
}

The proposed signature of seach method illustrates the many possible variations. Example:

System.out.println(monthAsNumber("MÄRZ", Locale.GERMANY, false, true));
// output: 2 (zero-based!)

If you want a month number starting with 1 then just add 1 to the result (more intuitive and also my recommendation).

Starting with Java 8 you have a new variation, too, namely stand-alone months. While in English these month names are identical in other languages they are not always identical (for example in Czech language "leden" (January) instead of "ledna"). To achieve these stand-alone forms you can use Month.getDisplayName(...) (not tested):

public static int monthAsNumber(
  String  month,
  Locale  locale,
  boolean abbreviated,
  boolean caseInsensitive,
  boolean standAlone
) {
  TextStyle style;
  Month[] months = Month.values[];

  if (abbreviated) {
    style = standAlone ? TextStyle.SHORT_STANDALONE : TextStyle.SHORT;
  } else {
    style = standAlone ? TextStyle.FULL_STANDALONE : TextStyle.FULL;
  }

  if (caseInsensitive) {
    for (int i = 0; i < 12; i++) {
      if (months[i].getDisplayName(style, locale).equalsIgnoreCase(month)) {
        return i; // month index is zero-based as usual in old JDK pre 8!
      }
    }
  } else {
    for (int i = 0; i < 12; i++) {
      if (months[i].getDisplayName(style, locale).equals(month)) {
        return i; // month index is zero-based as usual in old JDK pre 8!
      }
    }
  }
  return -1; // no match
}
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • 2
    The comment about "index is zero-based" leads me to remind people that the [`Month`](http://docs.oracle.com/javase/8/docs/api/java/time/Month.html) enum can be used in your code instead of `int` values. Rather than pass around `10` or the zero-based `9` for October, pass around `Month.OCTOBER`, an actual type-safe object rather than "magic number". Modify the example code by replacing `return i;` with `return months[i];`. `Enum` is quite the sleeper feature in Java, amazingly useful once you get the hang of it. See the [Tutorial](http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). – Basil Bourque Oct 27 '15 at 07:10
  • @BasilBourque Right, I have written my contribution that way because the OP explicitly wanted a number which gives space for interpretation, but I prefer an enum as return type like you. The only "disadvantage" for the OP might be that he/she will be forced to rewrite his application due to the incompatible change of method signature but at the end such a refactoring would be a win for the OP. – Meno Hochschild Oct 27 '15 at 11:04
3

If you have month name and you want integer number corresponding to that month try this

try{   
        Date date = new SimpleDateFormat("MMM", Locale.ENGLISH).parse(monthName);//put your month name in english here
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        monthNumber=cal.get(Calendar.MONTH);
        System.out.println(monthNumber);

 }
catch(Exception e)
{
 e.printStackTrace();
}
Vikcen
  • 153
  • 2
  • 9
RockAndRoll
  • 2,247
  • 2
  • 16
  • 35
3

Using Java 8 API

final DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("MMM").withLocale(Locale.ENGLISH);
final TemporalAccessor temporalAccessor = dtFormatter.parse(month);
final int monthNumber = temporalAccessor.get(ChronoField.MONTH_OF_YEAR);
K. Gol
  • 1,391
  • 12
  • 15
2

java.time

In March 2014, modern date-time API API supplanted the error-prone java.util date-time API and their formatting API, SimpleDateFormat. Since then it has been highly recommended to stop using the legacy API.

Solution using java.time, the modern Date-Time API:

Use a DateTimeFormatter with the pattern MMMM to parse the given date. If the name of the month can be in different cases, you should build and use a case-insensitive DateTimeFormatter.

Demo:

import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

class Main {
    public static void main(String[] args) {
        // A sample month
        String monthName = "March";
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("MMMM", Locale.ENGLISH);
        Month month = Month.from(parser.parse(monthName));
        int monthNumber = month.getValue();
        System.out.println(monthNumber);

        // A case-insensitive formatter
        DateTimeFormatter parserIgnoreCase = new DateTimeFormatterBuilder()
                                                    .parseCaseInsensitive()
                                                    .appendPattern("MMMM")
                                                    .toFormatter(Locale.ENGLISH);

        System.out.println(Month.from(parserIgnoreCase.parse("march")).getValue());
    }
}

Output:

3
3

Note: Never use SimpleDateFormat or DateTimeFormatter without a Locale.

Learn more about the modern Date-Time API from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110