CodeGym /Kursy /JAVA 25 SELF /Formatowanie i parsowanie dat: DateTimeFormatter

Formatowanie i parsowanie dat: DateTimeFormatter

JAVA 25 SELF
Poziom 13 , Lekcja 4
Dostępny

1. DateTimeFormatter: co to jest i po co jest potrzebny

W rzeczywistych programach daty rzadko żyją wyłącznie w kodzie. Zazwyczaj trzeba je:

  • Konwertować na napis do wypisania w konsoli, na ekran lub do pliku (np. "01.06.2025 14:30").
  • Parsować napis, czyli przekształcać łańcuch wprowadzony przez użytkownika lub wczytany z pliku z powrotem na obiekt daty/czasu.

Do tego w Javie istnieje potężne i wygodne narzędzie — klasa java.time.format.DateTimeFormatter.

Można powiedzieć, że DateTimeFormatter to tłumacz między obiektami czasu (LocalDate, LocalDateTime, ZonedDateTime, Instant itd.) a napisami. Potrafi:

  • Przekształcać obiekty dat/czasu w napisy w żądanym formacie (format — formatowanie).
  • Przekształcać napisy w obiekty dat/czasu (parse — parsowanie).

2. Standardowe formatery: szybko i prosto

Java przygotowała dla nas zestaw standardowych formaterów, które obejmują najpopularniejsze formaty ISO (międzynarodowe standardy dla daty i czasu).

Oto niektóre z nich:

Formater Przykładowy napis Opis
DateTimeFormatter.ISO_LOCAL_DATE
2025-06-01 Tylko data (rok-miesiąc-dzień)
DateTimeFormatter.ISO_LOCAL_TIME
14:30:00 Tylko czas (godziny:minuty:sekundy)
DateTimeFormatter.ISO_LOCAL_DATE_TIME
2025-06-01T14:30:00 Data i czas bez strefy czasowej
DateTimeFormatter.ISO_ZONED_DATE_TIME
2025-06-01T14:30:00+03:00[Europe/Minsk] Data, czas i strefa czasowa

Przykład użycia standardowego formatera

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class FormatterDemo {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();
        // Formatujemy datę do napisu
        String text = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
        System.out.println(text); // Na przykład: 2025-06-01

        // Parsujemy napis z powrotem do daty
        LocalDate parsed = LocalDate.parse("2025-06-01", DateTimeFormatter.ISO_LOCAL_DATE);
        System.out.println(parsed); // 2025-06-01
    }
}

Analogia

Gdyby Java była kawiarnią, standardowe formatery to „americano”, „latte” i „espresso”. Szybko, standardowo, ale czasem chce się czegoś wyjątkowego!

3. Własne wzorce: DateTimeFormatter.ofPattern

Czasem standardowe formaty nie wystarczają. Na przykład trzeba wypisać datę w postaci "01.06.2025 14:30", a nie "2025-06-01T14:30:00". W tym celu możemy utworzyć własny wzorzec metodą DateTimeFormatter.ofPattern(String pattern).

Składnia wzorców

We wzorcu używa się specjalnych liter:

  • y — rok (yyyy2025)
  • M — miesiąc (MM06)
  • d — dzień (dd01)
  • H — godzina (format 24-godzinny, HH14)
  • m — minuty (mm30)
  • s — sekundy (ss00)

Przykłady wzorców

Wzorzec Przykładowy wynik
"dd.MM.yyyy"
01.06.2025
"yyyy/MM/dd"
2025/06/01
"dd.MM.yyyy HH:mm"
01.06.2025 14:30
"yyyy-MM-dd HH:mm:ss"
2025-06-01 14:30:00
"d MMMM yyyy"
1 June 2025 (dla rosyjskiej lokalizacji)

Przykład: formatowanie daty i czasu

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

public class CustomFormatDemo {
    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2025, 6, 1, 14, 30);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
        String text = dt.format(formatter);
        System.out.println(text); // 01.06.2025 14:30
    }
}

Przykład: parsowanie napisu do daty

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

public class ParseDemo {
    public static void main(String[] args) {
        String input = "01.06.2025 14:30";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
        LocalDateTime dt = LocalDateTime.parse(input, formatter);
        System.out.println(dt); // 2025-06-01T14:30
    }
}

Uwaga: wzorzec musi dokładnie odpowiadać napisowi! Jeśli w napisie są sekundy — dodaj :ss do wzorca.

4. Formatowanie: zamieniamy datę/czas na napis

Ogólny schemat

  1. Tworzymy potrzebny obiekt (LocalDate, LocalDateTime, ZonedDateTime itd.).
  2. Tworzymy lub wybieramy odpowiedni formater.
  3. Wywołujemy na obiekcie metodę format(DateTimeFormatter) i otrzymujemy napis.

Przykład: wypisujemy datę w różnych formatach

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class MultiFormatDemo {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2025, 6, 1);

        // Standard ISO
        System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 2025-06-01

        // Własny format
        DateTimeFormatter rusFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        System.out.println(date.format(rusFormat)); // 01.06.2025

        // Styl angielski
        DateTimeFormatter usFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy");
        System.out.println(date.format(usFormat)); // 06/01/2025
    }
}

Formatowanie czasu

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class TimeFormatDemo {
    public static void main(String[] args) {
        LocalTime time = LocalTime.of(14, 30, 5);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        System.out.println(time.format(formatter)); // 14:30:05
    }
}

5. Parsowanie: zamieniamy napis na datę/czas

Ogólny schemat

  1. Pobieramy napis (np. od użytkownika).
  2. Tworzymy formater z tym samym wzorcem co napis.
  3. Wywołujemy statyczną metodę parse() lub metodę parse() obiektu formatera.

Przykład: parsowanie daty

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class ParseDateDemo {
    public static void main(String[] args) {
        String input = "01.06.2025";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        LocalDate date = LocalDate.parse(input, formatter);
        System.out.println(date); // 2025-06-01
    }
}

Przykład: parsowanie daty i czasu

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

public class ParseDateTimeDemo {
    public static void main(String[] args) {
        String input = "01.06.2025 14:30";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
        LocalDateTime dateTime = LocalDateTime.parse(input, formatter);
        System.out.println(dateTime); // 2025-06-01T14:30
    }
}

6. Obsługa błędów parsowania

Parsowanie bywa zdradliwe. Jeśli napis nie pasuje do wzorca, Java rzuci wyjątek DateTimeParseException. To normalna sytuacja, na przykład gdy użytkownik wprowadził błędną datę.

Przykład: obsługa błędów przy parsowaniu

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class ParseErrorDemo {
    public static void main(String[] args) {
        String input = "32.13.2025"; // Nieprawidłowa data
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        try {
            LocalDate date = LocalDate.parse(input, formatter);
            System.out.println(date);
        } catch (DateTimeParseException ex) {
            System.out.println("Błąd parsowania: " + ex.getMessage());
        }
    }
}

Ważne: zawsze obsługuj takie błędy, jeśli pracujesz z danymi wejściowymi od użytkownika!

7. Praktyka: przekształcanie dat dla użytkownika

Załóżmy, że w naszej aplikacji edukacyjnej jest zadanie: użytkownik wprowadza datę urodzenia w formacie "dd.MM.rrrr", a program ma wypisać datę w formacie "yyyy/MM/dd", a także dzień tygodnia.

Przykład

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Scanner;

public class BirthdayFormatDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Wprowadź datę urodzenia (dd.MM.rrrr): ");
        String input = scanner.nextLine();

        DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd");

        try {
            LocalDate birthday = LocalDate.parse(input, inputFormat);
            String formatted = birthday.format(outputFormat);
            System.out.println("Twoja data w nowym formacie: " + formatted);
            System.out.println("Dzień tygodnia: " + birthday.getDayOfWeek()); // Na przykład: SATURDAY
        } catch (DateTimeParseException ex) {
            System.out.println("Błąd: nieprawidłowy format daty!");
        }
    }
}

8. Lokalizacja: jak język wpływa na formatowanie

Za pomocą DateTimeFormatter można nie tylko zmieniać kolejność liczb, ale też wypisywać miesiąc słownie, dzień tygodnia itd. Przy tym uwzględniana jest lokalizacja (język i region).

Przykład: miesiąc słownie po rosyjsku

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

public class LocaleDemo {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2025, 6, 1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", new Locale("ru"));
        System.out.println(date.format(formatter)); // 1 June 2025
    }
}

Przykład: lokalizacja angielska

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

public class LocaleEnDemo {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2025, 6, 1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH);
        System.out.println(date.format(formatter)); // 1 June 2025
    }
}

Wskazówka: jeśli chcesz, aby nazwy miesięcy i dni tygodnia były w odpowiednim języku — ustawiaj lokalizację wprost!

9. Typowe błędy przy formatowaniu i parsowaniu dat

Błąd nr 1: Niezgodność wzorca i napisu.
Jeśli łańcuch to "01.06.2025 14:30", a wzorzec "dd.MM.yyyy", parsowanie zakończy się błędem. Wzorzec musi dokładnie odpowiadać łańcuchowi.

Błąd nr 2: Pomylenie symboli wzorca.
MM — miesiąc, mm — minuty. Jeśli napiszesz "dd.mm.yyyy", Java uzna, że chodzi o minuty, i zgłosi błąd. Dla miesiąca zawsze używaj wielkiej litery M.

Błąd nr 3: Nieobsłużone wyjątki podczas parsowania.
Jeśli nie przechwycisz DateTimeParseException, program może nagle zakończyć działanie przy błędnym wejściu użytkownika. Zawsze obsługuj takie błędy.

Błąd nr 4: Brak określonej lokalizacji przy użyciu nazw słownych.
Jeśli używasz wzorca z miesiącem słownie (MMMM), a lokalizacja nie jest wskazana, Java może użyć języka domyślnego (np. angielskiego). Zawsze jawnie ustawiaj potrzebną lokalizację.

Błąd nr 5: Używanie starych klas (SimpleDateFormat, Date) w nowych projektach.
Pamiętaj: we współczesnym kodzie używaj wyłącznie java.time i DateTimeFormatter.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION