Java: Nhận số nguyên tháng từ ngày


157

Làm cách nào để tôi nhận được tháng dưới dạng một số nguyên từ một đối tượng Date ( java.util.Date)?


23
thực sự getMonth () vào ngày bị từ
chối

6
@slhck: Không dùng nữa. Kể từ phiên bản JDK 1.1, được thay thế bằng Calendar.get (Lịch.MONTH).
adarshr

3
@Zenzen Tôi không thấy vấn đề trong việc sử dụng một phương thức không dùng nữa trong một lớp chủ yếu không dùng nữa.
Serabe

1
@Muhd nếu bạn đang làm việc với ngày, hãy tự giúp mình và sử dụng joda hoặc bất kỳ thư viện nào khác.
Serabe

1
@Serabe: vấn đề là có những giải pháp tốt hơn (những giải pháp ít nhất không bị phản đối). Và getMonth đã bị từ chối trong 14 năm nay và nó đã bị từ chối vì một lý do.
Mateusz Dymchot

Câu trả lời:


57

java.time (Java 8)

Bạn cũng có thể sử dụng gói java.time trong Java 8 và chuyển đổi java.util.Dateđối tượng của mình thành java.time.LocalDateđối tượng và sau đó chỉ cần sử dụng getMonthValue()phương thức.

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

Lưu ý rằng các giá trị tháng được đưa ra từ 1 đến 12 trái với cal.get(Calendar.MONTH)câu trả lời của adarshr đưa ra các giá trị từ 0 đến 11.

Nhưng như Basil Bourque đã nói trong các bình luận, cách ưa thích là lấy một Monthđối tượng enum với LocalDate::getMonthphương thức này.


1
Câu trả lời tốt. Lưu ý cho người đọc: Bạn có thể muốn chỉ định múi giờ thay vì dựa vào cuộc gọi mặc định được hiển thị trong Trả lời. Một ngày mới (và tháng) khởi đầu sớm hơn ở Paris, ví dụ, hơn Montréal. Nếu bạn quan tâm đặc biệt về Montréal, việc sử dụng ZoneId.of( "America/Montreal" ).
Basil Bourque

1
Tôi chỉ muốn nói thêm rằng có một bài viết tuyệt vời về việc giới thiệu java.time api oracle.com/technetwork/articles/java/

Nhân tiện, một lưu ý khác cho người đọc: Bạn cũng có thể nhận được một Monthđối tượng enum chứ không phải là một số nguyên. Month m = localDate.gotMonth();Xem LocalDate::getMonthphương pháp. Việc sử dụng các đối tượng như thế này làm cho mã của bạn tự ghi lại tài liệu, đảm bảo an toàn kiểu và đảm bảo các giá trị hợp lệ. Xem hướng dẫn Enum của Oracle.
Basil Bourque

1
nếu bạn sử dụng date.toInstant()và bạn tình cờ làm việc với java.sql.Date(con của java.util.Date) thì bạn sẽ nhận được UnsupportedOperationException. Hãy thửnew java.sql.Date(src.getTime()).toLocalDate()
Adam

1
@Adam Dễ dàng chuyển đổi sang / từ hơn java.sql.Datebằng cách sử dụng các phương thức chuyển đổi mới được thêm vào lớp cũ đó. java.sql.Date.valueOf( myLocalDate )myJavaSqlDate.toLocalDate() Ngoài ra, trình điều khiển JDBC được cập nhật cho JDBC 4.2 trở lên không còn cần java.sqlcác loại và có thể trực tiếp giải quyết java.timecác loại thông qua các phương thức ResultSet::getObjectPreparedStatement::setObject.
Basil Bourque

287
java.util.Date date= new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int month = cal.get(Calendar.MONTH);

166
Lưu ý rằng Calendar.MONTHkhông có lý do rõ ràng dựa trên ZERO, tức là tháng 1 == 0. Bây giờ, tài liệu này chỉ hoạt động tốt trong API, nhưng nó vẫn gây nhầm lẫn cho người dùng lần đầu. Tôi vẫn chưa tìm thấy ai có thể cho tôi biết lý do tại sao họ lại đi với điều đó - có lẽ đã đến lúc tôi có một câu hỏi SO mới (mặc dù tôi sợ không có bất kỳ nền tảng tuyệt vời nào về điều đó: /)
Voo

5
Phương thức @Voo Date.getMonth () là không dựa trên, đó có thể là lý do chính của Lịch.MONTH là tốt.
Muhd

1
@Muhd Chắc chắn sau tất cả, nó là sự thay thế. Nhưng điều đó chỉ làm thay đổi câu hỏi xung quanh tại sao Date.getMonth () không dựa trên? Imo một thiết kế khủng khiếp, đặc biệt là kể từ ngày bắt đầu tại một (ít nhất là chúng có thể nhất quán!). Tôi cho rằng đó chỉ là sự giám sát trong một API không được thiết kế đặc biệt (cả Ngày và Lịch) để bắt đầu. Nhưng có lẽ có một số tiền lệ - nó có vẻ lạ đối với tôi và đã gây ra nhiều vấn đề cho nhiều người mới bắt đầu trải nghiệm của tôi.
Voo

