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 |
|---|---|---|
|
2025-06-01 | Tylko data (rok-miesiąc-dzień) |
|
14:30:00 | Tylko czas (godziny:minuty:sekundy) |
|
2025-06-01T14:30:00 | Data i czas bez strefy czasowej |
|
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 (yyyy — 2025)
- M — miesiąc (MM — 06)
- d — dzień (dd — 01)
- H — godzina (format 24-godzinny, HH — 14)
- m — minuty (mm — 30)
- s — sekundy (ss — 00)
Przykłady wzorców
| Wzorzec | Przykładowy wynik |
|---|---|
|
01.06.2025 |
|
2025/06/01 |
|
01.06.2025 14:30 |
|
2025-06-01 14:30:00 |
|
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
- Tworzymy potrzebny obiekt (LocalDate, LocalDateTime, ZonedDateTime itd.).
- Tworzymy lub wybieramy odpowiedni formater.
- 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
- Pobieramy napis (np. od użytkownika).
- Tworzymy formater z tym samym wzorcem co napis.
- 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.
GO TO FULL VERSION