날짜 문자열 형식 변경

날짜 문자열 형식 변경

잘못된 날짜로 가득 찬 파일의 형식을 다시 지정하는 방법을 찾으려고 합니다. 소스는 다음과 같습니다.

{"_id":"","timestamp":"Mon Apr 20 08:30:55 +0000 2015"}
{"_id":"","timestamp":"Mon Apr 20 08:32:25 +0000 2015"}
{"_id":"","timestamp":"Mon Apr 20 08:35:39 +0000 2015"}

이와 같은 항목이 약 3백만 개 있습니다. 타임스탬프를 ISO-8601 형식으로 지정해야 합니다. YYYY-MM-DDTHH:mm:ss.mmm<+/-Offset>

나는 이것을 시도했고 작동합니다 :

date -d "Mon Apr 20 08:35:39 +0000 2015" +%FT%T%z

300만 개의 항목을 모두 수동으로 처리하지는 않을 것이므로 이 목적으로 sed를 사용하는 방법을 생각해 보았습니다.

cat input.json | sed "s|\"timestamp\":\"\(.*\)\"|\"timestamp\":\"$(date -d \1 +%FT%T%z)\"|g" > output.json

그러나 매번 동일한(잘못된) 출력이 인쇄됩니다 2015-05-08T01:00:00+0000. 이 딜레마를 해결하는 데 도움을 줄 수 있는 사람이 여기 있습니까?

답변1

sed이 목적 으로 사용될 수 있지만 awk더 자연스럽습니다.

awk -F'"' -v OFS='"'  '$8 {cmd="date -d \""$8"\" +%FT%T%z"; cmd | getline $8; close(cmd)} 1' input.json
{"_id":"","timestamp":"2015-04-20T01:30:55-0700"}
{"_id":"","timestamp":"2015-04-20T01:32:25-0700"}
{"_id":"","timestamp":"2015-04-20T01:35:39-0700"}

위 이미지는 -7:00시간의 오프셋을 보여줍니다. 이는 시스템의 기본 시간대를 반영합니다. 쉘 변수를 변경하면 TZ기본값이 변경됩니다.

어떻게 작동하나요?

  • -F'"' -v OFS='"'

    그러면 입력 및 출력 필드 구분 기호가 로 설정됩니다 ".

  • $8 {cmd="date -d \""$8"\" +%FT%T%z"; cmd | getline $8; close(cmd)}

    "필드 구분 기호 로 날짜는 필드 번호 8입니다. 그러면 올바른 명령을 사용하여 문자열이 생성된 date다음 명령을 실행하여 업데이트된 필드 8에 출력을 캡처합니다.

    앞의 출력은 $8필드 8에 null이 아닌 값이 있는 경우에만 이 섹션이 실행된다는 것을 의미합니다. 이를 통해 예를 들어 빈 라인이 방해받지 않고 통과할 수 있습니다.

  • 1

    이것은 "이 줄을 인쇄하세요"에 대한 awk의 비밀스러운 속기입니다.

추가 큰따옴표 처리

필드 구분 기호로 사용하고 있기 때문입니다 ". "타임스탬프 앞에는 다양한 횟수가 있다고 가정합니다 . 이 경우 타임스탬프를 $(NF-1)여덟 번째 필드가 아닌 두 번째에서 마지막 필드로 호출해야 합니다 $8. 이 경우:

awk -F'"' -v OFS='"'  '$8 {cmd="date -d \""$(NF-1)"\" +%FT%T%z"; cmd | getline $(NF-1); close(cmd)} 1' input.json

날짜 필드에 사용자 정의 형식 추가

$ awk -F'"' -v OFS='"'  '$8 {cmd="date -d \""$(NF-1)"\" +%FT%T%z"; cmd | getline $(NF-1); close(cmd);$(NF-1)="{$date:" $(NF-1) "}"} 1' input.json
{"_id":"","timestamp":"{$date:2015-04-20T01:30:55-0700}"}
{"_id":"","timestamp":"{$date:2015-04-20T01:32:25-0700}"}
{"_id":"","timestamp":"{$date:2015-04-20T01:35:39-0700}"}

답변2

jq,node:

cat /tmp/what \
| jq '.timestamp' \
| while read line ; do \
  node -e "console.log(new Date($line).toISOString())" ;\
  done

단일 Node.js 프로그램을 사용하여 전체 파일을 처리하여 성능을 향상시킬 수도 있지만 이는 JS 영역에 너무 깊을 수 있습니다. (자세한 내용을 원하시면 핑을 해보세요.)

답변3

입력이 표시한 대로 정확하게 형식화된다는 것을 보장할 수 있다면 정확히 그렇게 할 수 있습니다 sed. 이것은 약간의 무차별 대입입니다.

sed \
        -e 's/"timestamp":"... Jan/"timestamp":"01/' \
        -e 's/"timestamp":"... Feb/"timestamp":"02/' \
        -e 's/"timestamp":"... Mar/"timestamp":"03/' \
        -e 's/"timestamp":"... Apr/"timestamp":"04/' \
        -e 's/"timestamp":"... May/"timestamp":"05/' \
        -e 's/"timestamp":"... Jun/"timestamp":"06/' \
        -e 's/"timestamp":"... Jul/"timestamp":"07/' \
        -e 's/"timestamp":"... Aug/"timestamp":"08/' \
        -e 's/"timestamp":"... Sep/"timestamp":"09/' \
        -e 's/"timestamp":"... Oct/"timestamp":"10/' \
        -e 's/"timestamp":"... Nov/"timestamp":"11/' \
        -e 's/"timestamp":"... Dec/"timestamp":"12/' \
-e 's/"timestamp":"\(..\) \(..\) \(..:..:..\) \(.....\) \(....\)"/"timestamp":"\5-\1-\2T\3\4"/' \
        input.json > output.json

월 이름을 월 이름으로 바꾼 다음 (현재) 모든 숫자로 구성된 날짜 문자열을 분할하고 해당 부분을 원하는 순서로 다시 합칩니다. 밀리초를 추가하려면 와 사이에 .000삽입하세요 .\3\4

관련 정보