อธิบาย Java LocalDate: คู่มือครบวงจรการจัดการวันที่ใน Java 8 และรุ่นต่อไป

目次

LocalDate คืออะไร?

การจัดการวันที่ใน Java ได้พัฒนาอย่างมากตั้งแต่เวอร์ชัน 8 ใจกลางของการพัฒนานี้คือ LocalDate LocalDate เป็นออบเจ็กต์ที่ไม่สามารถเปลี่ยนแปลงได้ซึ่งแทนเฉพาะวันที่ (ปี, เดือน, และวัน, เช่น 2025-06-26) โดยไม่มีแนวคิดของเวลา หรือเขตเวลา มันช่วยให้คุณจัดการวันที่ปัจจุบันหรือวันที่ปฏิทินเฉพาะในลักษณะที่เรียบง่ายและปลอดภัย

ความแตกต่างจากคลาสจัดการวันที่แบบเก่า

ก่อน Java 8 คลาสเช่น java.util.Date และ java.util.Calendar ถูกใช้กันอย่างแพร่หลาย อย่างไรก็ตาม คลาสเหล่านี้มีปัญหาหลายประการ รวมถึง การออกแบบที่เสี่ยงต่อข้อผิดพลาด (เช่น เดือนที่เริ่มจากศูนย์) ขาดความปลอดภัยในเธรด และ API ที่ไม่ intuitive ส่งผลให้มักเกิดบั๊กหรือพฤติกรรมที่ไม่คาดคิด

LocalDate แก้ไขปัญหาเหล่านี้และนำเสนอคุณสมบัติดังต่อไปนี้:

  • การจัดการปี, เดือน, และวันอย่างชัดเจนเท่านั้น (เช่น 26 มิถุนายน 2025)
  • ออบเจ็กต์ที่ไม่สามารถเปลี่ยนแปลงได้ (ค่าที่ไม่สามารถเปลี่ยนแปลงได้ เพื่อความปลอดภัย)
  • ชื่อเมธอดและการออกแบบ API ที่ intuitive (เช่น plusDays(1) สำหรับวันถัดไป, getMonthValue() สำหรับหมายเลขเดือน)
  • ไม่ขึ้นกับเขตเวลา (พฤติกรรมที่สอดคล้องกันโดยไม่คำนึงถึงการตั้งค่าระบบหรือเซิร์ฟเวอร์)

เมื่อใดควรใช้ LocalDate?

LocalDate เหมาะสมเมื่อคุณต้องการจัดการวันที่อย่างชัดเจน ไม่ต้องการข้อมูลเวลา และต้องการดำเนินการวันที่อย่างปลอดภัยและง่ายดาย กรณีการใช้งานทั่วไป ได้แก่:

  • การบันทึกวันที่โดยไม่มีเวลา เช่น วันเกิดหรือวันครบรอบ
  • การจัดการตารางเวลา กำหนดการส่งงาน และวันครบกำหนด
  • การคำนวณวันครบกำหนดหรือจำนวนวันคงเหลือ

ด้วยเหตุผลเหล่านี้ LocalDate สามารถถือเป็น มาตรฐานใหม่สำหรับการจัดการวันที่ใน Java ในส่วนถัดไป เราจะอธิบายการใช้งานพื้นฐานและการเริ่มต้นของ LocalDate อย่างละเอียด

การดำเนินการพื้นฐานกับ LocalDate

LocalDate ให้ API ที่ intuitive และเรียบง่ายสำหรับการจัดการวันที่ ส่วนนี้จะอธิบายคุณสมบัติที่ใช้กันทั่วไปพร้อมตัวอย่างที่เป็นรูปธรรม

การรับวันที่ปัจจุบัน

เพื่อรับวันที่วันนี้ ให้ใช้เมธอด LocalDate.now() มันจะคืนค่าประวันที่ปัจจุบันของระบบ (ไม่ขึ้นกับเขตเวลา) เป็นอินสแตนซ์ของ LocalDate

import java.time.LocalDate;

LocalDate today = LocalDate.now();
System.out.println(today); // Example: 2025-06-26

การสร้างวันที่เฉพาะ

เพื่อสร้างวันที่任意ในอดีตหรืออนาคต ให้ใช้ LocalDate.of(int year, int month, int dayOfMonth) สิ่งนี้ช่วยให้คุณสร้างวันที่ได้อย่างอิสระ เช่น 31 ธันวาคม 2024

LocalDate specialDay = LocalDate.of(2024, 12, 31);
System.out.println(specialDay); // 2024-12-31

การแยกวิเคราะห์วันที่จากสตริง

