>  기사  >  Java  >  데이트 제대로 하자

데이트 제대로 하자

王林
王林원래의
2024-08-05 20:17:301069검색

Lets do dates properly

초보자가 배우게 될 가장 흥미로운 주제 중 하나는 날짜입니다. 다소 지루하게 들릴 수도 있지만 이는 여러분이 알고 있는 핵심 사항 중 하나입니다. 데이터베이스, API, GUI 등을 통해 날짜를 올바르게 처리하는 방법을 배우는 것은 좋은 애플리케이션을 작성하는 핵심 요소입니다.

시작하기 전에

기억해야 할 중요한 세부 사항은 Java가 웹용으로 급부상되었기 때문에 작업을 수행하는 데 기발하고 다소 어리석은 방법이 많다는 것입니다. 이 가이드의 목표는 최신 Java API를 사용하여 효율적이고 좋은 코드를 작성하는 방법을 가르치는 것입니다. 저는 여러분에게 어려운 코딩을 하지 않고 확장 가능한 애플리케이션을 위해 표준화된 ISO를 사용하는 방법을 가르치는 것을 목표로 할 것입니다.

날짜 작업 방법

날짜 API

Date Class가 출시된 Java 8 SE 기준:

Date 클래스는 밀리초 단위의 정밀도로 특정 순간을 나타냅니다.

또한 다음과 같이 정의된 Abstract Calender 클래스(JDK 1.1로 대폭 업그레이드됨)를 추가했습니다.

Calendar 클래스는 특정 시점과 YEAR, MONTH, DAY_OF_MONTH, HOUR 등과 같은 달력 필드 집합 사이를 변환하고 다음과 같은 달력 필드를 조작하기 위한 메서드를 제공하는 추상 클래스입니다. 다음주의 날짜를 가져옵니다. 순간은 Epoch, 1970년 1월 1일 00:00:00.000 GMT(그레고리력)

로부터의 오프셋인 밀리초 값으로 표시될 수 있습니다.

Oracle 문서에 명시된 바와 같이 그 이유는 국제화 능력이 부족했기 때문입니다.

관심이 있으신 경우 위에 링크된 동일한 문서에서 출시 시기에 대해 더 자세히 설명하고 있다는 점을 알아두시면 좋습니다.

LocalDate API

또한 Java 8 SE에는 다음과 같은 LocalDate 클래스가 제공되었습니다.

ISO-8601 달력 시스템에서 시간대가 없는 날짜(예: 2007-12-03)
LocalDate는 종종 연월일로 표시되는 날짜를 나타내는 변경 불가능한 날짜-시간 객체입니다. 연중일, 요일 및 주중과 같은 기타 날짜 필드에도 액세스할 수 있습니다. 예를 들어 "2007년 10월 2일" 값은 LocalDate에 저장될 수 있습니다.

주의해야 할 중요한 사양은 다음과 같습니다.

이 클래스는 시간이나 시간대를 저장하거나 나타내지 않습니다. 대신 생일에 사용되는 날짜에 대한 설명입니다. 오프셋이나 시간대 등의 추가 정보 없이는 타임라인의 순간을 표현할 수 없습니다.

차이점 및 어느 것을 사용할지

날짜/시간 API 관련 문제

LocalDate 클래스를 더 자세히 읽어보면 "이 클래스는 변경할 수 없으며 스레드로부터 안전합니다."라는 내용이 나옵니다. 이로 인해 첫 번째 문제가 발생합니다.

  • Date와 Calender는 모두 스레드로부터 안전하지 않았습니다. 의미가 약간 혼란스러울 경우 - 스레드는 컴퓨터 애플리케이션과 동시성을 구현하는 방법입니다. 이를 통해 여러 작업을 순차적이 아닌 동시에 실행할 수 있습니다(프로그래밍 배경 지식이 있는 경우 비동기로 볼 수 있음). .
  • Date/Calender API의 또 다른 문제는 디자인이 좋지 않다는 것입니다. 나중에 ISO 중심으로 개편되었습니다. (이 전체 ISO가 무엇인지 조금 헷갈리신다면 ISO는 "International Organization for Standardization"을 의미합니다.) 그리고 우리는 이것의 추가적인 이점을 나중에 보게 될 것입니다.
  • 마지막으로 국제화가 부족하다는 점은 개발자가 서로 다른 시간대를 처리하기 위한 논리를 작성해야 하므로 불일치로 인해 많은 오류가 발생할 수 있다는 것입니다.

실제 차이점

