UTCが欲しい

小ネタ

#UTC

[協定世界時@wikipedia](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)

そもそもSplunkの`_time`は　[UNIX時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)なので気楽にだせるはず。

##今の時刻を確認してみる
```Splunk:SPL
| makeresults 
| eval time=strftime(_time,"%F %T %Z")
```
| _time | time |
|:--|:--|
| 2019/12/07 09:23:48 | 2019-12-07 09:23:48 JST |
[日本標準時@wikipedia](https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E6%A8%99%E6%BA%96%E6%99%82)になっていますね。

##UTCに変更してみる

```Splunk:SPL
| makeresults 
| eval time_suffix=strftime(_time,"%:::z") 
| eval time_suffix_mod=time_suffix * -1
| eval unix_time=relative_time(_time,(time_suffix_mod."h"))
| eval unix_time=strftime(utc_time, "%F %T.%3N")
```

| _time | time_suffix | time_suffix_mod | utc_time |
|:--|--:|--:|:--|
| 2019/12/07 09:40:26 | +09 | -9 | 2019-12-07 00:40:26.000 |

`%z`をつけるとバレてしまうので、この形。
 プラスマイナス変換に`-1`を掛けるのも、知ってしまえば当然だけど、最初は`case`で作ってた・・・・

##追記(R2.7.24)
Splunk>Answersで、昔やったよな〜と思いつつ回答した。。

このページを見返したところ、上記クエリーは"-01"のように、アメリカあたりの時刻帯だと上手く動かないことが判明

```sql:GMT.spl
| makeresults
| eval time=strftime(_time,"%FT%T %:::z")
| eval offset = substr(time,21,23)
| eval time_args = if( -1 * offset >= 0, "+".substr(offset,2,3), printf("%03d",-1 * offset))
| eval GMT = ceil(relative_time(_time,time_args."h"))
| convert ctime(GMT)
```

やっぱり、±判定が必要らしい。
`printf()`で`"-01"`といった文字列を作っている。`%03`なのに注目。

`relative_time()`はミリセコンド以下を切りすてるので、必要な場合は別途くっつける必要がある。今回はじゃまな`.000000`を削除するため`ceil()`している。