เพื่อสร้าง LocalDate จากสตริงเช่น “2023-03-15” ให้ใช้เมธอด LocalDate.parse(String text) หากสตริงเป็นไปตามรูปแบบ ISO มาตรฐาน (“YYYY-MM-DD”) ไม่จำเป็นต้องกำหนดค่าพิเศษเพิ่มเติม

LocalDate parsedDate = LocalDate.parse("2023-03-15");
System.out.println(parsedDate); // 2023-03-15

การแยกวิเคราะห์ด้วยรูปแบบที่กำหนดเอง (ส่วนเสริม)

หากคุณจำเป็นต้องจัดการวันที่ในรูปแบบที่กำหนดเอง เช่น “2023/03/15” คุณสามารถรวม DateTimeFormatter กับ parse()

import java.time.format.DateTimeFormatter;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate formattedDate = LocalDate.parse("2023/03/15", formatter);
System.out.println(formattedDate); // 2023-03-15

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

การดึงปี, เดือน, วัน, และวันในสัปดาห์

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

การรับปี, เดือน, และวัน

เพื่อดึงแต่ละส่วนประกอบจากอินสแตนซ์ของ LocalDate ให้ใช้เมธอด getter ที่ทุ่มเท

.

LocalDate date = LocalDate.of(2025, 6, 26);

int year = date.getYear();           // Year (e.g. 2025)
int month = date.getMonthValue();    // Month as a number (1–12, e.g. 6)
int day = date.getDayOfMonth();      // Day of month (1–31, e.g. 26)

System.out.println("Year: " + year);
System.out.println("Month: " + month);
System.out.println("Day: " + day);

การรับชื่อเดือนและวันในสัปดาห์

LocalDate ยังรองรับการดึงชื่อเดือนและวันในสัปดาห์ ซึ่งเป็นประโยชน์เมื่อคุณต้องการตัวแทนข้อความ

  • ชื่อเดือน (การแสดงผลเป็นภาษาอังกฤษ) การใช้ getMonth() จะคืนค่า enum ของ Month (เช่น JUNE).
    import java.time.Month;
    
    Month monthName = date.getMonth(); // JUNE (uppercase English)
    System.out.println(monthName);
    
  • ชื่อวันในสัปดาห์ getDayOfWeek() จะคืนค่า enum ของ DayOfWeek (เช่น THURSDAY).
    import java.time.DayOfWeek;
    
    DayOfWeek dayOfWeek = date.getDayOfWeek(); // THURSDAY (uppercase English)
    System.out.println(dayOfWeek);
    

การแสดงชื่อเดือนและวันในสัปดาห์เป็นภาษาญี่ปุ่น

หากคุณต้องการแสดงชื่อเดือนหรือวันในสัปดาห์เป็นภาษาญี่ปุ่นแทนภาษาอังกฤษ คุณสามารถปรับแต่งผลลัพธ์โดยใช้ DateTimeFormatter.

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

DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("yyyy年MM月dd日(E)", Locale.JAPANESE);
String formatted = date.format(formatter); // 2025年06月26日(木)
System.out.println(formatted);

สรุปส่วนประกอบที่ดึงมาได้

หนึ่งในจุดแข็งหลักของ LocalDate คือการที่คุณสามารถดึง ปี, เดือน, วัน, และวันในสัปดาห์ ด้วยวิธีที่เข้าใจง่าย ความยืดหยุ่นนี้ทำให้การจัดการวันที่ในแอปพลิเคชันธุรกิจและเว็บเป็นเรื่องง่ายขึ้นมาก.

การคำนวณวันที่ (การบวกและการลบ)

การคำนวณวันที่ เช่น การเพิ่มหรือการลบวัน มักจำเป็นสำหรับการจัดการตารางเวลาและการคำนวณกำหนดเวลา ด้วย LocalDate คุณสามารถทำการดำเนินการเหล่านี้ได้อย่างปลอดภัยและเป็นธรรมชาติ เช่น “สามวันต่อมา”, “หนึ่งสัปดาห์ก่อนหน้า”, หรือ “ความแตกต่างระหว่างสองวันที่”.

การเพิ่มวันที่

  • การเพิ่มวัน
    LocalDate today = LocalDate.of(2025, 6, 26);
    LocalDate threeDaysLater = today.plusDays(3); // Three days later
    System.out.println(threeDaysLater); // 2025-06-29
    
  • การเพิ่มเดือนหรือปี
    LocalDate nextMonth = today.plusMonths(1); // One month later
    LocalDate nextYear = today.plusYears(1);   // One year later
    System.out.println(nextMonth); // 2025-07-26
    System.out.println(nextYear);  // 2026-06-26
    

