コンテンツにスキップ

時間と期間

時間値、期間、タイムゾーン、スケジューリングを扱う。タイマーの作成、指定期間のスリープ、タイムスタンプの解析とフォーマット。

ワークフローでは、time.now()は決定論的リプレイのために記録された時間参照を返します。

local time = require("time")

現在時刻を返す。ワークフローでは、決定論的リプレイのためにワークフローの時間参照から記録された時刻を返す。

local t = time.now()
print(t:format_rfc3339()) -- "2024-12-29T15:04:05Z"
-- 経過時間を測定
local start = time.now()
do_work()
local elapsed = time.now():sub(start)
print("Took " .. elapsed:milliseconds() .. "ms")

戻り値: Time

-- UTCで特定の日時を作成
local t = time.date(2024, time.DECEMBER, 25, 10, 30, 0, 0, time.utc)
print(t:format_rfc3339()) -- "2024-12-25T10:30:00Z"
-- 特定のタイムゾーンで作成
local ny, _ = time.load_location("America/New_York")
local meeting = time.date(2024, time.JANUARY, 15, 14, 0, 0, 0, ny)
-- 指定しない場合はローカルタイムゾーンがデフォルト
local t = time.date(2024, 1, 15, 12, 0, 0, 0)
パラメータ説明
yearnumber
monthnumber月(1-12またはtime.JANUARYなど)
daynumber
hournumber時(0-23)
minutenumber分(0-59)
secondnumber秒(0-59)
nanosecondnumberナノ秒(0-999999999)
locationLocationタイムゾーン(オプション、デフォルトはlocal)

戻り値: Time

-- エポックからの秒数から
local t = time.unix(1703862245, 0)
print(t:utc():format_rfc3339()) -- "2023-12-29T15:04:05Z"
-- ナノ秒付き
local t = time.unix(1703862245, 500000000) -- +500ms
-- JavaScriptタイムスタンプ(ミリ秒)を変換
local js_timestamp = 1703862245000
local t = time.unix(js_timestamp // 1000, (js_timestamp % 1000) * 1000000)
パラメータ説明
secnumberUnix秒
nsecnumberナノ秒オフセット

戻り値: Time

Goの参照時刻フォーマットを使用して時刻文字列を解析:Mon Jan 2 15:04:05 MST 2006

-- RFC3339を解析
local t, err = time.parse(time.RFC3339, "2024-12-29T15:04:05Z")
if err then
return nil, err
end
-- カスタムフォーマットを解析
local t, err = time.parse("2006-01-02", "2024-12-29")
local t, err = time.parse("15:04:05", "14:30:00")
local t, err = time.parse("2006-01-02 15:04:05 MST", "2024-12-29 14:30:00 EST")
-- 特定のタイムゾーンで解析
local ny, _ = time.load_location("America/New_York")
local t, err = time.parse("2006-01-02 15:04", "2024-12-29 14:30", ny)
パラメータ説明
layoutstringGo時刻フォーマットレイアウト
valuestring解析する文字列
locationLocationデフォルトタイムゾーン(オプション)

戻り値: Time, error

local t = time.now()
-- 期間を追加(数値、文字列、またはDurationを受け付け)
local tomorrow = t:add("24h")
local later = t:add(5 * time.MINUTE)
local d, _ = time.parse_duration("1h30m")
local future = t:add(d)
-- 時間を減算して期間を取得
local diff = tomorrow:sub(t) -- Durationを返す
print(diff:hours()) -- 24
-- カレンダー単位を追加(月境界を正しく処理)
local next_month = t:add_date(0, 1, 0) -- 1ヶ月追加
local next_year = t:add_date(1, 0, 0) -- 1年追加
local last_week = t:add_date(0, 0, -7) -- 7日減算
メソッドパラメータ戻り値説明
add(duration)number/string/DurationTime期間を追加
sub(time)TimeDuration時間の差分
add_date(years, months, days)numbersTimeカレンダー単位を追加
local t1 = time.date(2024, 1, 1, 0, 0, 0, 0, time.utc)
local t2 = time.date(2024, 1, 2, 0, 0, 0, 0, time.utc)
t1:before(t2) -- true
t2:after(t1) -- true
t1:equal(t1) -- true
メソッドパラメータ戻り値説明
before(time)Timebooleanこの時間は他より前か?
after(time)Timebooleanこの時間は他より後か?
equal(time)Timeboolean時間は等しいか?
local t = time.now()
t:format_rfc3339() -- "2024-12-29T15:04:05Z"
t:format(time.DATE_ONLY) -- "2024-12-29"
t:format(time.TIME_ONLY) -- "15:04:05"
t:format("Mon Jan 2, 2006") -- "Sun Dec 29, 2024"
メソッドパラメータ戻り値説明
format(layout)stringstringGoレイアウトでフォーマット
format_rfc3339()-stringRFC3339としてフォーマット
local t = time.now()
t:unix() -- エポックからの秒数
t:unix_nano() -- エポックからのナノ秒
local t = time.now()
-- 日付部分を取得
local year, month, day = t:date()
-- 時刻部分を取得
local hour, min, sec = t:clock()
-- 個別のアクセサ
t:year() -- 例:2024
t:month() -- 1-12
t:day() -- 1-31
t:hour() -- 0-23
t:minute() -- 0-59
t:second() -- 0-59
t:nanosecond() -- 0-999999999
t:weekday() -- 0=日曜 .. 6=土曜
t:year_day() -- 1-366
t:is_zero() -- ゼロ値の場合true
local t = time.now()
t:utc() -- UTCに変換
t:in_local() -- ローカルタイムゾーンに変換
t:in_location(ny) -- 特定のタイムゾーンに変換
t:location() -- 現在のLocationを取得
t:location():string() -- タイムゾーン名を取得
メソッドパラメータ戻り値説明
utc()-TimeUTCに変換
in_local()-Timeローカルタイムゾーンに変換
in_location(loc)LocationTimeタイムゾーンに変換
location()-Location現在のタイムゾーンを取得

期間境界に丸めまたは切り捨て。Duration userdataが必要(数値や文字列ではない)。

local t = time.now()
local hour_duration, _ = time.parse_duration("1h")
local minute_duration, _ = time.parse_duration("15m")
t:round(hour_duration) -- 最も近い時間に丸め
t:truncate(minute_duration) -- 15分境界に切り捨て
メソッドパラメータ戻り値説明
round(duration)DurationTime最も近い倍数に丸め
truncate(duration)DurationTime倍数に切り捨て
-- 文字列から解析
local d, err = time.parse_duration("1h30m45s")
local d, err = time.parse_duration("500ms")
local d, err = time.parse_duration("2h30m45s500ms")
-- 数値から(ナノ秒)
local d, err = time.parse_duration(time.SECOND)
local d, err = time.parse_duration(5 * time.MINUTE)
-- 有効な単位: ns, us, ms, s, m, h
パラメータ説明
valuenumber/string/Duration解析する期間

戻り値: Duration, error

local d, _ = time.parse_duration("1h30m45s500ms")
d:hours() -- 1.5125...
d:minutes() -- 90.75...
d:seconds() -- 5445.5
d:milliseconds() -- 5445500
d:microseconds() -- 5445500000
d:nanoseconds() -- 5445500000000

IANA名でタイムゾーンをロード(例:“America/New_York”、“Europe/London”、“Asia/Tokyo”)。

local ny, err = time.load_location("America/New_York")
if err then
return nil, err
end
local tokyo, _ = time.load_location("Asia/Tokyo")
local london, _ = time.load_location("Europe/London")
-- タイムゾーン間で変換
local t = time.now():utc()
print("UTC:", t:format(time.TIME_ONLY))
print("New York:", t:in_location(ny):format(time.TIME_ONLY))
print("Tokyo:", t:in_location(tokyo):format(time.TIME_ONLY))
パラメータ説明
namestringIANAタイムゾーン名

戻り値: Location, error

固定UTCオフセットでタイムゾーンを作成。

-- UTC+5:30(インド標準時)
local ist = time.fixed_zone("IST", 5*3600 + 30*60)
-- UTC-8(太平洋標準時)
local pst = time.fixed_zone("PST", -8*3600)
local t = time.date(2024, 1, 15, 12, 0, 0, 0, ist)
パラメータ説明
namestringゾーン名
offsetnumber秒単位のUTCオフセット

戻り値: Location

time.utc -- UTCタイムゾーン
time.localtz -- ローカルシステムタイムゾーン

指定期間だけ実行を一時停止。ワークフローでは、正しく記録・リプレイされます。

time.sleep("5s")
time.sleep(500 * time.MILLISECOND)
-- バックオフパターン
for attempt = 1, 3 do
local ok = try_operation()
if ok then break end
time.sleep(tostring(attempt) .. "s")
end
パラメータ説明
durationnumber/string/Durationスリープ時間

期間後に一度受信するチャネルを返す。channel.selectと連携。

-- シンプルなタイムアウト
local timeout = time.after("5s")
timeout:receive() -- 5秒間ブロック
-- selectでタイムアウト
local response_ch = make_request()
local timeout_ch = time.after("30s")
local result = channel.select{
response_ch:case_receive(),
timeout_ch:case_receive()
}
if result.channel == timeout_ch then
return nil, errors.new({message = "Request timed out", kind = errors.TIMEOUT})
end
パラメータ説明
durationnumber/string/Duration待機時間

戻り値: Channel

期間後に発火するワンショットタイマー。停止またはリセット可能。

local timer = time.timer("5s")
-- タイマーを待機
timer:response():receive()
send_reminder()
-- アクティビティでリセット
local idle_timer = time.timer("5m")
while true do
local r = channel.select{
user_activity:case_receive(),
idle_timer:response():case_receive()
}
if r.channel == idle_timer:response() then
logout_user()
break
end
idle_timer:reset("5m")
end
-- タイマーを停止
timer:stop()
パラメータ説明
durationnumber/string/Duration発火までの時間

戻り値: Timer, error

Timerメソッドパラメータ戻り値説明
response()-Channelタイマーチャネルを取得
channel()-Channelresponse()のエイリアス
stop()-booleanタイマーをキャンセル
reset(duration)number/string/Durationboolean新しい期間でリセット

定期的な間隔で発火する繰り返しタイマー。

-- 定期タスク
local ticker = time.ticker("30s")
local ch = ticker:response()
while true do
local tick_time = ch:receive()
check_health()
end
-- レート制限
local ticker = time.ticker("100ms")
for _, item in ipairs(items) do
ticker:response():receive()
process(item)
end
ticker:stop()
パラメータ説明
durationnumber/string/Durationティック間の間隔

戻り値: Ticker, error

Tickerメソッドパラメータ戻り値説明
response()-Channeltickerチャネルを取得
channel()-Channelresponse()のエイリアス
stop()-booleantickerを停止

期間定数はナノ秒単位。算術で使用。

time.NANOSECOND -- 1
time.MICROSECOND -- 1,000
time.MILLISECOND -- 1,000,000
time.SECOND -- 1,000,000,000
time.MINUTE -- 60 * SECOND
time.HOUR -- 60 * MINUTE
-- 使用例
time.sleep(5 * time.SECOND)
local timeout = time.after(30 * time.SECOND)
time.RFC3339 -- "2006-01-02T15:04:05Z07:00"
time.RFC3339NANO -- "2006-01-02T15:04:05.999999999Z07:00"
time.RFC822 -- "02 Jan 06 15:04 MST"
time.RFC822Z -- "02 Jan 06 15:04 -0700"
time.RFC850 -- "Monday, 02-Jan-06 15:04:05 MST"
time.RFC1123 -- "Mon, 02 Jan 2006 15:04:05 MST"
time.RFC1123Z -- "Mon, 02 Jan 2006 15:04:05 -0700"
time.DATE_TIME -- "2006-01-02 15:04:05"
time.DATE_ONLY -- "2006-01-02"
time.TIME_ONLY -- "15:04:05"
time.KITCHEN -- "3:04PM"
time.STAMP -- "Jan _2 15:04:05"
time.STAMP_MILLI -- "Jan _2 15:04:05.000"
time.STAMP_MICRO -- "Jan _2 15:04:05.000000"
time.STAMP_NANO -- "Jan _2 15:04:05.000000000"
time.JANUARY -- 1
time.FEBRUARY -- 2
time.MARCH -- 3
time.APRIL -- 4
time.MAY -- 5
time.JUNE -- 6
time.JULY -- 7
time.AUGUST -- 8
time.SEPTEMBER -- 9
time.OCTOBER -- 10
time.NOVEMBER -- 11
time.DECEMBER -- 12
time.SUNDAY -- 0
time.MONDAY -- 1
time.TUESDAY -- 2
time.WEDNESDAY -- 3
time.THURSDAY -- 4
time.FRIDAY -- 5
time.SATURDAY -- 6
条件種別再試行可能
無効な期間フォーマットerrors.INVALIDno
解析失敗errors.INTERNALno
空のlocation名errors.INVALIDno
Locationが見つからないerrors.INTERNALno
Duration <= 0(timer/ticker)errors.INVALIDno
local t, err = time.parse(time.RFC3339, "invalid")
if err then
if errors.is(err, errors.INVALID) then
print("Invalid format:", err:message())
end
return nil, err
end
local loc, err = time.load_location("Unknown/Zone")
if err then
if errors.is(err, errors.INTERNAL) then
print("Location not found:", err:message())
end
return nil, err
end

エラーの処理についてはエラー処理を参照。