####time format
[Common Time Format Variables@Splunk>Docs](https://docs.splunk.com/Documentation/Splunk/8.0.0/SearchReference/Commontimeformatvariables)
覚え切らないので、基本は　`%F %T` か `%c`

#props.confで変える
[I want to set a different time zone from the time@Splunk Answer](https://answers.splunk.com/answers/658355/i-want-to-set-a-different-time-zone-from-the-time.html)
ふと見てたらこんなやつを見つけた。

TZ（Time Formatだと`%z`）の値を上書きするオプションが`TZ_ALIAS`
`TZ_ALIAS= 00:00=JST`が回答。なので
`TZ_ALIAS= 00:00=UTC`にしてしまえば、多分ＵＴＣ

#１９７０年より前でも欲しい
```java:before1970.spl
| makeresults 
| eval time=-31553280 
| appendpipe
    [eval time=0]
    | makecontinuous time span=-31553280
| eval date=strftime(time,"%F %T")
| head 1970
| rex field=date "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (?<hour>\d{2}):(?<min>\d{2}):(?<sec>\d{2})"

| eval leap_year=if(year % 400 =0 OR (year % 4 =0 AND year % 100 !=0),"Leap", "NOTLeap") 
| eval mod_day=sec + 60 * min + pow(60,2) * hour + 24 * pow(60,2) * (tonumber(day)-1)
| eval date=strftime(time-mod_day,"%F %T")
| eval mod_3month=if(leap_year=="NOTLeap",mod_day+24*pow(60,2)*59,mod_day+24*pow(60,2)*60)
| eval mod_2month=mod_day+24*pow(60,2)*31
| eval date=case(month="03",strftime(time-mod_3month,"%F %T"),month="02",strftime(time-mod_2month,"%F %T"),true(),date)

| appendpipe
    [eval time=0, date=strftime(time,"%F %T")
    | head 1]
    | table date time
    | sort 0 - time
```
[2020年問題](https://docs.splunk.com/Documentation/Splunk/8.0.1/ReleaseNotes/FixDatetimexml2020)もあるなか、今回１９７０年より前の年を出してみたくなり作ってみた。
`strptime`が使えないのでこんな感じ。
[Microsoftの閏年判定](https://docs.microsoft.com/ja-jp/office/troubleshoot/excel/determine-a-leap-year)も組み込んでいろいろ調整をして作ってみた。
JSTは一回修正して-9時間してはみたもののバグが多すぎるので、この形にした。

> UNIX data represents different points in time as signed integers, traditionally of 32 bits, by encoding the UNIX timestamp. Because it uses 32 bits, UNIX time can only cover approximately 136 years in total. In other words, the maximum representable time for UNIX time is 19 January 2038 and the minimum representable time is 13 December 1901.
 
> Date & timeTimes that occurred before 1970 (the epoch time) have a negative value. When the counter passes the maximum date, the counter will ‘run out’ and time will ‘wrap around’ and be stored as a negative number (13 December 1901). This is referred to as the UNIX millennium bug.

splunk answerでなんとかならないのかと質問したら、このコメントが帰ってきた。でも負けない。

#epochの限界
```java:limit.spl
| makeresults
| eval time=-62167252739
| eval _time=time
| eval time_text=strftime(_time,"%c %::z")
```
`-62167252739`がepochの限界っぽい。
ターミナルで`date -r -62167252739`で確認したら `0000年 1月 1日 土曜日 00時00分00秒 LMT`が帰ってきた。

#Splunkの時間について
```java:until1887-01-01.spl
| makeresults 
| eval time=-62167252739
| appendpipe
    [eval time=0]
| eval date=strftime(time,"%F %T")
| makecontinuous span=31536000 time
| eval date=strftime(time,"%F %T")
| rex field=date "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (?<hour>\d{2}):(?<min>\d{2}):(?<sec>\d{2})"
| dedup year
| eval mod_date=strftime(time,"%j")
| eval time=if(day="01",time,time - (mod_date -1)  * 24 * 60 * 60)
| eval date=strftime(time,"%F %T")
```
`strftime()`は使えるから始めの時間から逆算で作ってみた。
`1887-01-01 00:00:00 -2619249539`までは普通に動いていたけどそこからがおかしくなった。
#1970前でもUTCが欲しいver2
```java:before1970v2.spl
| makeresults count=2
| streamstats count
| eval time=if(count=1,0,-62167252739)
| makecontinuous time span=31536000
| eval time = time - (time % (24 * 60 * 60))- (9 * 60 * 60)
| sort 100 - time
| eval date=strftime(time,"%F %T")
| rex field=date "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (?<hour>\d{2}):(?<min>\d{2}):(?<sec>\d{2})"
| dedup year
| eval mod_date=strftime(time,"%j")
| eval time=if(day="01",time,time - (mod_date -1)  * 24 * 60 * 60)
| eval date=strftime(time,"%F %T")
| sort 83 - date
| table date	day	hour	min	mod_date	month	sec	time	year
| append [| makeresults count=2
| streamstats count
| eval time=if(count=1,0,-62167252739)
| makecontinuous span=31536000 time
| eval date=strftime(time,"%F %T")
| rex field=date "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) (?<hour>\d{2}):(?<min>\d{2}):(?<sec>\d{2})"
| dedup year
| eval mod_date=strftime(time,"%j")
| eval time=if(day="01",time,time - (mod_date -1)  * 24 * 60 * 60)
| eval date=strftime(time,"%F %T")]
| sort date
| where sec="00"
| table date time
```
結論ありきで作ってみたらこんな感じ。内部的にはめちゃくちゃだと思う。

#まとめ
一応動的に現在の環境の変数から導きだしているので、たまたまSplunk環境が日本時間じゃなかったとしても使えるはず。

------
12/9　props.confで変える　を追加
12/26 １９７０年より前でも欲しい　を追加
2/8 epochの限界、1970前でもUTCが欲しいver2　を追加
7/24/2020 追記　を追加