LinuxのdateコマンドでISO8601の日付を解析する方法


15

dateコマンドを使用して、dateコマンド自体が解釈できるファイルのタイムスタンプを生成しようとしています。ただし、dateコマンドは独自の出力を好まないようで、これを回避する方法はわかりません。適例:

sh-4.2$ date
Fri Jan  3 14:22:19 PST 2014
sh-4.2$ date +%Y%m%dT%H%M
20140103T1422
sh-4.2$ date -d "20140103T1422"
Thu Jan  2 23:22:00 PST 2014

日付は、15時間のオフセットで文字列を解釈しているようです。これに関する既知の回避策はありますか?

編集:これは表示の問題ではありません:

sh-4.2$ date +%s
1388791096
sh-4.2$ date +%Y%m%dT%H%M
20140103T1518
sh-4.2$ date -d 20140103T1518 +%s
1388737080
sh-4.2$ python
Python 3.3.3 (default, Nov 26 2013, 13:33:18) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1388737080 - 1388791096
-54016
>>> 54016/3600
15.004444444444445
>>> 

UNIXタイムスタンプとして表示される場合、まだ15時間ずれています。

編集#1

たぶん、私はこの質問を少し違ったやり方で提起すべきです。フォームのISO8601基本タイムスタンプのリストがあるとします:

  • YYYYMMDDThhmm
  • YYYYMMDDThhmmss

それらを対応するUnixタイムスタンプに変換する最も簡単な方法は何ですか?

例えば:

- 20140103T1422   = 1388787720
- 20140103T142233 = 1388787753

1
@drewbennタイムスタンプに特殊文字を含めることはできません。数字と文字だけ。残念ながら、それはできません。
alex.forencich

@sim TZは設定されていませんが、/ etc / localtimeはリンクされています。
alex.forencich 14年

あなたは私を殺している、これはあなたの最後の質問ですか?8
slm

20140103T1518有効なISO 8601ではありません、それはタイムゾーンの部分を見逃し
Ferrybig

回答:


9

「既知の回避策」を要求します。以下に簡単なものを示します。

$ date -d "$(echo 20140103T1422 | sed 's/T/ /')"
Fri Jan  3 14:22:00 PST 2014

これはsed、「T」をスペースに置き換えるために使用します。結果はdate理解できる形式です。

ISO8601の日付に秒を追加するdateと、さらに変更が必要になります。

$ date -d "$(echo 20140103T142211 | sed -r 's/(.*)T(..)(..)(..)/\1 \2:\3:\4/')"
Fri Jan  3 14:22:11 PST 2014

上記でsedは、「T」をスペースに置き換え、HHMMSSをHH:MM:SSに分離します。


+が削除されていれば機能します。ただし、秒精度のタイムスタンプでは機能せず、分精度のみです。
alex.forencich 14年

@ alex.forencich回答は秒の精度で更新されました。選択した秒形式が必要なものではない場合はお知らせください。
John1024 14年

8

coreutilsの情報のドキュメントは、 ISO 8601「拡張フォーマットは、」サポートされていることを述べています。

+%zそれを機能させるには、ハイフン、コロン、およびaを追加する必要があります。

$ date +"%Y-%m-%dT%H:%M:%S%z"
2014-01-03T16:08:23-0800
$ date -d 2014-01-03T16:08:23-0800
Fri Jan  3 16:08:23 PST 2014

質問の2番目の部分に答えるには...

日付形式には数字と記号のみが含まれているため、たとえば次のように各記号を一意の文字に置き換えることができます。 tr

$ ts="$(date +"%Y-%m-%dT%H:%M:%S%z" | tr -- '-:+' 'hcp')"; echo "$ts"
2014h01h03T16c18c04h0800
$ date -d "$(echo "$ts" | tr -- 'hcp' '-:+')"
Fri Jan  3 16:18:04 PST 2014

