Java: pobierz liczbę całkowitą miesiąca od daty

157

Jak uzyskać miesiąc jako liczbę całkowitą z obiektu Date ( java.util.Date)?

Muhd
źródło
23
faktycznie getMonth () on Date jest przestarzałe od zawsze;)
Mateusz Dymczyk
6
@slhck: wycofane. Od wersji 1.1 JDK zastąpiony przez Calendar.get (Calendar.MONTH).
adarshr
3
@Zenzen Nie widzę problemu w używaniu przestarzałej metody w przeważnie przestarzałej klasie.
Serabe
1
@Muhd, jeśli pracujesz z datami, pomóż sobie i użyj jody lub innej biblioteki.
Serabe
1
@Serabe: problem polega na tym, że istnieją lepsze rozwiązania (takie, które przynajmniej nie są przestarzałe). Funkcja getMonth jest przestarzała od 14 lat i nie bez powodu została wycofana.
Mateusz Dymczyk

Odpowiedzi:

57

java.time (Java 8)

Możesz także użyć pakietu java.time w Javie 8 i przekonwertować java.util.Dateobiekt na java.time.LocalDateobiekt, a następnie po prostu użyć tej getMonthValue()metody.

Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
int month = localDate.getMonthValue();

Zauważ, że wartości miesięcy są tutaj podane od 1 do 12, w przeciwieństwie do cal.get(Calendar.MONTH)odpowiedzi adarshr, która podaje wartości od 0 do 11.

Ale jak powiedział Basil Bourque w komentarzach, preferowanym sposobem jest uzyskanie Monthobiektu enum za pomocą LocalDate::getMonthmetody.

Ortomala Lokni
źródło
1
Dobra odpowiedź. Uwaga dla czytelnika: Możesz chcieć określić strefę czasową zamiast polegać na wywołaniu domyślnym pokazanym w odpowiedzi. Na przykład nowy dzień (i miesiąc) wstaje w Paryżu wcześniej niż w Montrealu. Jeśli zależy Ci szczególnie na Montrealu, użyj ZoneId.of( "America/Montreal" ).
Basil Bourque
1
Chcę tylko dodać, że jest świetny artykuł o wprowadzeniu api java.time oracle.com/technetwork/articles/java/ ...
Nawiasem mówiąc, kolejna uwaga dla czytelnika: można również uzyskać Monthobiekt wyliczenia zamiast zwykłej liczby całkowitej. Month m = localDate.gotMonth();Zobacz LocalDate::getMonthmetodę. Użycie takich obiektów powoduje, że kod samodokumentuje się, zapewnia bezpieczeństwo typów i gwarantuje prawidłowe wartości. Zobacz samouczek dotyczący Enum firmy Oracle.
Basil Bourque
1
jeśli używasz date.toInstant()i pracujesz z java.sql.Date(dzieckiem java.util.Date), otrzymasz rozszerzenie UnsupportedOperationException. Spróbujnew java.sql.Date(src.getTime()).toLocalDate()
Adam,
1
@Adam Znacznie łatwiejsze do konwersji na / z java.sql.Dateprzy użyciu nowych metod konwersji dodanych do tej starej klasy. java.sql.Date.valueOf( myLocalDate )a myJavaSqlDate.toLocalDate() także zaktualizowane sterowniki JDBC dla JDBC 4.2 lub nowszy nie jest już potrzebna java.sqlrodzajów oraz możliwość bezpośredniego kontaktu z java.timetypów za ResultSet::getObjecti PreparedStatement::setObjectmetody.
Basil Bourque
287
java.util.Date date= new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int month = cal.get(Calendar.MONTH);
adarshr
źródło
166
Zauważ, że Calendar.MONTHbez wyraźnych powodów opiera się na ZERO, tj. Styczeń == 0. Teraz jest to dobrze udokumentowane w API, ale wciąż jest mylące dla początkujących użytkowników. Nie znalazłem jeszcze nikogo, kto mógłby mi powiedzieć, dlaczego poszli na to - może sam czas na nowe pytanie SO (choć obawiam się, że nie ma w tym świetnego tła: /)
Voo
5
Metoda @Voo Date.getMonth () była oparta na zerach, co jest prawdopodobnie głównym powodem, dla którego Calendar.MONTH jest również.
Muhd
1
@Muhd Pewnie, że to była wymiana. Ale to tylko przesuwa pytanie, dlaczego Date.getMonth () był oparty na zero? Imo okropny projekt, zwłaszcza że dni zaczynają się od pierwszego (przynajmniej mogą być spójne!). Zakładam, że na początku było to tylko przeoczenie w niezbyt dobrze zaprojektowanym API (zarówno Data, jak i Kalendarz). Ale może jest jakiś precedens - po prostu wydaje mi się to dziwne i z mojego doświadczenia wynika, że ​​przysporzyło problemów więcej niż jednemu początkującemu.
Voo
2
Właściwie pytano o to już tutaj na SO (i nie tylko). Najważniejsze jest to, że jest to wynikiem źle zaprojektowanego API. To znaczy, jak wspomniałeś, cała klasa randkowa to żart. Zabawne jest to, że nie tylko Java cierpi na ten problem - Date getMonth () iirc również zaczyna się od 0!
Mateusz Dymczyk
1
@Voo getYear()jest również odejmowane „bez wyraźnych powodów” do roku 1900.
Hele,
17