การลบวันที่

  • การลบวัน, เดือน, หรือปี
    LocalDate lastWeek = today.minusWeeks(1);   // One week earlier
    LocalDate previousDay = today.minusDays(1); // Previous day
    System.out.println(lastWeek);    // 2025-06-19
    System.out.println(previousDay); // 2025-06-25
    

การคำนวณความแตกต่างระหว่างวันที่

  • คำนวณความแตกต่างเป็นวัน
    import java.time.temporal.ChronoUnit;
    
    LocalDate start = LocalDate.of(2025, 6, 1);
    LocalDate end = LocalDate.of(2025, 6, 26);
    
    long daysBetween = ChronoUnit.DAYS.between(start, end); // 25
    System.out.println(daysBetween); // 25
    
  • คำนวณความแตกต่างโดยใช้หน่วยอื่น (เดือน, ปี)
    long monthsBetween = ChronoUnit.MONTHS.between(start, end); // 0
    long yearsBetween = ChronoUnit.YEARS.between(start, end);   // 0
    

สรุป

โดยการใช้เมธอดการบวกและลบของ LocalDate คุณสามารถนำไปใช้ในการคำนวณวันที่ทั่วไปได้อย่างง่ายดาย เช่น “กำหนดเวลาของเดือนถัดไป” หรือ “จำนวนวันตั้งแต่เหตุการณ์ล่าสุด”.

เนื่องจาก LocalDate เป็นอิมมูทาเบิล (immutable) อินสแตนซ์ต้นฉบับจะไม่ถูกแก้ไข ทุกการดำเนินการจะคืนค่าอินสแตนซ์ LocalDate ใหม่ ทำให้การจัดการวันที่ปลอดภัย.

การดำเนินการขั้นสูง: ปรับเปลี่ยนวันที่เฉพาะเจาะจง

ในการจัดการวันที่ในโลกจริง การบวกหรือการลบอย่างง่ายมักไม่เพียงพอ ความต้องการทั่วไปรวมถึงการกำหนด “วันสุดท้ายของเดือน” หรือ “วันแรกของเดือนถัดไป” LocalDate มี API ที่สะดวกสำหรับการปรับเปลี่ยนประเภทนี้.

การใช้ TemporalAdjuster

ด้วย LocalDate คุณสามารถผสานเมธอด with() และ TemporalAdjuster เพื่อทำการดำเนินการที่เข้าใจง่าย เช่น “สิ้นเดือน”, “ต้นเดือน”, หรือ “วันทำงานเฉพาะวันถัดไป” Adjuster ที่มีให้ใช้แล้วจะอยู่ในคลาส TemporalAdjusters.

การรับวันแรกและวันสุดท้ายของเดือน

  • การรับวันสุดท้ายของเดือน
    import java.time.LocalDate;
    import java.time.temporal.TemporalAdjusters;
    
    LocalDate date = LocalDate.of(2025, 6, 26);
    LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println(endOfMonth); // 2025-06-30
    
  • การรับวันแรกของเดือน
    LocalDate startOfMonth = date.with(TemporalAdjusters.firstDayOfMonth());
    System.out.println(startOfMonth); // 2025-06-01
    

การปรับตามวันในสัปดาห์

การปรับตามวันในสัปดาห์—เช่น “วันจันทร์ที่สองของเดือน” หรือ “วันศุกร์ถัดไป”—ก็ทำได้ง่ายเช่นกัน

  • การรับวันศุกร์ถัดไป
    import java.time.DayOfWeek;
    
    LocalDate nextFriday =
        date.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
    System.out.println(nextFriday); // 2025-06-27
    
  • การรับวันจันทร์ที่สองของเดือนปัจจุบัน
    LocalDate secondMonday =
        date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY));
    System.out.println(secondMonday); // 2025-06-09
    

การปรับให้เป็นจุดเริ่มต้นหรือจุดสิ้นสุดของปี

คุณสามารถใช้วิธีเดียวกันเพื่อดึงวันแรกหรือวันสุดท้ายของปีได้

LocalDate startOfYear =
    date.with(TemporalAdjusters.firstDayOfYear());
LocalDate endOfYear =
    date.with(TemporalAdjusters.lastDayOfYear());

System.out.println(startOfYear); // 2025-01-01
System.out.println(endOfYear);   // 2025-12-31

การสร้าง Adjuster ที่กำหนดเอง

หากคุณต้องการตรรกะการปรับวันที่แบบกำหนดเองตามกฎธุรกิจเฉพาะ คุณสามารถทำการ implement อินเทอร์เฟซ TemporalAdjuster ด้วยตนเองได้

