Java วันที่และเวลา

⚡ สรุปอย่างชาญฉลาด

Java การจัดการวันที่และเวลาเป็นการผสานรวมคลาส java.util.Date และ SimpleDateFormat แบบดั้งเดิมเข้ากับ API java.time ที่ทันสมัยซึ่งเปิดตัวในเวอร์ชันใหม่ Java 8. มอบประเภทข้อมูลที่ไม่เปลี่ยนแปลงและปลอดภัยต่อการทำงานแบบมัลติเธรดให้แก่นักพัฒนา เพื่อการทำงานปฏิทินที่แม่นยำ

  • 🕒 วันที่เริ่มต้นระบบ: คลาส java.util.Date จะเก็บค่าเวลาเป็นมิลลิวินาที และแสดงผลเป็นสตริงเริ่มต้นผ่านเมธอด toString
  • 🔤 ตัวอักษรแบบแพทเทิร์น: SimpleDateFormat ใช้ตัวอักษร เช่น yyyy, MM, dd, HH, mm, ss และ zzz เพื่อกำหนดรูปแบบเอาต์พุตแบบกำหนดเอง
  • 🇧🇷 การเปรียบเทียบ: เมธอด compareTo จะส่งคืนค่าจำนวนเต็มลบ ศูนย์ หรือบวก เพื่อเรียงลำดับอินสแตนซ์ Date สองตัวตามลำดับเวลา
  • 🆕 API สมัยใหม่: LocalDate, LocalDateTime, ZonedDateTime และ Instant ใน java.time แทนที่ Date และ Calendar ด้วยอ็อบเจ็กต์ที่ไม่สามารถเปลี่ยนแปลงได้
  • 🧵 ความปลอดภัยของเกลียว: DateTimeFormatter เป็นอ็อบเจ็กต์ที่ไม่สามารถเปลี่ยนแปลงได้และปลอดภัยในการใช้งานร่วมกัน ในขณะที่ SimpleDateFormat ต้องการการซิงโครไนซ์หรือตัวห่อหุ้ม ThreadLocal
  • 🔁 ความสามารถในการทำงานร่วมกัน: แปลงข้อมูลระหว่าง API เก่าและใหม่โดยใช้ตัวช่วย Date.toInstant, Date.from และ Calendar.toInstant

Java วันที่และเวลา

การจัดการวันที่และเวลาใน Java การกำหนดวันที่เป็นส่วนหนึ่งของขั้นตอนการสร้างระบบการจัดตารางเวลา การบันทึกเวลา การสร้างรายงาน และการตรวจสอบประวัติการทำงาน ก่อนที่จะเขียนโค้ดใดๆ การรู้พารามิเตอร์ที่ประกอบขึ้นเป็นวันที่นั้นเป็นสิ่งสำคัญ:

  • การขอ ปี (เป็นตัวเลขสองหรือสี่หลัก)
  • การขอ เดือน (อาจเป็นตัวเลขสองหลัก ตัวอักษรสามตัวแรกของเดือน หรือชื่อเดือนเต็ม)
  • การขอ ข้อมูล (หมายเลขวันในเดือนจริง)
  • การขอ วัน (ชื่อวันในวันที่กำหนด เช่น อาทิตย์ จันทร์ อังคาร)

Java โปรแกรมนี้แสดงพารามิเตอร์อื่นๆ อีกมากมายที่ใช้อธิบายช่วงเวลาบนไทม์ไลน์ รวมถึงยุคสมัย สัปดาห์ในรอบปี เขตเวลา และค่าชดเชย ส่วนต่างๆ ด้านล่างจะกล่าวถึงแต่ละพารามิเตอร์พร้อมตัวอย่างที่สามารถใช้งานได้จริง

วิธีใช้วันที่ใน Java

แสดงวันที่ใน Java

Java ให้ Date ชั้นเรียนใน java.util แพ็กเกจนี้ คลาสจะจัดเก็บช่วงเวลาที่เฉพาะเจาะจงด้วยความแม่นยำระดับมิลลิวินาที และมีเมธอดช่วยในการพิมพ์ เปรียบเทียบ และจัดรูปแบบช่วงเวลานั้น หากต้องการรับวันที่และเวลาปัจจุบัน ให้สร้างอินสแตนซ์ของคลาสโดยใช้คอนสตรัคเตอร์เริ่มต้น:

import java.util.Date;

