各言語で日時文字列の解析
手元にある各言語で、標準入力から日時文字列を読み込んで、標準出力にUNIX TIME値を吐き出すプログラムを書いてみようと思ったメモ。
要件は以下の通り。
- 入力される日時文字列は1つのみ
- 不正入力のチェックは不要とする
- OS等のタイムゾーンはJST
- 対応するUNIX TIME値を出力
- 例えば、「2017/12/31 12:34:56 +0900」が入力されたら「1514723696」を出力
環境
手元にあるものということで、環境は以下のものに限定する。
- CentOS 7
入力ファイルの例
- 001.txt
2017/12/31 12:34:56 +0900
期待される出力の例
- 001.txt
1514723696
Java
import java.io.PrintWriter; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Scanner; import java.util.Date; public class Main { public static void main(String[] args) { try (Scanner in = new Scanner(System.in); PrintWriter out = new PrintWriter(System.out) ) { String str = in.nextLine(); DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss ZZZZZ"); Date date = df.parse(str); out.println(date.getTime() / 1000); } catch (ParseException e) { e.printStackTrace(); } } }
C
#define _XOPEN_SOURCE #include <stdio.h> #include <time.h> int main(int argc, char** argv) { char str[32]; fgets(str, sizeof(str) - 1, stdin); struct tm timeinfo; strptime(str, "%Y/%m/%d %H:%M:%S %z", &timeinfo); long second = mktime(&timeinfo); printf("%d\n", second); return 0; }
strptime
を使ったソースを警告も出さないようにコンパイルするためには、マクロ定数を定義してやる必要がある。
上記を見ると、%z
については、「glibc での注意」として書いてあるが、「サポートさせようとしているが、多くの場合、tmフィールドは変更されない」らしい、つまり無視される、と。
実際、「+0000」を与えて試してみたら、見事に無視されて、tmフィールドのタイムゾーン情報には"JST"が入っていた・・・
C++
#include <ctime> #include <iostream> using namespace std; int main(int argc, char** argv) { char str[32]; cin.getline(str, sizeof(str)); struct tm timeinfo; strptime(str, "%Y/%m/%d %H:%M:%S %z", &timeinfo); long second = mktime(&timeinfo); cout << second << endl; return EXIT_SUCCESS; }
上記を見ると、%z
については、「glibc での注意」として書いてあるが、「サポートさせようとしているが、多くの場合、tmフィールドは変更されない」らしい、つまり無視される、と。
実際、「+0000」を与えて試してみたら、見事に無視されて、tmフィールドのタイムゾーン情報には"JST"が入っていた・・・
PHP
(2017/12/07)DateTimeクラス版を書いてみたので追記。大して変わらないけど(ぉ
strtotime()版
<?php $lines = file('php://stdin'); $str = $lines[0]; date_default_timezone_set("Asia/Tokyo"); $second = strtotime($str); printf("%d\n", $second);
DateTimeクラス版
<?php $lines = file('php://stdin'); $str = $lines[0]; date_default_timezone_set("Asia/Tokyo"); $dt = new DateTime($str); $second = $dt->getTimestamp(); printf("%d\n", $second);
Python 2
import sys import re from datetime import datetime import time str = sys.stdin.readline() str = re.sub(r' [+][0-9][0-9][0-9][0-9][\r]*\n', "", str) dt = datetime.strptime(str, "%Y/%m/%d %H:%M:%S") second = int(time.mktime(dt.timetuple())) print second
最初、%z
を入れたら、ValueError: 'z' is a bad directive in format '%Y/%m/%d %H:%M:%S %z'
って怒られた‥
次に、%z
を外したら、ValueError: unconverted data remains: +0900
って怒られた‥
なので、時差を指定している部分を正規表現による文字列置換で削除‥当然、JST扱いされるので、「+0000」を与えたテストケースは通らない‥
Python 3
import sys import re from datetime import datetime import time str = sys.stdin.readline() str = re.sub(r'[\r]*\n', "", str) dt = datetime.strptime(str, "%Y/%m/%d %H:%M:%S %z") second = int(dt.timestamp()) print(second)
- 8.1. datetime — 基本的な日付型および時間型 — Python 3.6.3 ドキュメント
- 8.1. datetime — 基本的な日付型および時間型 — Python 3.6.3 ドキュメント
Ruby
require 'time' str = STDIN.gets second = Time.parse(str).to_i print second,"\n"
Perl
DateTime::Format::Strptime版
use DateTime::Format::Strptime; my $str = readline(STDIN); my $strp = DateTime::Format::Strptime->new( pattern => "%Y/%m/%d %H:%M:%S %z" ); my $second = $strp->parse_datetime($str)->epoch; print $second,"\n";
これをやるには、「yum install perl-DateTime-Format-Strptime」をしておく必要がある。
Time::Piece版
use Time::Piece; my $str = readline(STDIN); chomp($str); my $dt = Time::Piece->strptime($str, "%Y/%m/%d %H:%M:%S %z"); my $second = $dt->epoch; print $second,"\n";
これをやるには、「yum install perl-Time-Piece」をしておく必要がある。
Go
package main import ( "bufio" "fmt" "io" "os" "time" ) func main() { stdin := bufio.NewReader(os.Stdin) buf := make([]byte, 0, 1024) str := "" for { line, prefix, err := stdin.ReadLine() if err == io.EOF { break } buf = append(buf, line...) if prefix { continue } str = string(buf) break } t, err := time.Parse("2006/01/02 15:04:05 -0700", str) if err != nil { panic(err) } fmt.Println(t.Unix()) }
- time - The Go Programming Language
- Golangでの日付のフォーマット指定の方法について - Qiita
- Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日? - Qiita
Go言語の日時のフォーマット指定子の仕様は何度見ても謎だ‥
bash
#! /bin/bash IFS=$'\n' read str date -d "${str}" +"%s"
man date
(ぉ