โดยการผสาน LocalDate กับ TemporalAdjusters แม้การคำนวณวันที่ที่ซับซ้อนก็จะกลายเป็นเรื่องเข้าใจง่ายและยืดหยุ่น ซึ่งมีประโยชน์อย่างยิ่งเมื่อจัดการกับกำหนดเวลา หรือกำหนดการเฉพาะของธุรกิจ

การทำงานกับ LocalDate และ LocalDateTime

ใน Java Date and Time API (แพคเกจ java.time) LocalDate แทนวันที่เท่านั้น ส่วน LocalDateTime แทนทั้งวันที่และเวลา ในการปฏิบัติ นักพัฒนามักต้องแปลงระหว่างสองประเภทนี้ ส่วนนี้อธิบายวิธีทำการแปลงเหล่านั้น

การแปลง LocalDate เป็น LocalDateTime

เพื่อเพิ่มข้อมูลเวลาให้กับ LocalDate และแปลงเป็น LocalDateTime ให้ใช้ atTime() หรือ atStartOfDay()

  • การเพิ่มเวลาเฉพาะ
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    
    LocalDate date = LocalDate.of(2025, 6, 26);
    LocalDateTime dateTime =
        date.atTime(14, 30, 0); // 2025-06-26 14:30:00
    System.out.println(dateTime);
    
  • การสร้าง LocalDateTime ที่จุดเริ่มต้นของวัน
    LocalDateTime startOfDay =
        date.atStartOfDay(); // 2025-06-26T00:00
    System.out.println(startOfDay);
    

การแปลง LocalDateTime เป็น LocalDate

เพื่อดึงเฉพาะส่วนของวันที่จาก LocalDateTime ให้ใช้เมธอด toLocalDate()

import java.time.LocalDateTime;

LocalDateTime dateTime =
    LocalDateTime.of(2025, 6, 26, 14, 30);
LocalDate dateOnly = dateTime.toLocalDate();
System.out.println(dateOnly); // 2025-06-26

การรวม LocalDate กับ LocalTime

คุณยังสามารถผสาน LocalDate กับ LocalTime เพื่อสร้าง LocalDateTime ได้

import java.time.LocalTime;

LocalTime time = LocalTime.of(9, 0);
LocalDateTime combined =
    date.atTime(time); // 2025-06-26T09:00
System.out.println(combined);

สรุป

  • แปลง LocalDate เป็น LocalDateTime ด้วย atTime() หรือ atStartOfDay()
  • แปลง LocalDateTime เป็น LocalDate ด้วย toLocalDate()
  • การแยกและผสานวันที่กับเวลาเป็นเรื่องทั่วไปในระบบจริง

การจัดการข้อยกเว้นและแนวปฏิบัติที่ดีที่สุด

.Date handling can easily lead to unexpected exceptions if invalid values or formats are used. Even when working with LocalDate, exceptions may occur due to non-existent dates or parsing errors. This section explains common exceptions and best practices for handling them safely.

การระบุวันที่ที่ไม่มีอยู่จริง

If you attempt to create a date that does not exist—such as February 30, 2023— a DateTimeException will be thrown.

import java.time.LocalDate;

// Example that throws an exception
LocalDate invalidDate = LocalDate.of(2023, 2, 30);

In such cases, it is important to catch the exception and handle it appropriately.

try {
    LocalDate invalidDate = LocalDate.of(2023, 2, 30);
} catch (DateTimeException e) {
    System.out.println("An invalid date was specified: " + e.getMessage());
}

ข้อยกเว้นระหว่างการแปลงสตริง

When using LocalDate.parse(), a DateTimeParseException is thrown if the string format is invalid or the date itself does not exist.

import java.time.format.DateTimeParseException;

try {
    LocalDate date = LocalDate.parse("2023/02/30");
} catch (DateTimeParseException e) {
    System.out.println("Failed to parse date: " + e.getMessage());
}

แนวปฏิบัติที่ดีที่สุด

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

ข้อผิดพลาดทั่วไป

  • การจัดการ 29 กุมภาพันธ์ในปีอธิกสุรทิน
  • การระบุค่าที่อยู่นอกช่วงที่ถูกต้อง (เช่น เดือน = 13, วัน = 0)
  • รูปแบบที่ไม่ตรงกันระหว่างการแปลงสตริง

These issues are especially common among beginners, so extra care is required.

ตัวอย่างการใช้งานจริงของ LocalDate

LocalDate is not limited to simple date storage—it is widely used in real-world business systems and applications. Below are several practical examples.

การคำนวณวันเกิดและอายุ

Calculating a person’s age based on their birth date is a classic use case. Using LocalDate together with Period makes this easy.

import java.time.LocalDate;
import java.time.Period;

LocalDate birthDay = LocalDate.of(1990, 8, 15);
LocalDate today = LocalDate.now();

Period period = Period.between(birthDay, today);
int age = period.getYears();
System.out.println("Age: " + age);

การจัดการกำหนดเวลาและวันครบกำหนด

LocalDate is also useful for task management systems, such as calculating how many days remain until a deadline.

LocalDate deadline = LocalDate.of(2025, 7, 10);
long daysLeft =
    java.time.temporal.ChronoUnit.DAYS.between(today, deadline);

System.out.println("Days remaining until deadline: " + daysLeft);

การกำหนดเวลาและการสร้างปฏิทิน

Requirements such as “a meeting on the second Monday of every month” can be implemented easily using TemporalAdjusters.

import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate secondMonday =
    LocalDate.of(2025, 7, 1)
        .with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY));

System.out.println("Second Monday of July: " + secondMonday);

การตรวจสอบวันที่ในระบบเว็บและ API

LocalDate is frequently used in backend systems for validating date input. For example, you may want to reject future dates or dates older than a certain range.

LocalDate inputDate = LocalDate.parse("2024-12-31");
LocalDate tenYearsAgo = today.minusYears(10);

if (inputDate.isAfter(today)) {
    System.out.println("Future dates are not allowed");
} else if (inputDate.isBefore(tenYearsAgo)) {
    System.out.println("Please specify a date within the last 10 years");
} else {
    System.out.println("The date is valid");
}

Adoption in Training and Production Systems

As seen in many competing articles, LocalDate is now a standard topic in Java training programs and onboarding curricula. It is also widely used in production systems such as banking business-day calculations and inventory management.

FAQ (Frequently Asked Questions)

Q1. What is the difference between LocalDate and Date?

A.
LocalDate is part of the modern Java Date and Time API introduced in Java 8 and represents only a date (year, month, day). java.util.Date, on the other hand, is a legacy class that includes time and internally manages values in milliseconds.

LocalDate is immutable, intuitive, and thread-safe, and is recommended for modern Java development.

Q2. Can LocalDate handle time zones?

A.
LocalDate itself does not contain time zone information. If time zone support is required, use ZonedDateTime or OffsetDateTime. A common approach is to manage dates with LocalDate first, then convert when time zones become necessary.

Q3. What is the difference between LocalDate and LocalDateTime?

A.
LocalDate represents only a date. LocalDateTime represents both date and time (e.g. 2025-06-26 14:00). Use LocalDate for deadlines or anniversaries, and LocalDateTime for events with precise timestamps.

Q4. Can I parse custom date formats?

A.
Yes. By using DateTimeFormatter, you can parse dates in custom formats.

import java.time.format.DateTimeFormatter;

DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date =
    LocalDate.parse("2025/06/26", formatter);

Q5. How should I handle invalid dates or formats?

A.
Invalid dates or formats cause exceptions such as DateTimeException or DateTimeParseException. Use try-catch blocks, validate input in advance, and provide clear error messages to users.

Q6. Can I compare two LocalDate instances?

A.
Yes. Use isAfter(), isBefore(), or isEqual().

LocalDate date1 = LocalDate.of(2025, 6, 26);
LocalDate date2 = LocalDate.of(2025, 7, 1);

if (date1.isBefore(date2)) {
    System.out.println("date1 is earlier than date2");
}

Conclusion

This article provided a comprehensive explanation of Java LocalDate, from basic concepts to advanced use cases. Key points include:

  • What LocalDate is An immutable date-only object introduced in Java 8 that fixes the flaws of legacy Date and Calendar classes.
  • Basic usage Retrieving the current date, creating specific dates, and parsing strings using simple APIs.
  • Extracting components Easily retrieving year, month, day, and weekday values.
  • Date calculations Intuitive addition, subtraction, and difference calculations.
  • Date adjustments Using TemporalAdjusters to handle end-of-month, weekdays, and more.
  • Integration with time APIs Flexible conversion between LocalDate, LocalDateTime, and LocalTime.
  • Safe handling and best practices Proper exception handling and validation for robust systems.
  • Real-world applications and FAQs Practical examples such as age calculation, deadlines, scheduling, and validation.

Next Steps

Once you master LocalDate, date handling becomes straightforward and reliable. For more advanced scenarios—such as time zones, period calculations, and formatting—consider learning ZonedDateTime, Period, and DateTimeFormatter.

Use LocalDate as a powerful foundation to build clean, robust, and maintainable Java applications.