class Date_Ex1 {
    public static void main(String args[]) {
        // Instantiate a Date object by invoking its constructor
        Date objDate = new Date();
        // Display the Date and Time using toString()
        System.out.println(objDate.toString());
    }
}

Output:

Wed Nov 29 06:36:22 UTC 2017

ตัวอย่างนี้แสดงวันที่ในรูปแบบ toString ตามค่าเริ่มต้น หากต้องการแสดงเวลาเดียวกันในรูปแบบอื่น คุณต้องเข้าใจตัวอักษรการจัดรูปแบบก่อน Java การใช้งาน

SimpleDateFormat: แยกวิเคราะห์และจัดรูปแบบวันที่

การขอ SimpleDateFormat ชั้นเรียนใน java.text แปลง Date แปลงอ็อบเจ็กต์เป็นสตริงที่มีรูปแบบ และแปลงสตริงที่มีรูปแบบนั้นกลับเป็นอ็อบเจ็กต์อีกครั้ง Dateระบบนี้ใช้ตัวอักษรรูปแบบที่เชื่อมโยงกับส่วนประกอบของวันที่หรือเวลา ตารางด้านล่างแสดงรายการตัวอักษรที่รองรับทั้งหมด:

จดหมายส่วนประกอบวันที่หรือเวลาตัวอย่าง
Gผู้กำหนดยุคสมัยAD
yปี2026
Mเดือนในปีกรกฎาคม หรือ กรกฎาคม หรือ 07
wสัปดาห์ในปี27
Wสัปดาห์ในเดือน2
Dวันในปี189
dวันในเดือน10
Fวันในสัปดาห์ในเดือน2
Eชื่อวันในสัปดาห์วันอังคารหรืออังคาร
uจำนวนวันของสัปดาห์ (1 = Monday, 7 = วันอาทิตย์)1
aเครื่องหมาย AM หรือ PMPM
Hชั่วโมงต่อวัน (0-23)0
kชั่วโมงต่อวัน (1-24)24
Kชั่วโมง (เช้าหรือบ่าย) (0-11)0
hชั่วโมง (เช้าหรือบ่าย) (1-12)12
mนาทีต่อชั่วโมง30
sวินาทีในนาที55
Sมิลลิวินาที978
zเขตเวลา (ชื่อ)เวลามาตรฐานแปซิฟิก; PST; GMT-08:00
Zเขตเวลา (ค่าชดเชย RFC 822)-0800
Xเขตเวลา (ค่าชดเชย ISO 8601)-08 หรือ -0800 หรือ -08:00 น

คุณไม่จำเป็นต้องจำตารางทั้งหมด ให้ดูตารางนี้ทุกครั้งที่คุณสร้างแพทเทิร์นใหม่

วิธีใช้งาน SimpleDateFormat

SimpleDateFormat เป็นคลาสย่อยของ DateFormat ซึ่งช่วยให้คุณจัดรูปแบบและแยกวิเคราะห์วันที่โดยใช้ตัวอักษรตามรูปแบบด้านบน รวมตัวอักษรเข้าด้วยกันเพื่อสร้างหรืออ่านข้อความที่ต้องการได้อย่างแม่นยำ

ตัวอย่างเช่น:

  1. ต้องระบุรูปแบบวันที่: 2012.10.23 น. 20 20:45:XNUMX น. ตามเวลาแปซิฟิกรูปแบบที่เหมาะสมคือ yyyy.MM.dd HH:mm:ss zzz.
  2. ต้องระบุรูปแบบวันที่: 09:30:00 AM 23-May-2012รูปแบบที่เหมาะสมคือ hh:mm:ss a dd-MMM-yyyy.

เคล็ดลับ: ดูตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก M คือเดือน ตัวพิมพ์เล็ก m เล็กมาก ตัวพิมพ์ใหญ่ H เป็นนาฬิกา 24 ชั่วโมง ตัวพิมพ์เล็ก h เป็นนาฬิกา 12 ชั่วโมง การสลับเวลาจะทำให้เกิดผลลัพธ์ที่ผิดพลาดโดยไม่มีการแจ้งเตือน

โปรแกรมด้านล่างนี้จะพิมพ์วันที่ปัจจุบันสองครั้ง ครั้งแรกในรูปแบบมาตรฐาน และครั้งที่สองโดยใช้รูปแบบ SimpleDateFormat:

import java.text.SimpleDateFormat;
import java.util.Date;

