Cách tạo Đối tượng Ngày với các giá trị trong java


91

Tôi cần một đối tượng ngày tháng cho ngày 2014-02-11. Tôi không thể trực tiếp tạo nó như thế này,

Date myDate = new Date(2014, 02, 11);

Vì vậy, tôi đang làm như sau,

Calendar myCalendar = new GregorianCalendar(2014, 2, 11);
Date myDate = myCalendar.getTime();

Có cách nào dễ dàng để tạo đối tượng ngày tháng trong java không?


7
Có gì không dễ dàng trong cách tiếp cận của bạn?
giorashc

3
"Có cách nào dễ dàng không". Điều gì khiến bạn nghĩ rằng điều đó không dễ dàng như nó có thể được? Thời gian và ngày tháng phức tạp hơn bạn tưởng rất nhiều. Có nhiều lịch và nhiều múi giờ.
Raedwald

5
Một dòng như thế Date myDate = new GregorianCalendar(2014, 2, 11).getTime();nào?
Elliott Frisch

2
Hãy cẩn thận khi sử dụng số 0 đứng đầu trong một chữ số nguyên như được thấy trong Câu hỏi này , 02. Trong Java, điều đó có nghĩa là số bát phân (cơ số 8) chứ không phải số thập phân (cơ số 10).
Basil Bourque

2
FYI, người già lớp ngày thời gian khủng khiếp phiền hà như java.util.Date, java.util.Calendarjava.text.SimpleDateFormatbây giờ là di sản , thay thế bởi sự java.time class built vào Java 8 và sau đó. Xem Hướng dẫn của Oracle .
Basil Bourque

Câu trả lời:


108

Gotcha: vượt qua 2 là tháng có thể mang lại cho bạn kết quả không mong đợi: trong API Lịch, tháng là số không. 2 thực sự có nghĩa là tháng ba.

Tôi không biết cách "dễ dàng" mà bạn đang tìm kiếm là gì vì tôi cảm thấy rằng việc sử dụng Lịch đã đủ dễ dàng.

Hãy nhớ sử dụng các hằng số chính xác cho tháng:

 Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11).getTime();

Một cách khác là sử dụng DateFormat, mà tôi thường sử dụng như sau:

 public static Date parseDate(String date) {
     try {
         return new SimpleDateFormat("yyyy-MM-dd").parse(date);
     } catch (ParseException e) {
         return null;
     }
  }

để tôi có thể viết đơn giản

Date myDate = parseDate("2014-02-14");

Tuy nhiên, một giải pháp thay thế khác mà tôi thích hơn: Không sử dụng Ngày / Lịch Java nữa. Chuyển sang Giờ JODA hoặc Giờ Java (hay còn gọi là JSR310, có sẵn trong JDK 8+). Bạn có thể sử dụng LocalDateđể đại diện cho một ngày, có thể dễ dàng tạo bởi

LocalDate myDate =LocalDate.parse("2014-02-14");
// or
LocalDate myDate2 = new LocalDate(2014, 2, 14);
// or, in JDK 8+ Time
LocalDate myDate3 = LocalDate.of(2014, 2, 14);

1
.toTime()không tồn tại. Nó phải là .getTime()(xem Tài liệu Java )
0xJoKe

Xin lỗi một lỗi chính tả. Mặc dù tôi nghĩ OP đã biết phương pháp đúng để gọi: P
Adrian Shum

Khá chắc chắn rằng bạn đúng. Nhưng đối với những người (như tôi), những người phải tra cứu nó mỗi khi cần thì thật là khó chịu. Cảm ơn vì đã sửa :)
0xJoKe

1
return new SimpleDateFormat("yyyy-mm-dd").parse(date) nên đượcreturn new SimpleDateFormat("yyyy-MM-dd").parse(date)
aks

Nắm bắt tốt. Dunno tại sao tôi lại mắc sai lầm như vậy. Khắc phục sự cố
Adrian Shum

34

tl; dr

LocalDate.of( 2014 , 2 , 11 )

Nếu bạn khăng khăng sử dụng java.util.Datelớp cũ khủng khiếp , hãy chuyển đổi từ các lớp java.time hiện đại .