または、Tand -やor +をセパレータとして使用して解析できます。たとえば、シェル${var%word}${var#word}展開を使用します

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T162228-0800
$ date=${ts%T*}; time=${ts#*T}
etc.    

またはbash正規表現マッチングを使用する

$ ts="$(date +"%Y%m%dT%H%M%S%z")"; echo "$ts"
20140103T165611-0800
$ [[ "$ts" =~ (.*)(..)(..)T(..)(..)(..)(.....) ]]
$ match=("${BASH_REMATCH[@]}")
$ Y=${match[1]}; m=${match[2]}; d=${match[3]}; H=${match[4]}; M=${match[5]}; S=${match[6]}; z=${match[7]}
$ date -d "$Y-$m-$d"T"$H:$M:$S$z"
Fri Jan  3 16:56:11 PST 2014

またはPerl、Pythonなどなど。


タイムスタンプに特殊文字を含めることはできません。それらを自動的に追加する良い方法を知っていますか?
alex.forencich 14年

6

GNU coreutilsは、バージョン8.13(2011-09-08にリリース)以降、入力としてISO 8601日付のみをサポートしています。古いバージョンを使用している必要があります。

古いバージョンではT、スペースで置き換える必要があります。それ以外の場合は、米国の軍事タイムゾーンとして解釈されます

最近のバージョンでも、完全に句読点形式のみが認識され、数字とaのみの基本形式は認識されませんT

# Given a possibly abbreviated ISO date $iso_date...
date_part=${iso_date%%T*}
if [ "$date_part" != "$iso_date" ]; then
  time_part=${abbreviated_iso_date#*T}
  case ${iso_date#*T} in
    [!0-9]*) :;;
    [0-9]|[0-9][0-9]) time_part=${time_part}:00;;
    *)
      hour=${time_part%${time_part#??}}
      minute=${time_part%${time_part#????}}; minute=${minute#??}
      time_part=${hour}:${minute}:${time_part#????};;
  esac
else
  time_part=
fi
date -d "$date_part $time_part"

2

のmanページでこのメモに気付きましたdate

DATE STRING
      The --date=STRING is a mostly free format human readable date string
      such as "Sun, 29 Feb 2004 16:21:42 -0800"  or  "2004-02-29
      16:21:42"  or  even  "next Thursday".  A date string may contain 
      items indicating calendar date, time of day, time zone, day of
      week, relative time, relative date, and numbers.  An empty string 
      indicates the beginning of the day.  The date  string  format
      is more complex than is easily documented here but is fully described 
      in the info documentation.

決定的なものではありませんがT、[ISO 8601]の場合、試行しているasを含む時刻形式文字列を明示的に表示しません。以下のよう@Gillesの答えが示されている、のサポートGNU coreutilsの中にISO 8601は比較的新しいものです。

文字列の再フォーマット

Perlを使用して、文字列を再構成できます。

例:

$ date -d "$(perl -pe 's/(.*)T(\d{2})(\d{2})(\d{2})/$1 $2:$3:$4/' \
    <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

これに、秒を含む文字列と含まない文字列の両方を処理させることができます。

20140103T1422:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T1422")"
Fri Jan  3 14:22:00 EST 2014

20140103T142233:

$ date -d "$(perl -pe 's/^(.*)T(\d{2})(\d{2})(\d{2})$/$1 $2:$3:$4/ || \
     s/^(.*)T(\d{2})(\d{2})$/$1 $2:$3:00/' <<<"20140103T142233")"
Fri Jan  3 14:22:33 EST 2014

@ alex.forencich-両方の時間形式を処理する代替コマンド。よろしくお願いします。関連性がなくなった上記のコメントは削除してください。
slm

1

日付のマニュアルページによると、出力する形式dateは、入力として期待されるものと同じではありません。これはマニュアルページに書かれていることです:

date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]

したがって、次のようにすることができます。

# date +%m%d%H%M%Y
010402052014
# date 010402052014
Sat Jan  4 02:05:00 EAT 2014

出力文字列を定義するために使用される変数+%m%d%H%M%Yでは、入力として予期されるものと等しいためです。


次に、ISO8601形式の日付を必要な日付にマップするコマンドを提供できますか?実際に保存されるタイムスタンプは、日付でソートできるようにISO8601形式である必要があります。
alex.forencich 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.