class TestDates_Format {
    public static void main(String args[]) {
        // Current system date and time is assigned to objDate
        Date objDate = new Date();
        System.out.println(objDate);

        // Build the target pattern and format the date
        String strDateFormat = "hh:mm:ss a dd-MMM-yyyy";
        SimpleDateFormat objSDF = new SimpleDateFormat(strDateFormat);
        System.out.println(objSDF.format(objDate));
    }
}

Output:

Wed Nov 29 06:31:41 UTC 2017
06:31:41 AM 29-Nov-2017

ตัวอย่างการเปรียบเทียบวันที่

ตัวอย่างการเปรียบเทียบวันที่

วิธีที่น่าเชื่อถือที่สุดในการสั่งซื้อสองชิ้น Date วัตถุคือ compareTo() เมธอดนี้จะคืนค่าจำนวนเต็มลบเมื่อเวลาของผู้เรียกใช้มาก่อน ค่าศูนย์เมื่อเวลาทั้งสองเท่ากัน และค่าจำนวนเต็มบวกเมื่อเวลาของผู้เรียกใช้มาทีหลัง โค้ดด้านล่างนี้จะแยกวิเคราะห์สตริงวันที่สองสตริงและพิมพ์ลำดับสัมพัทธ์ของวันที่เหล่านั้น:

import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;

class TestDates_Compare {
    public static void main(String args[]) throws ParseException {

        SimpleDateFormat objSDF = new SimpleDateFormat("dd-MM-yyyy");
        Date dt_1 = objSDF.parse("20-08-1981");
        Date dt_2 = objSDF.parse("12-10-2012");

        System.out.println("Date1 : " + objSDF.format(dt_1));
        System.out.println("Date2 : " + objSDF.format(dt_2));

        // compareTo returns > 0 when dt_1 is after dt_2
        if (dt_1.compareTo(dt_2) > 0) {
            System.out.println("Date 1 occurs after Date 2");
        }
        // compareTo returns < 0 when dt_1 is before dt_2
        else if (dt_1.compareTo(dt_2) < 0) {
            System.out.println("Date 1 occurs before Date 2");
        }
        // compareTo returns 0 when both dates are equal
        else {
            System.out.println("Both are the same date");
        }
    }
}

Output:

Date1 : 20-08-1981
Date2 : 12-10-2012
Date 1 occurs before Date 2

หมายเหตุ โค้ดต้นฉบับใช้รูปแบบดังกล่าว dd-mm-yyyyตัวพิมพ์เล็ก mm ตัวอักษรคือนาที ไม่ใช่เดือน ดังนั้นตัวแยกวิเคราะห์จึงแสดงค่าเดือนที่ไม่ถูกต้องโดยไม่แจ้งให้ทราบ การแก้ไขข้างต้นใช้ตัวพิมพ์ใหญ่ MM สำหรับเดือนนั้น ตัวอักษรใดคือแบบแผนที่ถูกต้อง

Java 8. API วันที่และเวลาสมัยใหม่ (java.time)

Java 8 ได้แนะนำ java.time แพ็กเกจนี้คือ API ที่ได้รับการออกแบบใหม่ โดยได้รับแรงบันดาลใจจากไลบรารี Joda-Time คลาสใหม่เหล่านี้เป็นแบบไม่เปลี่ยนแปลง (immutable) ปลอดภัยต่อการทำงานแบบมัลติเธรด (thread-safe) และแยกปฏิทินของมนุษย์ออกจากไทม์ไลน์ของเครื่อง ประเภทที่พบบ่อยที่สุด ได้แก่:

  • LocalDate สำหรับวันนัดหมายที่ไม่ได้ระบุเวลาหรือเขตเวลา (เช่น วันเกิด)
  • LocalTime สำหรับเวลาที่แสดงบนนาฬิกาติดผนังโดยไม่มีวันที่หรือโซนเวลา
  • LocalDateTime สำหรับวันที่และเวลาที่ไม่ระบุโซนเวลา
  • ZonedDateTime สำหรับวันที่และเวลาที่ระบุเขตเวลาที่แน่นอน
  • OffsetDateTime สำหรับวันที่และเวลาที่มีค่าชดเชย UTC แต่ไม่มีชื่อโซนเวลา
  • Instant สำหรับการประทับเวลาของเครื่องที่วัดจากยุค UNIX
  • Duration และ Period สำหรับจำนวนเงินที่คำนวณตามเวลาและวันที่