Date라는 이름에도 불구하고 가장 큰 차이점은 시간과 날짜를 모두 저장한다는 것입니다(에포크 이후 밀리초 오프셋이 있는 문서에서 언급했듯이 에포크에 대해서는 나중에 이야기하겠습니다). 최신 API를 사용하면 날짜 형식 지정/구문 분석/조작을 더 쉽게 수행할 수 있습니다.

시간도 저장하고 싶다면 어떻게 해야 하나요?

Java에서는 LocalDateTime 클래스를 통해 해당 부분도 다루었습니다.

ISO-8601 달력 시스템에서 시간대가 없는 날짜-시간(예: 2007-12-03T10:15:30)
LocalDateTime은 날짜-시간을 나타내는 변경 불가능한 날짜-시간 개체로, 종종 연-월-일-시-분-초로 표시됩니다. 연중일, 요일 및 주중과 같은 기타 날짜 및 시간 필드에도 액세스할 수 있습니다. 시간은 나노초 정밀도로 표시됩니다. 예를 들어 "2007년 10월 2일 13:45.30.123456789" 값은 LocalDateTime에 저장될 수 있습니다.

시간만 저장하고 싶다면 LocalTime 클래스를 사용할 수 있습니다

간단한 요약 및 사용 사례

Name Should Use Use Case Example
LocalDate Interprating Dates 2021-02-28
LocalTime Interprating Time 19:32:25.457826
LocalDateTime Interprating Time/Date 2021-02-28T19:32:25.457826.
Date prefer not Represents Time Tue Jul 12 18:35:37 IST 2016

현지 날짜

이제 배경과 이를 통해 무엇을 할 수 있는지 충분히 이해했으므로 LocalDate 클래스의 메서드를 살펴보겠습니다.

ISO 8601

ISO-8601 달력 시스템은 오늘날 전 세계 대부분에서 사용되는 현대 민간 달력 시스템입니다. 이는 오늘날의 윤년 규칙이 항상 적용되는 역산 그레고리력 시스템과 동일합니다. 오늘날 작성된 대부분의 애플리케이션에는 ISO-8601 규칙이 완전히 적합합니다. 그러나 과거 날짜를 활용하고 정확성을 요구하는 애플리케이션에서는 ISO-8601 접근 방식이 부적절하다는 것을 알게 됩니다.

이것은 날짜 형식을 올바르게 지정하는 데 사용되는 표준 Java입니다.

일시적인

자세한 내용을 살펴보기 전에 모든 새로운 Date API가 구현하는 Temporal 개체(LocalDate, LocalTime, LocalDateTime)를 소개하고 싶습니다. 이 개체는 다음과 같이 정의됩니다.

더하기와 빼기를 사용해 조작할 수 있을 만큼 완전한 날짜, 시간, 오프셋 객체에 대한 기본 인터페이스 유형입니다. 정보를 필드나 쿼리로 제공하고 조작할 수 있는 클래스에 의해 구현됩니다. 이 인터페이스의 읽기 전용 버전은 TemporalAccessor를 참조하세요.

깊이 들어가지 않고, 여러분이 이 문제를 겪게 되면 이것이 무엇인지 이해하시기 바랍니다.

행동 양식

이 형식은 순서대로입니다. 메서드 이름, 지정된 반환 설명, 수행 작업/심층 다이빙에 대한 빠른 요약입니다. 따라하시려면 jshell을 사용하여 java.time.LocalDate를 가져오고 동일한 메소드를 복사하세요.

LocalDate.now(): > null이 아닌 시스템 시계와 기본 시간대를 사용하는 현재 날짜

설명에서 언급했듯이 2024-07-10과 같이 시간대를 기준으로 현재 날짜 형식을 반환하지만 해당 국가에 할당된 ISO 8601 형식에 따라 해당 지역 시간에 따라 형식이 변경될 수 있습니다. (예: 2024.07.10 또는 24/7/10일 수 있습니다. 이는 해당 국가에서 사용하는 표준입니다.)

LocalDate.now() 메서드는 인수를 받을 수 있습니다. 이를 사용하기 위해 java.time.ZoneId를 가져옵니다.

ZoneId란 무엇입니까?

Java 8SE로 출시된 ZoneId는 다음과 같이 정의됩니다.

ZoneId는 Instant와 LocalDateTime 간의 변환에 사용되는 규칙을 식별하는 데 사용됩니다. ID에는 두 가지 유형이 있습니다.

  • 고정 오프셋 - 모든 현지 날짜 시간에 대해 동일한 오프셋을 사용하는 UTC/그리니치에서 완전히 해결된 오프셋
  • 지리적 지역 - UTC/그리니치로부터의 오프셋을 찾는 특정 규칙 세트가 적용되는 지역