2
Trên thực tế, nó đã được hỏi ở đây trên SO (và không chỉ). Điểm mấu chốt là đó là kết quả của API được thiết kế tồi. Ý tôi là như bạn đã đề cập đến toàn bộ lớp Date là một trò đùa. Một sự thật thú vị là không chỉ Java gặp phải vấn đề này - iirc JavaScript của Ngày getMonth () cũng bắt đầu bằng 0!
Mateusz Dymchot

1
@Voo getYear()cũng vậy, "không có lý do rõ ràng", bị trừ vào năm 1900.
Hele

17

Nếu bạn sử dụng api Java 8 ngày, bạn có thể trực tiếp lấy nó trong một dòng!

LocalDate today = LocalDate.now();
int month = today.getMonthValue();

7

Joda-Thời gian

Ngoài ra, với lớp Joda-Time DateTime .

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

…hoặc là…

int month = dateTime.getMonthOfYear();

2
Thậm chí đơn giản hơn, chỉ cần yêu cầu DateTimeđối tượng cho tháng của nó. int month = dateTime.getMonthOfYear();
Basil Bourque

Gọi Basil tốt, tôi đã cập nhật mã. Tuy nhiên, tôi thích .toString("MM")vì nó cho thấy có nhiều khả năng hơn là "MM".
ssoward

1
Câu trả lời này bỏ qua vấn đề quan trọng của múi giờ. Xem ý kiến ​​của tôi về Câu hỏi và Anh chị em Trả lời. Tôi đề nghị chuyển một DateTimeZoneđối tượng đến hàm tạo 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 Chi tiết

Câu trả lời của Ortomala Lokni cho việc sử dụng java.time là chính xác. Và bạn nên sử dụng java.time vì đây là một cải tiến vượt bậc so với các lớp java.util.Date/.CalWiki cũ. Xem Hướng dẫn của Oracle trên java.time.

Tôi sẽ thêm một số mã cho biết cách sử dụng java.time mà không cần quan tâm đến java.util.Date, khi bạn bắt đầu với mã mới.

Sử dụng java.time một cách ngắn gọn Instantlà An An là một khoảnh khắc trên dòng thời gian trong UTC. Áp dụng múi giờ ( ZoneId) để có được a ZonedDateTime.

Các Monthlớp là một tinh vi enum để đại diện cho một tháng nói chung. Enum đó có các phương thức tiện dụng như lấy tên địa phương. Và hãy yên tâm rằng số tháng trong java.time là một số lành mạnh, 1-12, không phải là vô nghĩa dựa trên số không (0-11) được tìm thấy trong java.util.Date/.CalWiki.

Để có được thời gian hiện tại, múi giờ là rất quan trọng. Tại bất kỳ thời điểm nào, ngày không giống nhau trên toàn thế giới. Do đó, tháng không giống nhau trên toàn thế giới nếu gần cuối / đầu tháng.

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 );

Giới thiệu về java.time

Các java.time khung được xây dựng vào Java 8 và sau đó. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Để tìm hiểu thêm, xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của bạn. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần chuỗi, không cần java.sql.*lớp.

Nơi để có được các lớp java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với việc triển khai đi kèm.
    • Java 9 thêm một số tính năng nhỏ và sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng java.time được chuyển ngược lại sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản sau của triển khai gói Android của các lớp java.time.
    • Đối với Android trước đó (<26), các ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP .

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho các bổ sung có thể trong tương lai cho java.time. Bạn có thể tìm thấy một số lớp hữu ích ở đây nhưInterval , YearWeek, YearQuarter, và nhiều hơn nữa .


4

Nếu bạn không thể sử dụng thời gian của Joda và bạn vẫn sống trong thế giới đen tối :) (Java 5 hoặc thấp hơn), bạn có thể tận hưởng điều này:

Lưu ý: Đảm bảo rằng ngày của bạn đã được thực hiện theo định dạng: dd / MM / YYYY

/**
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));
}

Con là mẹ! / Είσiated μάα!
Tzegenos

0
Date mDate = new Date(System.currentTimeMillis());
mDate.getMonth() + 1

Giá trị trả về bắt đầu từ 0, vì vậy bạn nên thêm một vào kết quả.


6
2 vấn đề với câu trả lời của bạn: một là bạn có thể hẹn hò với thời gian hiện tại bằng cách thực hiện new Date()mà không cần System.currentTimeMillis. Khác là getMonth không được dùng nữa.
Muhd

@Muhd Vậy đâu là giải pháp tốt nhất?
twlkyao

@Muhd System.civerseTimeMillis () tôi đã thêm ở đây là để chỉ ra rằng đây là một loại dài và bạn có thể chỉ định ngày.
twlkyao

4
Ngày :: getMonth đã bị phản đối trong Java 1.1 ( cs.mun.ca/~michael/java/jdk1.1-beta2-docs/api/iêu )
Ortomala Lokni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.