Jeśli korzystasz z api dat Java 8 , możesz je pobrać bezpośrednio w jednej linii!

LocalDate today = LocalDate.now();
int month = today.getMonthValue();
Ketan Chitale
źródło
7

Joda-Time

Alternatywnie z klasą Joda-Time DateTime .

//convert date to datetime
DateTime datetime = new DateTime(date);
int month = Integer.parseInt(datetime.toString("MM"))

…lub…

int month = dateTime.getMonthOfYear();
ssoward
źródło
2
Jeszcze prościej, po prostu zapytaj DateTimeobiekt o jego miesiąc. int month = dateTime.getMonthOfYear();
Basil Bourque
Dobry telefon Bazyli, zaktualizowałem kod. Jednak podoba mi się to, .toString("MM")ponieważ pokazuje, że możliwości jest więcej niż tylko „MM”.
ssoward
1
Ta odpowiedź pomija kluczową kwestię strefy czasowej. Zobacz moje komentarze na temat pytania i odpowiedzi rodzeństwa. Proponuję przechodzącą DateTimeZoneobiekt do tego konstruktora DateTime: DateTimeZone.forID( "America/Montreal" ).
Basil Bourque
6

tl; dr

myUtilDate.toInstant()                          // Convert from legacy class to modern. `Instant` is a point on the timeline in UTC.
          .atZone(                              // Adjust from UTC to a particular time zone to determine date. Renders a `ZonedDateTime` object. 
              ZoneId.of( "America/Montreal" )   // Better to specify desired/expected zone explicitly than rely implicitly on the JVM’s current default time zone.
          )                                     // Returns a `ZonedDateTime` object.
          .getMonthValue()                      // Extract a month number. Returns a `int` number.

java.time Detale

Odpowiedź Ortomala Lokni dotycząca korzystania z java.time jest poprawna. I powinny być korzystając java.time jak to jest gigantyczna poprawa w stosunku do dawnych klas java.util.Date/.Calendar. Zobacz samouczek Oracle w witrynie java.time.

Dodam kod pokazujący, jak używać java.time bez względu na java.util.Date, gdy zaczynasz od nowego kodu.

Korzystanie z java.time w pigułce… InstantTo moment na osi czasu w UTC. Zastosuj strefę czasową ( ZoneId), aby uzyskać plik ZonedDateTime.

MonthKlasa to wyrafinowana enum do reprezentowania miesiąc w ogóle. To wyliczenie ma przydatne metody, takie jak uzyskanie zlokalizowanej nazwy. Zapewniamy, że numer miesiąca w java.time to rozsądny numer 1-12, a nie bzdury zaczynające się od zera (0-11), które można znaleźć w java.util.Date/.Calendar.

Aby uzyskać aktualną datę i godzinę, kluczowa jest strefa czasowa . W żadnym momencie data nie jest taka sama na całym świecie. Dlatego miesiąc nie jest taki sam na całym świecie, jeśli zbliża się koniec / początek miesiąca.

ZoneId zoneId = ZoneId.of( "America/Montreal" );  // Or 'ZoneOffset.UTC'.
ZonedDateTime now = ZonedDateTime.now( zoneId );
Month month = now.getMonth(); 
int monthNumber = month.getValue(); // Answer to the Question.
String monthName = month.getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH );

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas.

Skąd wziąć klasy java.time?

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
4

Jeśli nie możesz wykorzystać czasu Jody, a nadal żyjesz w ciemnym świecie :) (Java 5 lub niższa), możesz cieszyć się tym:

Uwaga: upewnij się, że data jest już wpisana w formacie: dd / MM / RRRR

/**
Make an int Month from a date
*/
public static int getMonthInt(Date date) {

    SimpleDateFormat dateFormat = new SimpleDateFormat("MM");
    return Integer.parseInt(dateFormat.format(date));
}

/**
Make an int Year from a date
*/
public static int getYearInt(Date date) {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");
    return Integer.parseInt(dateFormat.format(date));
}
Badr DRAIFI
źródło
Ty jesteś matką! / Είσαι η μάνα!
Tzegenos,
0
Date mDate = new Date(System.currentTimeMillis());
mDate.getMonth() + 1

Zwracana wartość zaczyna się od 0, więc do wyniku należy dodać jeden.

twlkyao
źródło
6
2 problemy z twoją odpowiedzią: jeden z nich polega na tym, że możesz umówić się na randkę z aktualnym czasem, robiąc new Date()bez System.currentTimeMillis. Po drugie, metoda getMonth jest przestarzała.
Muhd
@Muhd Jakie jest więc najlepsze rozwiązanie?
twlkyao
@Muhd System.currentTimeMillis () dodałem tutaj, aby wskazać, że tutaj jest długi typ i możesz określić datę.
twlkyao
4
Date :: getMonth był już przestarzały w Javie 1.1 ( cs.mun.ca/~michael/java/jdk1.1-beta2-docs/api/… )
Ortomala Lokni