간단히 말하면 이는 이전 Date API에서 발생했던 국제화 문제를 해결합니다. java.time.ZoneId를 가져온 후 제공되는 몇 가지 메소드를 살펴볼 수 있습니다.

  • ZoneId.getAvailableZoneIds() 여기에는 사용 가능한 모든 영역이 표시됩니다. 예를 들어 Europe/Istanbul, America/Eirunepe, Etc/GMT-4, America/Miquelon(각각은 고유하며 두 가지 유형의 고유 ID가 있음을 기억하세요. 위에 나열되어 있습니다).
  • ZoneId.systemDefault() 이 메서드는 "시스템 기본 시간대가 변경되면 이 메서드의 결과도 변경됩니다."로 정의됩니다. 설명이 필요없죠.
  • ZoneId.of("") 이를 사용하여 .getAvailableZoneIds() 목록에서 사용자 정의 세트 ZoneId를 정의합니다. 여기서 예로 사용된 UTC와 유럽/이스탄불을 모두 사용할 수 있다는 점을 기억하세요.
  • ZoneId.from() 이전에 이야기한 시간을 기억하시나요? 여기서는 이를 인수로 전달하겠습니다. 이것이 무엇을 하는지 완전히 확신할 수 없다면 임의의 날짜 및 시간 정보 세트를 나타내는 ==TemporalAccessor가 주어지면 ZoneId를 얻게 됩니다. 아직 잘 모르겠다면 java.time.ZoneId를 가져오고 ZonedDateTime.now()를 사용하면 정확한 시간/날짜를 얻을 수 있으며 이를 통해 ZoneId로 구문 분석할 수 있습니다. 기본적으로 ZoneId.from(ZonedDateTime.now())

또한 전달할 수 있는 Clock 인수가 있지만 ZoneID만 사용할 수 있지만 자유롭게 탐색할 수 있는 경우에는 아무 소용이 없습니다

이제 알았으니 파리의 현재 날짜를 알아봅시다!

LocalDate.now(ZoneId.of("Europe/Paris")) // 2024-07-10
LocalDate.of(년, 월, 일): > 연도, 월, 일에서 LocalDate의 인스턴스를 가져옵니다.

LocalDate는 날짜를 나타냄을 기억하세요. 이 경우 원하는 연도, 월, 일로 날짜를 설정할 수 있습니다!

LocalDate.ofYearDay(년, dayOfYear): >

많은 경우 1년 1일밖에 남지 않을 수도 있습니다. 이 함수는 이를 연-월-일 형식으로 변환합니다. 다음은 LocalDate.ofYearDay(2023, 234)가 2023-08-22라는 예입니다. 윤년도 고려됩니다.

LocalDate.parse(text) : > Obtains an instance of LocalDate from a text string using a specific format.

Basically, if we generate a String Date format like 2023-08-22 this will convert it into a LocalDate format

Epoch

There’s one last method I would like to talk about and even though it might not be that useful, it's a good thing to know.
Epoch in simple terms is a date set to the start. Virtually means it's “The start of time”. For example UNIX epoch is set to 1970/1/1 This is when all Unix time is calculated. Now this is not standardized between all computers. Most programming languages will use the UNIX epoch but not between all devices. For example NTP epoch is 1900/1/1. Now you might be asking why. And the simple answer is I don’t know. Unix was developed in 1969 and released in 71 but I guess the developers found 70 easier to work with and now that’s what we use!

LocalDate.ofEpochDay(epochDay) : >

Just going based on the description I gave about the output of this would be X days from 1970/1/1. Given epochDay is 1 => 1970-01-02 and so on.

~
~
~

By now I think you guys are all bored of all this nerdy talk and most likely lost interest completely but we are going to make it way more interesting in just a bit.
LocalDate methods have a ton of subsets to modify dates as we talked about above. Explaining all of these is just a waste of time. The best thing is for you guys to check ’em out and play around a bit, they are all very simple to understand.

Locale

The main idea of this whole article was to teach you internationalization and we are going to start that now.
If you recall above I talked about how LocalDate.now() might show different numbers/punctuations and this is standardized by Locale Class

A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user. For example, displaying a number is a locale-sensitive operation— the number should be formatted according to the customs and conventions of the user's native country, region, or culture.

Again the Locale class uses pre-defined ISO standards that Oracle has included.

As I said - In the early days of the web Java was rushed and we can really see that here.