java.util.Date                        // Terrible old legacy class, avoid using. Represents a moment in UTC. 
.from(                                // New conversion method added to old classes for converting between legacy classes and modern classes.
    LocalDate                         // Represents a date-only value, without time-of-day and without time zone.
    .of( 2014 , 2 , 11 )              // Specify year-month-day. Notice sane counting, unlike legacy classes: 2014 means year 2014, 1-12 for Jan-Dec.
    .atStartOfDay(                    // Let java.time determine first moment of the day. May *not* start at 00:00:00 because of anomalies such as Daylight Saving Time (DST).
        ZoneId.of( "Africa/Tunis" )   // Specify time zone as `Continent/Region`, never the 3-4 letter pseudo-zones like `PST`, `EST`, or `IST`. 
    )                                 // Returns a `ZonedDateTime`.
    .toInstant()                      // Adjust from zone to UTC. Returns a `Instant` object, always in UTC by definition.
)                                     // Returns a legacy `java.util.Date` object. Beware of possible data-loss as any microseconds or nanoseconds in the `Instant` are truncated to milliseconds in this `Date` object.   

Chi tiết

Nếu bạn muốn "dễ dàng", bạn nên sử dụng gói java.time mới trong Java 8 thay vì các lớp java.util.Date & .Calendar nổi tiếng rắc rối đi kèm với Java.

java.time

Các java.time khuôn khổ xây dựng vào Java 8 và sau đó đã thế chỗ các lớp java.util.Date/.Calendar cũ phiền hà.

Chỉ ngày

nhập mô tả hình ảnh ở đây

Một LocalDatelớp được cung cấp bởi java.time để đại diện cho một giá trị chỉ ngày mà không có bất kỳ thời gian trong ngày hoặc múi giờ nào. Bạn cần một múi giờ để xác định một ngày, ví dụ như một ngày mới ở Paris sớm hơn ở Montréal. Các ZoneIdlớp học là dành cho các múi giờ.

ZoneId zoneId = ZoneId.of( "Asia/Singapore" );
LocalDate today = LocalDate.now( zoneId );

Đổ vào bảng điều khiển:

System.out.println ( "today: " + today + " in zone: " + zoneId );

hôm nay: 2015-11-26 trong khu vực: Châu Á / Singapore

Hoặc sử dụng phương pháp nhà máy để xác định năm, tháng, ngày.

LocalDate localDate = LocalDate.of( 2014 , Month.FEBRUARY , 11 );

localDate: 2014-02-11

Hoặc chuyển một tháng số 1-12 thay vì một DayOfWeekđối tượng enum.

LocalDate localDate = LocalDate.of( 2014 , 2 , 11 );

Múi giờ

nhập mô tả hình ảnh ở đây

A LocalDatekhông có ý nghĩa thực sự cho đến khi bạn điều chỉnh nó thành một múi giờ. Trong java.time, chúng tôi áp dụng múi giờ để tạo một ZonedDateTimeđối tượng. Điều đó cũng có nghĩa là thời gian trong ngày, nhưng thời gian nào? Thường có ý nghĩa khi đi với khoảnh khắc đầu tiên trong ngày. Bạn có thể nghĩ rằng điều đó có nghĩa là thời gian 00:00:00.000, nhưng không phải lúc nào cũng đúng vì Giờ tiết kiệm ánh sáng ban ngày (DST) và có lẽ là những dị thường khác. Thay vì giả định thời gian đó, chúng tôi yêu cầu java.time xác định thời điểm đầu tiên trong ngày bằng cách gọi atStartOfDay.

Chỉ định một tên múi giờ thích hợp trong các định dạng của continent/region, chẳng hạn như America/Montreal, Africa/Casablancahoặc Pacific/Auckland. Không bao giờ sử dụng từ viết tắt 3-4 chữ cái, chẳng hạn như ESThoặc ISTvì chúng không phải là múi giờ thực, không được tiêu chuẩn hóa và thậm chí không phải là duy nhất (!).

ZoneId zoneId = ZoneId.of( "Asia/Singapore" );
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );

zdt: 2014-02-11T00: 00 + 08: 00 [Châu Á / Singapore]

UTC

nhập mô tả hình ảnh ở đây

Đối với công việc back-end (logic nghiệp vụ, cơ sở dữ liệu, lưu trữ và trao đổi dữ liệu), chúng tôi thường sử dụng múi giờ UTC . Trong java.time, Instantlớp biểu thị một thời điểm trên dòng thời gian ở UTC. Một đối tượng Instant có thể được trích xuất từ ​​ZonedDateTime bằng cách gọi toInstant.

Instant instant = zdt.toInstant();

tức thì: 2014-02-10T16: 00: 00Z

Đổi

