datetime
永井 忠一 2024.10.5
Perl と Python
Perl モジュールのインストール
Linux apt |
$ sudo apt install libdatetime-perl libdatetime-hires-perl libdatetime-format-iso8601-perl
|
(Python では標準ライブラリ)
タイムゾーン
インスタンス化。日付と時刻、タイムゾーンの情報を引数で与えている
Perl | Python |
use strict;
use warnings;
use DateTime;
my $epoch = DateTime->new(
year => 1970,
month => 1,
day => 1,
hour => 0,
minute => 0,
second => 0,
nanosecond => 0,
time_zone => "UTC");
die if not $epoch->time_zone eq DateTime::TimeZone->new(name => "UTC");
print($epoch->rfc3339() . "\n");
$epoch->set_time_zone("local");
die if not $epoch->time_zone eq DateTime::TimeZone->new(name => "local");
die if not $epoch->time_zone eq DateTime::TimeZone->new(name => "Asia/Tokyo");
print($epoch->rfc3339() . "\n");
|
from datetime import datetime, timezone
epoch = datetime(1970, 1, 1,
hour=0,
minute=0,
second=0,
microsecond=0,
tzinfo=timezone.utc)
assert epoch.tzinfo == timezone.utc
print(epoch.isoformat())
epoch = epoch.astimezone()
from datetime import timedelta
assert epoch.tzinfo == timezone(timedelta(hours=9))
print(epoch.isoformat())
|
実行結果
Perl | Python |
1970-01-01T00:00:00Z
1970-01-01T09:00:00+09:00
|
1970-01-01T00:00:00+00:00
1970-01-01T09:00:00+09:00
|
(Perl の iso8601() メソッドでは、タイムゾーンの情報が付与されないため、rfc3339() のほうを利用している)
タイムゾーンを与えない場合の挙動
Perl | Python |
use strict;
use warnings;
use DateTime;
my $epoch = DateTime->new(
year => 1970,
month => 1,
day => 1,
hour => 0,
minute => 0,
second => 0);
print($epoch->time_zone . "\n");
print($epoch->rfc3339() . "\n");
$epoch->set_time_zone("UTC");
print($epoch->time_zone . "\n");
print($epoch->rfc3339() . "\n");
$epoch->set_time_zone("local");
print($epoch->time_zone . "\n");
print($epoch->rfc3339() . "\n");
|
from datetime import datetime, timezone
epoch = datetime(1970, 1, 1,
hour=0,
minute=0,
second=0,
microsecond=0)
print(epoch.tzinfo)
print(epoch.isoformat())
from datetime import timedelta
epoch = (epoch + timedelta(hours=9)).astimezone(timezone.utc)
print(epoch.tzinfo)
print(epoch.isoformat())
epoch = epoch.astimezone()
print(epoch.tzinfo)
assert epoch.tzinfo == timezone(timedelta(hours=9))
print(epoch.isoformat())
|
実行結果
Perl | Python |
DateTime::TimeZone::Floating=HASH(0x5b7acc868448)
1970-01-01T00:00:00
DateTime::TimeZone::UTC=HASH(0x5b7acc840ef0)
1970-01-01T00:00:00Z
DateTime::TimeZone::Asia::Tokyo=HASH(0x5b7acbda98e8)
1970-01-01T09:00:00+09:00
|
None
1970-01-01T00:00:00
UTC
1970-01-01T00:00:00+00:00
JST
1970-01-01T09:00:00+09:00
|
(Python では、tzinfo が None のとき、localtime と同じように扱われる)
現在時刻の取得
Perl と Python とも、now() メソッドを利用
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now();
print($now->time_zone . "\n");
die if not $now->time_zone eq DateTime::TimeZone->new(name => "UTC");
|
from datetime import datetime
now = datetime.now()
print(now.tzinfo)
assert now.tzinfo == None
|
デフォルトのタイムゾーンは、Perl では UTC、Python では None となる
サブ秒の取得
Perl では、別モジュール「DateTime::Hires」が必要になる
Perl | Python |
use strict;
use warnings;
use DateTime::HiRes;
foreach (1..10) {
my $now = DateTime::HiRes->now();
print($now->microsecond . " us\n");
print($now->nanosecond . " ns\n");
}
|
from datetime import datetime
for iDummy in range(10):
print(datetime.now().microsecond, 'us')
|
(私の環境では、Perl で nano sec. 分解能のタイムスタンプは取得できなかった。)Perl の実行結果の例
Perl |
494635 us
494635000 ns
494711 us
494711000 ns
494739 us
494739000 ns
494759 us
494759000 ns
494776 us
494776000 ns
494791 us
494791000 ns
494806 us
494806000 ns
494821 us
494821000 ns
494835 us
494835000 ns
494849 us
494849000 ns
|
(nano sec. 台は 000 となり、実際には取得できていない)
日付時刻の処理
要素の値の変更
Perl | Python |
use strict;
use warnings;
use DateTime;
my $epoch = DateTime->new(
year => 1970,
month => 1,
day => 1);
$epoch->set_year(2000);
print("$epoch\n");
|
from datetime import datetime, timezone
epoch = datetime(1970, 1, 1,
tzinfo=timezone.utc)
epoch = epoch.replace(year=2000)
print(epoch)
|
Perl では、set_*() メソッドが、それぞれ用意されている
Python では、replace() の引数に、各要素を渡すことができる
時間 間隔
翌日、翌月、翌年を求める
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now(time_zone => 'local');
print(($now + DateTime::Duration->new(days => 1)) . "\n");
$now->add(days => 1);
print("$now\n");
$now = DateTime->now(time_zone => 'local');
print(($now + DateTime::Duration->new(months => 1)) . "\n");
$now->add(months => 1);
print("$now\n");
$now = DateTime->now(time_zone => 'local');
print(($now + DateTime::Duration->new(years => 1)) . "\n");
$now->add(years => 1);
print("$now\n");
|
from datetime import datetime, timedelta
now = datetime.now()
print(now + timedelta(days=1))
from dateutil.relativedelta import relativedelta
print(now + relativedelta(months=1))
print(now + relativedelta(years=1))
|
前日、前月、前年を求める
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now(time_zone => 'local');
print(($now - DateTime::Duration->new(days => 1)) . "\n");
die if not ($now - DateTime::Duration->new(days => 1)) eq ($now + DateTime::Duration->new(days => -1));
$now->subtract(days => 1);
print("$now\n");
$now = DateTime->now(time_zone => 'local');
print(($now - DateTime::Duration->new(months => 1)) . "\n");
die if not ($now - DateTime::Duration->new(months => 1)) eq ($now + DateTime::Duration->new(months => -1));
$now->subtract(months => 1);
print("$now\n");
$now = DateTime->now(time_zone => 'local');
print(($now - DateTime::Duration->new(years => 1)) . "\n");
die if not ($now - DateTime::Duration->new(years => 1)) eq ($now + DateTime::Duration->new(years => -1));
$now->subtract(years => 1);
print("$now\n");
|
from datetime import datetime, timedelta
now = datetime.now()
print(now - timedelta(days=1))
assert (now - timedelta(days=1)) == (now + timedelta(days=-1))
from dateutil.relativedelta import relativedelta
print(now - relativedelta(months=1))
assert (now - relativedelta(months=1)) == (now + relativedelta(months=-1))
print(now - relativedelta(years=1))
assert (now - relativedelta(years=1)) == (now + relativedelta(years=-1))
|
(Perl では、Duration を使った演算のほかに、add()、subtract() メソッドが利用できる)
(Python では、前年・翌年と前月・翌月を timedelta では求められない。別途 relativedelta が用意される)
時刻と時刻の引き算
Perl | Python |
use strict;
use warnings;
use DateTime;
print((DateTime->now() - DateTime->now()) . "\n");
print((DateTime->now() - DateTime->now())->seconds . "\n");
|
from datetime import datetime
print(type(datetime.now() - datetime.now()))
print((datetime.now() - datetime.now()).seconds)
|
実行結果の例
Perl | Python |
DateTime::Duration=HASH(0x6458dc80f7b0)
0
|
<class 'datetime.timedelta'>
0
|
演算の結果は、それぞれ Duration、timedelta となる
(Perl では、time_zone が TimeZone::Floating のものと、タイムゾーンを持つ DateTime との引き算が行える)
(Pytnon では、tzinfo が None のものと、タイムゾーンを持つ datetime との引き算は、TypeError となる)
print(datetime.now(timezone.utc) - datetime.now())
~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
TypeError: can't subtract offset-naive and offset-aware datetimes
指定した要素で切り詰める
指定した要素まで残して、切り捨てる
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now();
$now->truncate(to => "day");
print("$now\n");
|
from datetime import datetime
now = datetime.now()
now = datetime(now.year, now.month, now.day)
print(now)
|
Perl の truncate() には、「truncate(to => "year")」、「truncate(to => "month")」など、日付時刻の要素を指定することができる
要素に、秒を指定した場合
Perl |
use strict;
use warnings;
use DateTime::HiRes;
my $now = DateTime::HiRes->now();
print($now->microsecond . "\n");
$now->truncate(to => "second");
print($now->microsecond . "\n");
|
(Python には、truncate() は無い)
前後関係の比較
Perl | Python |
use strict;
use warnings;
use DateTime;
my $primary = DateTime->now();
my $secondary = DateTime->now();
die if not $primary <= $secondary;
|
from datetime import datetime
primary = datetime.now();
secondary = datetime.now();
assert primary <= secondary
|
(Perl では、time_zone が TimeZone::Floating のものと、タイムゾーンを持つ DateTime との比較が行える)
(Pytnon では、tzinfo が None のものと、タイムゾーンを持つ datetime との比較は、TypeError となる)
assert datetime.now(timezone.utc) <= datetime.now()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: can't compare offset-naive and offset-aware datetimes
月の最終日を得る
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now(time_zone => 'local');
print((DateTime->last_day_of_month(year => $now->year, month => $now->month))->day . "\n");
|
from datetime import datetime
now = datetime.now()
from calendar import monthrange
print(monthrange(now.year, now.month)[1])
|
ユーティリティの、last_day_of_month() や calendar を使わないで求める場合
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now(time_zone => 'local');
$now->add(months => 1);
$now->set_day(1);
$now->subtract(days => 1);
print($now->day . "\n");
|
from datetime import datetime, timedelta
now = datetime.now()
from dateutil.relativedelta import relativedelta
now = now + relativedelta(months=1)
now = now.replace(day=1)
now = now - timedelta(days=1)
print(now.day)
|
(Python では、dateutil が必要になる)
文字列への変換
Perl と Python とも、strftime() が利用できる
Perl | Python |
use strict;
use warnings;
use DateTime;
my $now = DateTime->now(time_zone => 'local');
print($now->strftime("%Y-%m-%d %H:%M:%S") . "\n");
|
from datetime import datetime
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
文字列のパース
「ISO 8061」形式の文字列を準備
IPython |
$ ipython3
Python 3.12.3 (main, Jul 31 2024, 17:43:48) [GCC 13.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.20.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from datetime import datetime, timezone
...: datetime(1970, 1, 1, tzinfo=timezone.utc).isoformat()
Out[1]: '1970-01-01T00:00:00+00:00'
|
Perl では、「DateTime::Format::*」に様々なパーサーが用意されている(Format::ISO8601 モジュールを利用)
Python では、fromisoformat() が(isoformat() の逆演算として)実装されている
Perl | Python |
use strict;
use warnings;
use DateTime::Format::ISO8601;
my $epoch = DateTime::Format::ISO8601->parse_datetime("1970-01-01T00:00:00+00:00");
my $verify = DateTime->new(year => 1970, month => 1, day => 1, time_zone => "UTC");
die if not $epoch eq $verify;
die if not $epoch->time_zone eq DateTime::TimeZone->new(name => "UTC");
print($epoch->rfc3339() . "\n");
|
from datetime import datetime, timezone
epoch = datetime.fromisoformat('1970-01-01T00:00:00+00:00')
verify = datetime(1970, 1, 1, tzinfo=timezone.utc)
assert epoch == verify
assert epoch.tzinfo == timezone.utc
print(epoch.isoformat())
|
文字列「1970-01-01T00:00:00+00:00」から、日付時刻のインスタンスを正しく構築できている
《データベースの、TIMESTAMP 型とのバインディングについて》
参照したドキュメント
© 2024 Tadakazu Nagai