Locale Constant & Why not to use

If you import java.util.Locale you can see that we have a few constants. Locale.CANADA as an example. If you're wondering what these are and why they were picked, it's quite simple. Due to the reason mentioned above, the Java devs just picked some Locale constants to support and you should not use them. Now if you look closely we have a Locale.French
and a Locale.France and you might be confused, what is this?? I’ll talk about it in a second

Now how do we go about using these Locales? By using Locale.availableLocales() you will see a large subset of available locales that you can use. you might see it in the format of en_US and you might get confused. Following up on the question listed above Java has accounted for different language subsets used in different countries. In this France/French example, We can refer to Canadian French versus French used in France. They are not entirely the same. Now a country like Iran will use Persian no matter the place, so you could just use Locale.of(language) to specify the Locale, But for French you could rather use Locale.of(language, country). Remember if you split what you got from Locale.availableLocales() by the _ you can just format it like that. An example would be Locale.of("en", "US") for en_US

Now let's implement this into our time for our different users around the globe.

System.out.println(
LocalDate.now().format(

DateTimeFormatter

.ofLocalizedDate(FormatStyle.SHORT)

.localizedBy(Locale.GERMAN)));

Now don’t mind the extra code, and even me using Locale.GERMAN cause honestly I was looking for a different output and the easiest way was to use Javas constants. I landed on Locale.GERMAN which outputs 10.07.24 as opposed to what Japan uses (2024/07/10).

Why not use Locale.of()

Now it might sound weird, but first of all i tell you not to use constants and prefer Locale.of(), then I tell you not to use Locale.of() an important factor to consider is Locale.of() was introduced with Java 19 which goes against supporting Java 8 SE to combat that from now on we will use

new Locale.Builder()
            .setLanguage("language")
            .setRegion("country").build();

Now another thing you could use is Locale.setDefault(language, country) which will work as well.

DateTimeFormatter

Now looking at the code above you might recall seeing DateTimeFormatter defined by docs as:

Formatter for printing and parsing date-time objects.

LocalDate.format()

As I mentioned above, one of the key features of Date/Time Local* APIs was formatting. And this is how we are going to format our dates. Looking at the code above - everything should make sense apart from the .ofLocalizedDate() method. The easiest way to show what it does is with an example.

LocalDate anotherSummerDay = LocalDate.of(2016, 8, 23);
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(anotherSummerDay));

will output the following in order:

Tuesday, August 23, 2016
August 23, 2016
Aug 23, 2016
8/23/16

Now sometimes you might want to have your own pattern which you can easily do with

System.out.println(

LocalDate.now().format(

DateTimeFormatter

.ofPattern("dd-uuuu-MMM")));

Now I’ll quickly go over what these symbols mean:
dd => It's a representation of the day field, now you could also use d and the difference would be that d would not have a fixed character limit since it represents 1 digit from 0-9 and 2 from 10-31. if you're lost it basically means dd would show 01; however d would show 1. However, going into two digits it's the same
uuuu/yyyy => Is the field for years. And you could also do yy which would show only the last two digits of the year. ex. 24 rather than 2024
MMM => The last field as you might have guessed is for the month - MMM tells Java that we want a String representation rather than a number. If you want a number use MM

So by now, you should’ve guessed that the output would be:

10-2024-Jul

Instants

Now that you have a firm grip on Dates. I want to introduce you to Instants defined as:

An instantaneous point on the timeline.

Basically, this refers to Instants showing a specific moment.
By now you might have assumed that LocalDateTime has a timezone, but it doesn’t as the docs mentioned they are just a representation of date/time. However a ZoneId is in fact a representation of a time zone. Also, note that Instants don’t provide methods for altering our dates and times.

Instants capture the current moment in UTC with the Instant.now() . Now based on this, you realize that Local* really doesn’t have a meaning unless it's applied, that’s the reason why you would actually refrain from using it in a business-level application. So prefer using ZonedDateTime and Insant. As a general rule of thumb use Locale When it's a specific point on a timeline rather than a moment in time. A moment would be like the moment I publish this, or the moment you read this, or the moment the world explodes, however a point in a timeline would be like an appointment there’s no moment for an appointment. If you're going on a vacation it's a specific time on a timeline, not a moment.

Whats ZonedDateTime?

Quite simple. It's just an Instant with a ZoneId and this is why we say Insant has a timezone. No matter what you do it's not going to represent a time but rather be a specific moment.

Aigh’t well that was quite the thing, wasn’t it? phew
have a nice one >#

위 내용은 데이트 제대로 하자의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.