Bạn nên tránh sử dụng java.util.Datehoàn toàn lớp học. Nhưng nếu bạn phải tương tác với mã cũ chưa được cập nhật cho java.time , bạn có thể chuyển đổi qua lại. Tìm kiếm các phương thức chuyển đổi mới được thêm vào các lớp cũ.

java.util.Date d = java.util.from( instant ) ;

… Và…

Instant instant = d.toInstant() ;

Bảng tất cả các loại ngày-giờ trong Java, cả hiện đại và kế thừa


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.

Để tìm hiểu thêm, hãy 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 .

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.

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 mình. 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. Hibernate 5 & JPA 2.2 hỗ trợ java.time .

Lấy các lớp java.time ở đâu?


CẬP NHẬT: Thư viện Joda-Time hiện đang ở chế độ bảo trì và khuyên bạn nên di chuyển sang các lớp java.time . Tôi để lại phần này cho lịch sử.

Joda-Time

Có điều, Joda-Time sử dụng cách đánh số hợp lý nên tháng 2 thì 2không 1. Một điều khác, Joda-Time DateTime thực sự biết múi giờ được chỉ định của nó không giống như java.util.Date dường như có múi giờ nhưng không.

Và đừng quên múi giờ. Nếu không, bạn sẽ nhận được mặc định của JVM.

DateTimeZone timeZone = DateTimeZone.forID( "Asia/Singapore" );
DateTime dateTimeSingapore = new DateTime( 2014, 2, 11, 0, 0, timeZone );
DateTime dateTimeUtc = dateTimeSingapore.withZone( DateTimeZone.UTC );

java.util.Locale locale = new java.util.Locale( "ms", "SG" ); // Language: Bahasa Melayu (?). Country: Singapore.
String output = DateTimeFormat.forStyle( "FF" ).withLocale( locale ).print( dateTimeSingapore );

Đổ vào bảng điều khiển…

System.out.println( "dateTimeSingapore: " + dateTimeSingapore );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "output: " + output );

Khi chạy…

dateTimeSingapore: 2014-02-11T00:00:00.000+08:00
dateTimeUtc: 2014-02-10T16:00:00.000Z
output: Selasa, 2014 Februari 11 00:00:00 SGT

Chuyển đổi

Nếu bạn cần chuyển đổi sang java.util.Date để sử dụng với các lớp khác…

java.util.Date date = dateTimeSingapore.toDate();

4
Chỉ một bình luận. Thực hành tiền tố số không trong các trường như thế new DateTime( 2014, 02, 11, 0, 0, timeZone );có lẽ không thích hợp. Mặc dù nó hoạt động trong trường hợp này, nhưng, nó sẽ không biên dịch cho tháng 8 và tháng 9 nếu bạn đang chuyển 0809khi đặt tiền tố int bằng 0 có nghĩa là bản trình bày bát phân. Nó thậm chí sẽ cung cấp cho bạn các giá trị bất ngờ từ nhiều năm trước 1000, ví dụ như new DateTime( 0100, 02, 01, 0, 0, timeZone );rằng người ta có thể mong đợi nó sẽ 100AD nhưng thực sự nó là 64AD
Adrian Shum

@AdrianShum Yikes! Tôi chưa bao giờ biết một lỗi đánh máy nhỏ vô tội như một số 0 đứng đầu trên một chữ số nguyên có thể gây ra một tác dụng phụ khó chịu như vậy. Cảm ơn.
Basil Bourque vào

2
Kính gửi Cử tri xuống, hãy để lại lời chỉ trích cùng với phiếu bầu của bạn.
Basil Bourque vào

"Nếu bạn khăng khăng sử dụng lớp java.util.Date cũ khủng khiếp". Nhiều nhà cung cấp không cung cấp tomcat server chạy trên Java vượt JDK7, vì vậy, trong khi tôi sẽ loove sử dụng những thứ mới hơn, một số đang bị mắc kẹt tại các shit cũ vì người khác .....
KimvdLinde

@KimvdLinde Đọc lại câu trả lời của tôi cẩn thận hơn. Nhìn vào những viên đạn. Tìm các từ “Java SE 6 và Java SE 7”.
Basil Bourque

14

Tôi nghĩ rằng cách tốt nhất sẽ là sử dụng một SimpleDateFormatđối tượng.

DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateString = "2014-02-11";
Date dateObject = sdf.parse(dateString); // Handle the ParseException here

Y .. Và hãy chắc chắn rằng không bao giờ sử dụng YYYY - sử dụng yyyy - đặc biệt nếu làm điều này ngược lại với định dạng thay vì phân tích cú pháp. Bạn nhận được một số kết quả kỳ lạ !!! Xem tại đây: code.sololearn.com/c0EYUAOc92uQ/#java
JGFMK

9

Từ Java8:

import java.time.Instant;
import java.util.Date;

Date date = Date.from(Instant.parse("2000-01-01T00:00:00.000Z"))

2

Thử đi

 Calendar cal = Calendar.getInstance();
    Date todayDate = new Date();
    cal.setTime(todayDate);

    // Set time fields to zero
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    todayDate = cal.getTime();

1
SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.ENGLISH);
//format as u want

try {
    String dateStart = "June 14 2018 16:02:37";
    cal.setTime(sdf.parse(dateStart));
    //all done
} catch (ParseException e) {
    e.printStackTrace();
}

Các lớp CalendarSimpleDateFormatlớp khủng khiếp đã được thay thế nhiều năm trước bởi các lớp java.time . Đề xuất việc sử dụng chúng vào năm 2018 là một lời khuyên tồi.
Basil Bourque

Câu trả lời này không giải quyết các chi tiết cụ thể của Câu hỏi này.
Basil Bourque

1
Theo "cấp độ API", tôi cho rằng bạn muốn nói đến Android. Nhưng đây không phải là một Câu hỏi dành riêng cho Android. Hơn nữa, hầu hết chức năng java.time được chuyển ngược sang Java 6 & 7 trong dự án ThreeTen-Backport . Được điều chỉnh thêm cho Android trong dự án ThreeTenABP . Vì vậy, không cần phải sử dụng những lớp ngày-giờ kế thừa khủng khiếp đó. Các lớp java.time hoàn toàn tốt hơn.
Basil Bourque

Cảm ơn vì nhận xét này. Thư viện này có cung cấp chức năng như chênh lệch ngày và chênh lệch thời gian không.
Syed Danish Haider

1
Đúng. Tìm kiếm Tràn ngăn xếp cho nhiều câu hỏi và đáp hiện có về chủ đề này. Và hãy xem cả dự án ThreeTen-Extra (không được chuyển sang Android đời đầu).
Basil Bourque

0

Những cách đơn giản nhất:

Date date = Date.valueOf("2000-1-1");
LocalDate localdate = LocalDate.of(2000,1,1);
LocalDateTime localDateTime = LocalDateTime.of(2000,1,1,0,0);

Nên tránh cái đầu tiên vì java.sql.Datelớp mà bạn đang sử dụng được thiết kế kém và lâu lỗi thời. Tôi khuyên bạn nên sử dụng LocalDatenhư trong dòng thứ hai. Thói quen của tôi là LocalDate.of(2000, Month.JANUARY, 1), đọc xong thấy rõ hơn một chút.
Ole VV

và điều đó bởi vì câu trả lời chứa khai báo LocalDate, không chỉ đối tượng Date được hỏi (không bị phản đối và đôi khi được sử dụng) ...
Adam Silenko

-1
import java.io.*;
import java.util.*;
import java.util.HashMap;

public class Solution 
{

