Java에서 RSS 포맷의 시간 다루기

한재희·2021년 10월 3일
0

결론

약간의 서사가 있어 결론부터 말씀드리자면,

// Fri, 01 Oct 2021 07:24:36 +0000
SimpleDateFormat RFC_822 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
// 2021-09-10T00:23:16Z
SimpleDateFormat ISO_INSTANT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
SimpleDateFormat target = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

if(rawDate.charAt(0) >= 'A' && rawDate.charAt(0) <= 'Z'){
      return target.format(RFC_822.parse(rawDate));
}else {
      return target.format(ISO_INSTANT.parse(rawDate));
}

위와 같은 형식으로 해결했습니다!

발단

POST-IT에서는 블로그와 유튜브를 파싱해 데일리 컨텐츠를 제공하고있습니다.

이 블로그와 유튜브가 작성된 시간을 다루는데 기존에는

String rawTime = "Fri, 01 Oct 2021 07:24:36 +0000"
int year = Integer.parseInt(rawTime.substring[12,16]);
int month = monthMap.get(rawTime.substring[8,11]);
int day = Integer.parseInt(rawTime.substring[5,7]);

와 같은 형태로 문자열을 substring으로 다뤘습니다.
그런데 이제 메일 구독 서비스를 준비하면서 yyyy-MM-mm HH:mm:ss 형태로 시간을 제공하기로 결정하면서, 시간을 좀 더 제대로 다뤄보며 겪은 이슈들입니다.

시작

시간을 다루기 전 자주 언급될 클래스는 DateTimeFormatterInstant 입니다.

Instant는 Java 8부터 지원되는 TIME API입니다.
기본적으로 시간을 생성하면 밑에서 언급될 ISO_INSTANT 형태로 생성되며, 타임존을 변경하기 용이하며, DateTimeFormatter와 연동해시간을 원하는 형태로 변경하기 쉽습니다.

이제 본격적으로 시간을 다루기 전, RSS에서 자주 사용되는 시간의 포맷을 알아야합니다.
먼저, ISO_INSTANT 으로, UTC기준 시간형태입니다.

2011-12-03T10:15:30Z

이 시간은 문자열 split을 하기도 좋게 생기기도 했지만, 자바에서는 Instant 클래스를 통해 가장 활용하기 무난한 형태입니다.

Instant.parse("2011-12-03T10:15:30Z").atZone(ZondId.of("Asia/Seoul"));
// 2011-12-03 19:15:30

그리고 RSS 표준에서 사용되는 RFC_1123_DATE_TIME입니다.

Fri, 01 Oct 2021 07:24:36 +0000
Fri, 01 Oct 2021 07:24:36 GMT


https://validator.w3.org/feed/docs/rss2.html
위에서 빨간 표시된 PDT는 이후에 언급됨으로 기억해두세요!


https://datatracker.ietf.org/doc/html/rfc822#page-26
위에서 빨간 표시된 PDT는 이후에 언급됨으로 기억해두세요!

RSS 2.0 표준과 RFC 822에서의 DATE와 TIME에 대한 부분입니다.
RFC 1123에서도 DATE, TIME 부분은 RFC 822를 따라가기 때문에 정의는 RFC 1123으로 되어있습니다.

위의 타입은 다음과 같이 처리할 수 있습니다.

OffsetDateTime
              .parse(rawDate, DateTimeFormatter.RFC_1123_DATE_TIME)
              .toInstant();

OffsetDateTime+HHMMGMT, EDT등을 모두 처리해줍니다. 다음은 실제 클래스 구현부입니다.

미리 정의된 형태 외의 커스텀이 필요하다면, DateTimeFormatterbuilder로 커스텀할 수 있습니다.
DateTimeFormatter로 받을 수 있는 시간 형태는 다음과 같습니다.

이제 RSS에서 사용되는 시간 형태는 모두 관리할 수 있을 줄 알았는데..

문제


Microsoft에서는 PDT를 사용하는데, JAVA의 RFC_1123_DATE_TIME에서는 PDT를 지원하지 않습니다..

그렇다면 PDT는 무엇인가?

Pacific Daylight Time, 태평양 일광 절약 시간, UTC -0700

위에서 사용했던 DateTimeFormatter에서는

위에서 빨간 표시됐던 PDT만 없습니다.

PDT를 왜 지원하지 않는지는 찾지 못했고.. 대체법을 찾을 수 있었습니다.

https://stackoverflow.com/questions/18493528/java-date-format-gmt-0700-pdt

각각이 왜 지원하고, 하지 않는지까지는 잘 모르겠지만..
SimpleDateFormat으로 날짜형식을 커스텀해 정의하는 것으로 해결했습니다.

사실 기존의 RFC_1123ISO_INSTANT를 그대로 따라가는 것이라 크게 어렵지 않아 결론과 같이 해결했습니다.

// Fri, 01 Oct 2021 07:24:36 +0000
SimpleDateFormat RFC_822 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
// 2021-09-10T00:23:16Z
SimpleDateFormat ISO_INSTANT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
SimpleDateFormat target = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

if(rawDate.charAt(0) >= 'A' && rawDate.charAt(0) <= 'Z'){
      return target.format(RFC_822.parse(rawDate));
}else {
      return target.format(ISO_INSTANT.parse(rawDate));
}

마무리

PDT와 같은 특이 케이스가 아니라면 DateTimeFormatter로 간단히 해결할 수 있을 것이고, 특별한 형태로 받아야 한다면 SimpleDateFormat으로 해결할 수 있습니다!
현재까지는 RSS에 표준이 있긴 해도 사이트별로 시간 형태가 제각각이라.. 틈틈히 케이스들을 추가하고 있습니다.
이런 형태로 본다면, SimpleDateFormat를 더 자주 쓸 것 같습니다.

profile
IT관련 된 것들은 가리지 않고 먹어요.

0개의 댓글