ตัวอย่างด้านล่างนี้แสดงวันที่ปัจจุบัน เวลา เวลาประทับ และเขตเวลา โดยใช้ API รุ่นใหม่:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.Instant;
import java.time.ZoneId;

class ModernDateDemo {
    public static void main(String args[]) {
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();
        ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
        Instant epoch = Instant.now();

        System.out.println("LocalDate     : " + today);
        System.out.println("LocalDateTime : " + now);
        System.out.println("ZonedDateTime : " + zoned);
        System.out.println("Instant       : " + epoch);
    }
}

แต่ละประเภทมีวิธีการผลิตในโรงงาน (now, of, parse) และการดำเนินการที่ไม่สามารถเปลี่ยนแปลงได้ (plusDays, minusHours, withYear) ซึ่งจะส่งคืนค่าใหม่แทนที่จะเปลี่ยนแปลงอ็อบเจ็กต์เดิม

DateTimeFormatter: จัดรูปแบบวันที่ในรูปแบบสมัยใหม่ Java

DateTimeFormatter in java.time.format แทนที่ SimpleDateFormatมันใช้รูปแบบตัวอักษรแบบเดียวกัน ไม่สามารถเปลี่ยนแปลงได้ และปลอดภัยที่จะแชร์ข้ามเธรดโดยไม่ต้องซิงโครไนซ์เพิ่มเติม คลาสนี้ยังเปิดเผยค่าคงที่สำเร็จรูป เช่น ISO_LOCAL_DATE และ ISO_ZONED_DATE_TIME สำหรับรูปแบบมาตรฐาน

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

class FormatterDemo {
    public static void main(String args[]) {
        LocalDateTime now = LocalDateTime.now();

        DateTimeFormatter iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        DateTimeFormatter human = DateTimeFormatter.ofPattern("hh:mm:ss a dd-MMM-yyyy");

        System.out.println(now.format(iso));
        System.out.println(now.format(human));

        LocalDateTime parsed = LocalDateTime.parse("2026-07-04T09:30:00", iso);
        System.out.println("Parsed back : " + parsed);
    }
}

ในการเปรียบเทียบวันที่สองวันใน API รุ่นใหม่ ให้เรียกใช้คำสั่งต่อไปนี้ isBefore, isAfterหรือ isEqualวิธีการเหล่านี้อ่านเข้าใจง่ายกว่า compareTo และทำงานร่วมกับทุกๆ java.time ชั้นเรียน

ความปลอดภัยของเกลียวและแนวปฏิบัติที่ดีที่สุดสำหรับ Java วันที่และเวลา

ทั้งสอง java.util.Date และ SimpleDateFormat มาก่อนยุคปัจจุบัน Javaและแต่ละวิธีก็มีข้อเสียที่ทราบกันดีอยู่แล้ว ปฏิบัติตามแนวทางด้านล่างนี้เพื่อให้การจัดการข้อมูลในโค้ดที่ใช้งานจริงถูกต้อง:

  • ควรเลือกใช้ java.time แทน Date และ Calendar ประเภทข้อมูลใหม่เหล่านี้ไม่สามารถเปลี่ยนแปลงได้ ปลอดภัยต่อการใช้งานแบบมัลติเธรด และจำลองโดเมนได้อย่างแม่นยำยิ่งขึ้น (เช่น วันที่โดยไม่มีเวลา เวลาโดยไม่มีโซนเวลา เป็นต้น)
  • ห้ามใช้ SimpleDateFormat ร่วมกันในเธรดต่างๆ คลาสนี้เก็บสถานะการแยกวิเคราะห์ภายในและไม่ปลอดภัยต่อการใช้งานแบบมัลติเธรด ควรห่อหุ้มไว้ใน ThreadLocalซิงโครไนซ์บนอินสแตนซ์ หรือเปลี่ยนไปใช้ DateTimeFormatter.
  • ระบุภาษาท้องถิ่นเสมอ ชื่อเดือนและวันจะเปลี่ยนแปลงไปตามการตั้งค่าภาษาเริ่มต้นของ JVM ซึ่งทำให้รูปแบบต่างๆ เช่น MMM และ EEE ไม่สามารถพกพาได้ ต้องระบุภาษาอย่างชัดเจน (ตัวอย่างเช่น Locale.ENGLISH).
  • ระบุเขตเวลาให้ชัดเจน LocalDateTime ไม่มีโซน ดังนั้นแปลงเป็น ZonedDateTime or Instant เมื่อใดก็ตามที่จังหวะเวลาที่แน่นอนมีความสำคัญ โดยเฉพาะอย่างยิ่งสำหรับบันทึกข้อมูล คอลัมน์ฐานข้อมูล และข้อมูลที่ส่งผ่านเครือข่าย
  • ควรแปลงข้อมูลระหว่าง API ทั้งสองอย่างระมัดระวัง ใช้ date.toInstant(), Date.from(instant)และ calendar.toInstant().atZone(zone) ตรงรอยต่อระหว่างโค้ดเก่าและโค้ดใหม่
  • บันทึกเวลาในรูปแบบ UTC อดทนและ transmit วันที่ในรูปแบบ UTC (an) Instant หรือสตริง ISO 8601) และแปลงเป็นโซนผู้ใช้เฉพาะเมื่อแสดงผลเท่านั้น