    public static void main(String[] args)
    {
        HashMap<Integer,String> hm = new HashMap<Integer,String>();
        hm.put(1,"SUNDAY");
        hm.put(2,"MONDAY");
        hm.put(3,"TUESDAY");
        hm.put(4,"WEDNESDAY");
        hm.put(5,"THURSDAY");
        hm.put(6,"FRIDAY");
        hm.put(7,"SATURDAY");
        Scanner in = new Scanner(System.in);
        String month = in.next();
        String day = in.next();
        String year = in.next();

        String format = year + "/" + month + "/" + day;
        Date date = null;
        try
        {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
            date = formatter.parse(format);
        }
        catch(Exception e){
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
        System.out.println(hm.get(dayOfWeek));
    }
}

Định dạng SimpleDateFormat có thể được sử dụng để định dạng Ngày theo chúng tôi. và sau đó phân tích cú pháp bên trong Đối tượng Ngày. Chương trình trên cho thấy cách nhận các ngày trong tuần bằng cách đưa ra bất kỳ ngày nào.
Ankush

-5

Tôi nghĩ ngày của bạn đến từ php và được viết bằng html (dom) hay? Tôi có một hàm php để chuẩn bị tất cả các ngày và dấu thời gian. Điều này trả lại một sự hình thành cần thiết.

$timeForJS = timeop($datetimeFromDatabase['payedon'], 'js', 'local'); // save 10/12/2016 09:20 on var

định dạng này có thể được sử dụng trên js để tạo Ngày mới ...

<html>
   <span id="test" data-date="<?php echo $timeForJS; ?>"></span>
   <script>var myDate = new Date( $('#test').attr('data-date') );</script>
</html>

Những gì tôi sẽ nói là, hãy tạo ra một chức năng riêng để bao bọc, giúp cuộc sống của bạn dễ dàng hơn. Bạn có thể cho chúng tôi func của tôi như mẫu nhưng được bao gồm trong tin nhắn của tôi, bạn không thể sao chép và dán 1 kèm 1 :)

    function timeop($utcTime, $for, $tz_output = 'system')
{
    // echo "<br>Current time ( UTC ): ".$wwm->timeop('now', 'db', 'system');
    // echo "<br>Current time (USER): ".$wwm->timeop('now', 'db', 'local');
    // echo "<br>Current time (USER): ".$wwm->timeop('now', 'D d M Y H:i:s', 'local');
    // echo "<br>Current time with user lang (USER): ".$wwm->timeop('now', 'datetimes', 'local');

    // echo '<br><br>Calculator test is users timezone difference != 0! Tested with "2014-06-27 07:46:09"<br>';
    // echo "<br>Old time (USER -> UTC): ".$wwm->timeop('2014-06-27 07:46:09', 'db', 'system');
    // echo "<br>Old time (UTC -> USER): ".$wwm->timeop('2014-06-27 07:46:09', 'db', 'local');

    /** -- */
    // echo '<br><br>a Time from db if same with user time?<br>';
    // echo "<br>db-time (2019-06-27 07:46:09) time left = ".$wwm->timeleft('2019-06-27 07:46:09', 'max');
    // echo "<br>db-time (2014-06-27 07:46:09) time left = ".$wwm->timeleft('2014-06-27 07:46:09', 'max', 'txt');

    /** -- */
    // echo '<br><br>Calculator test with other formats<br>';
    // echo "<br>2014/06/27 07:46:09: ".$wwm->ntimeop('2014/06/27 07:46:09', 'db', 'system');

    switch($tz_output){
        case 'system':
            $tz = 'UTC';
            break;

        case 'local':
            $tz = $_SESSION['wwm']['sett']['tz'];
            break;

        default:
            $tz = $tz_output;
            break;
    }

    $date = new DateTime($utcTime,  new DateTimeZone($tz));

    if( $tz != 'UTC' ) // Only time converted into different time zone
    {
        // now check at first the difference in seconds
        $offset = $this->tz_offset($tz);
        if( $offset != 0 ){
            $calc = ( $offset >= 0  ) ? 'add' : 'sub';
            // $calc = ( ($_SESSION['wwm']['sett']['tzdiff'] >= 0 AND $tz_output == 'user') OR ($_SESSION['wwm']['sett']['tzdiff'] <= 0 AND $tz_output == 'local') ) ? 'sub' : 'add';
            $offset = ['math' => $calc, 'diff' => abs($offset)];
            $date->$offset['math']( new DateInterval('PT'.$offset['diff'].'S') ); // php >= 5.3 use add() or sub()
        }
    }

    // create a individual output
    switch( $for ){
        case 'js':
            $format = 'm/d/Y H:i'; // Timepicker use only this format m/d/Y H:i without seconds // Sett automatical seconds default to 00
            break;
        case 'js:s':
            $format = 'm/d/Y H:i:s'; // Timepicker use only this format m/d/Y H:i:s with Seconds
            break;
        case 'db':
            $format = 'Y-m-d H:i:s'; // Database use only this format Y-m-d H:i:s
            break;
        case 'date':
        case 'datetime':
        case 'datetimes':
            $format = wwmSystem::$languages[$_SESSION['wwm']['sett']['isolang']][$for.'_format']; // language spezific output
            break;
        default:
            $format = $for;
            break;
    }

    $output = $date->format( $format );

    /** Replacement
     * 
     * D = day short name
     * l = day long name
     * F = month long name
     * M = month short name
     */
    $output = str_replace([
        $date->format('D'),
        $date->format('l'),
        $date->format('F'),
        $date->format('M')
    ],[
        $this->trans('date', $date->format('D')),
        $this->trans('date', $date->format('l')),
        $this->trans('date', $date->format('F')),
        $this->trans('date', $date->format('M'))
    ], $output);

    return $output; // $output->getTimestamp();
}

2
Tại sao bạn trả lời câu hỏi Java > 2 tuổi với câu trả lời bằng PHP?
Alan Hay
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.