Java 날짜 패턴에서 'Y'와 'y' 문자의 차이점이 무엇인지 아시나요? 이 문서에서는 잘못된 날짜 형식으로 인해 오류가 어떻게 발생하는지 살펴보겠습니다. 갑작스러운 시간 여행으로부터 여러분을 구해줄 새로운 Java용 V6122 진단 규칙도 소개하겠습니다.
큰 TODO 노트의 먼지를 털어낸 후 우리는 특히 흥미로운 사례를 발견했습니다. 기사의 댓글 작성자가 잠재적인 문제를 강조했습니다.
댓글
그런데 여기에 아이디어가 있습니다. Java의 SimpleDateFormat은 새해를 놀라게 할 수 있습니다. 소문자로 작성된 연도는 대문자로 작성된 연도와 동일하지 않습니다. 2021년 12월 27일~12월 31일 날짜의 "YYYY"가 일부 예상대로 2021년이 아니라 2022년이기 때문에 올해의 마지막 주에 갑자기 미래에 있는 자신을 발견할 수 있습니다.
자세한 내용을 살펴보겠습니다.
SimpleDateFormat이 무엇인지 잊어버린 경우 여기에서 지식을 복습할 수 있습니다.
날짜를 저장하고 표시하려면 특정 패턴을 따라야 하는 경우가 많습니다. SimpleDateFormat은 주어진 패턴에 따라 날짜 형식을 쉽게 지정할 수 있는 클래스입니다. 형식 지정 외에도 SimpleDateFormat은 문자열을 구문 분석하여 날짜 개체로 변환할 수도 있습니다.
Java가 제공하는 것이 이것이 전부인가요? SimpleDateFormat 외에도 DateTimeFormatter 클래스를 사용하여 날짜 형식을 지정할 수도 있습니다.
이 두 클래스를 사용하는 예를 보여드리겠습니다.
SimpleDateFormat을 통해 날짜 형식을 지정하는 경우:
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
콘솔에 다음이 표시됩니다.
2024년 12월 31일
여기서 무슨 일이 일어난 걸까요?
날짜가 있고 이를 특정 형식으로 저장/표시하려고 합니다. 이를 달성하기 위해 패턴 문자열을 생성자에 전달하여 SimpleDateFormat 객체를 생성합니다. 날짜는 이 패턴에 따라 정확하게 형식화됩니다. format 메서드는 형식이 지정된 날짜의 문자열 표현을 반환합니다. 이것이 바로 우리가 원했던 것입니다.
동일한 내용이지만 DateTimeFormatter:
를 사용합니다.
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
콘솔에 다음이 표시됩니다.
2024년 12월 31일
동일한 단계와 결과이지만 약간의 차이가 있습니다. DateTimeFormatter를 사용하면 TemporalAccessor 인터페이스를 구현하는 클래스가 나타내는 날짜 형식만 지정할 수 있습니다. 예를 들어 LocalDate 및 LocalDateTime이 여기에 포함됩니다. SimpleDateFormat은 Date 클래스의 개체 형식만 지정합니다.
댓글로 돌아가 보겠습니다. 날짜 패턴에 'y' 대신 'Y'를 사용하면 실제로 결과가 바뀌나요?
코드 살펴보기:
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
콘솔에 다음이 표시됩니다.
2025년 12월 31일
앗. DateTimeFormatter도 마찬가지인가요?
코드는 다음과 같습니다.
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
콘솔에 다음이 표시됩니다.
2025년 12월 31일
우리는 1년 미래로 여행을 떠났습니다. 무슨 일이 일어나는지 지켜볼 시간입니다.
첫 번째 단계는 SimpleDateFormat 클래스에 대한 문서를 살펴보는 것이었습니다. 다음은 날짜 패턴이 관심 있는 알파벳 문자를 해석하는 방법을 설명하는 표의 일부입니다.
Letter | Date or Time Component | Presentation | Examples |
---|---|---|---|
y | Year | Year | 1996; 96 |
Y | Week year | Year | 2009; 09 |
일주일? 설명드리겠습니다.
주 연도는 해당 연도의 주 수를 기준으로 한 연도입니다. 이는 무엇을 의미하며 왜 중요한가요?
특정 작업에서는 해당 연도의 주의 순서 번호가 중요합니다. 주의 순서 번호를 결정하려면 먼저 고려할 주를 결정해야 합니다. 이는 한 해에서 다른 해로 전환할 때 두 해에 걸쳐 몇 주가 걸리는 경우가 많기 때문입니다. 그렇다면 이번 주가 어느 연도에 속하는지 어떻게 알 수 있을까요? ISO-8601 표준은 이를 규제합니다.
이 기준에 따르면, 해당 연도의 첫 주는 다음 조건을 충족해야 합니다.
이로부터 우리는 간단한 규칙을 추론할 수 있습니다: 목요일이 1월에 해당하는 경우 그 주가 그 해의 첫 번째 주가 됩니다.
실제 사례를 통해 이를 더욱 명확하게 이해할 수 있습니다.
예제의 날짜는 2024년 12월 31일입니다. 다음은 날짜가 포함된 주의 달력 조각입니다(2024년 12월~2025년 1월):
Mo | Tu | We | Th | Fr | Sa | Su |
---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
이번 주는 위의 조건을 만족하므로 2025년의 첫 주로 간주됩니다(1월 5일이 있음). 따라서 'Y' 지정자를 사용하면 2025년이 됩니다.
짐작하시겠지만 DateTimeFormatter 의 경우도 똑같습니다.
미래뿐만 아니라 과거로도 여행할 수 있다는 점을 기억하는 것이 중요합니다.
2027년 1월 1일을 다른 날짜로 잡겠습니다.
2027년 첫 주에 1월 1일이 포함되나요? 다시한번 달력을 참고해 보세요.
다음은 날짜가 포함된 주의 달력 조각입니다(2026년 12월~2027년 1월).
Mo | Tu | We | Th | Fr | Sa | Su |
---|---|---|---|---|---|---|
28 | 29 | 30 | 31 | 1 | 2 | 3 |
이번 주는 1월의 일수가 3일뿐이므로(요구 사항에 따라 첫 번째 주에는 4일이어야 함) 2026년의 마지막 주로 계산됩니다. 따라서 날짜 형식을 'Y'로 지정하면 캐릭터, 2026년을 보여드리겠습니다.
여기에 증거가 있습니다. 코드를 살펴보세요:
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-yyyy"); System.out.println(dateFormatter.format(date)); }
콘솔에 다음이 표시됩니다.
2026-01-01
알겠습니다. 문제를 분석했습니다. 또한 PVS-Studio Java 분석기에 전용 진단 규칙을 추가하는 것만으로도 충분히 흥미로웠습니다.
진단 규칙이 작성되었으니 테스트해 볼 차례입니다.
분석기 개발 중 테스트 단계 중 하나에는 회귀 테스트 실행이 포함됩니다. 이 과정에 대한 기사가 있습니다. 즉, 새로운 진단 규칙을 추가할 때 대규모 오픈 소스 프로젝트 풀을 분석하고 새 보고서를 참조 보고서와 비교합니다.
이 진단 규칙의 경우 분석기가 여러 프로젝트에 새로운 경고를 발행했습니다. 살펴보겠습니다.
이번 프로젝트에서는 진단 룰이 가리키는 코드 조각이 동일하므로 그 중 하나만 보여드리겠습니다.
코드 살펴보기:
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); System.out.println(formatter.format(date)); }
PVS-Studio 경고:
V6122 'Y'(연도) 패턴 사용이 감지되었습니다. 아마도 'y'(연도)를 사용하려는 의도였던 것 같습니다. SkeinParameters.java 246
먼저 GitHub를 살펴봤습니다. 그것이 정말로 버그이고 개발자가 이미 버그를 발견하고 수정을 완료했다면 어떻게 될까요? 그것이 바로 일어난 일입니다. 커밋에 대한 링크는 다음과 같습니다. 확인해 보세요. 패턴의 모든 'Y'(주 연도) 문자가 'y'(연도)로 대체되었습니다.
커밋이 비교적 오래 전에 이루어진 이유가 궁금할 수 있습니다. 설명하겠습니다. 우리의 회귀 테스트는 특정 오픈 소스 프로젝트의 품질을 지속적으로 제어하기 위한 것이 아닙니다. 작업은 새 진단 규칙이 추가될 때 보고서가 어떻게 변경되는지 확인하는 것입니다. 분석기에 문제가 있음을 나타내는 이전 경고가 사라지거나 새 오류가 나타나서는 안 됩니다. 따라서 확인된 코드는 동일해야 합니다.
이제 진단 룰이 발동된 두 번째 프로젝트를 살펴보겠습니다.
PVS-Studio 경고:
V6122 'Y'(연도) 패턴 사용이 감지되었습니다. 아마도 'y'(연도)를 사용하려는 의도였던 것 같습니다. RepositoryInfo.java 77
코드:
public static void main(String[] args) { Date date = new Date("2024/12/31"); var dateFormatter = new SimpleDateFormat("dd-MM-YYYY"); System.out.println(dateFormatter.format(date)); }
이전 프로젝트와 마찬가지로 무슨 일이 일어나고 있는지 확인하기 위해 서둘러 커밋을 진행했습니다. 우선, 리팩토링의 결과로 필드가 파생 클래스인 Repository로 이동했다는 점에 주목할 가치가 있습니다(여기에 커밋 링크가 있습니다). 더 자세히 검색해 수정 사항이 포함된 커밋을 찾았습니다. 날짜 패턴의 'Y' 문자가 'y'로 대체되었습니다:
public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 12, 31); var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY"); System.out.println(formatter.format(date)); }
그래서 여기도 오류였군요.
PVS-Studio에서는 커뮤니티의 모든 피드백을 환영합니다. Habr 사용자의 의견을 처리한 후 몇 가지 유용한 진단 규칙을 추가하여 Java 분석기를 향상했습니다. 따라서 우리와 공유하고 싶은 생각이 있으면 이 기사의 댓글 섹션에서 대화를 나누고 싶습니다.
그런데 진단 규칙은 10월 7.33 릴리스에서 도입되었습니다. 따라서 우리의 분석기를 사용해 보고 싶다면 이 링크를 사용하세요.
그게 다입니다. 여기에서 내용을 마무리하겠습니다. 갑작스런 1년 전(혹은 후진) 여행으로 당황하지 않으셨으면 좋겠습니다.
위 내용은 응? 이야!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!