คำถามที่พบบ่อย

เรียกใช้ LocalDateTime.now() จากแพ็กเกจ java.time เพื่อดูวันที่และเวลาในโซนเวลาของระบบ หรือเรียกใช้ LocalDate.now() เพื่อดูเฉพาะวันที่เท่านั้น สำหรับระบบปฏิบัติการรุ่นเก่ากว่า Javaใช้ `new java.util.Date()` เพื่อรับเวลาปัจจุบัน

java.util.Date แสดงเวลาเป็นมิลลิวินาทีตั้งแต่ยุคเริ่มต้น และสามารถเปลี่ยนแปลงได้ ในขณะที่ LocalDate จำลองวันที่ตามปฏิทินโดยไม่มีเวลาหรือเขตเวลา ไม่สามารถเปลี่ยนแปลงได้ ปลอดภัยต่อการใช้งานแบบมัลติเธรด และมีเมธอดที่ชัดเจนกว่า เช่น plusDays และ isBefore

ไม่ SimpleDateFormat เก็บสถานะการแยกวิเคราะห์ที่เปลี่ยนแปลงได้ และจะให้ผลลัพธ์ที่ไม่ถูกต้องเมื่อใช้ร่วมกันระหว่างเธรด ควรห่อหุ้มด้วย ThreadLocal, ซิงโครไนซ์บนอินสแตนซ์ หรือเปลี่ยนไปใช้ DateTimeFormatter ซึ่งไม่สามารถเปลี่ยนแปลงได้และปลอดภัยกว่า

ระบุสตริงที่ถูกต้องคือ “yyyy-MM-dd” โดยตัวอักษร MM ตัวใหญ่คือเดือน และตัวอักษร mm ตัวเล็กคือนาที สำหรับวันที่และเวลาแบบเต็ม ให้ใช้ “yyyy-MM-dd HH:mm:ss” ควรระบุ Locale เสมอเพื่อให้ชื่อเดือนมีความสม่ำเสมอ

สำหรับคลาส Date แบบดั้งเดิม ให้ใช้ compareTo ซึ่งจะส่งค่ากลับมาเป็นจำนวนเต็มลบ ศูนย์ หรือบวก ส่วนสำหรับคลาส java.time ให้เรียกใช้ isBefore, isAfter หรือ isEqual กับ LocalDate หรือ Instant ทั้งสองวิธีนี้จะคำนึงถึงลำดับเวลา

เรียกใช้ date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() หากต้องการย้อนกลับ ให้ใช้ Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()) เลือกโซนเวลาอย่างชัดเจนเมื่อใดก็ตามที่ต้องการระบุเวลาที่แน่นอน

โมเดล AI ที่ได้รับการฝึกฝนจากชุดข้อมูลบันทึกและเอกสารจะอนุมานรูปแบบที่น่าจะเป็นไปได้จากสตริงตัวอย่างและส่งคืนรูปแบบ DateTimeFormatter ที่ตรงกัน ตัวจำแนกประเภทการเรียนรู้ของเครื่องยังระบุฟิลด์ที่ไม่ชัดเจน เช่น ลำดับเดือน-วัน เทียบกับ วัน-เดือน

ใช่แล้ว GitHub Copilot แนะนำรูปแบบ DateTimeFormatter, การแปลง ZonedDateTime และอื่นๆ JUnit การทดสอบสำหรับผลลัพธ์ที่คำนึงถึงภาษาท้องถิ่น Revโปรดตรวจสอบคำแนะนำแต่ละข้อเพื่อดูตัวอักษรรูปแบบที่ถูกต้อง สถานที่ และเขตเวลา ก่อนตัดสินใจเลือก

สรุปโพสต์นี้ด้วย: