作業時間明細(task_time_worked)は継承でなく参照
Incident や Change のフォームを下までスクロールすると、「Time Worked(作業時間)」という関連リストや、ストップウォッチのようなタイマーを見かけます。あの「このチケットに何時間かけたか」を1件ずつ記録しているのが、task_time_worked というテーブルです。
この記事は、ITSM の各プロセス画面には慣れてきて、その裏でどう作業時間が貯まっているのかを確認したい管理者・開発者を想定しています。PDI(Zurich / OOTB)で task_time_worked を実際に開き、実機の全8件のデータとともに次の3点を確認します。1点目は、task_time_worked が task を「継承」した子テーブルではなく、task を「参照」してぶら下がる明細テーブルだという点です。2点目は、1つのタスクに対して「誰が・何時間」を複数行で積み上げる構造である点です。3点目は、time_worked が duration(HH:MM:SS)型で持たれる点です。
この記事で分かること
task_time_worked が、task 系レコードに「誰が・何時間」作業したかを1件ずつ積む作業時間明細テーブルであること
これは テーブル継承の子ではなく、task フィールドで task を参照する 1対多の明細であること(継承との違い)
主要フィールド task / user / time_worked / time_in_seconds / comments の役割(PDI 実測)
time_worked が glide_duration 型で「HH:MM:SS」、その秒数を time_in_seconds が別に持つこと
PDI 実機の 全8件が、3つの incident に「誰がどれだけ」で積まれている実際の分布(合計38時間)
この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich(ズーリッヒ)リリースの OOTB(初期設定)で確認した個人メモです。本番環境やカスタマイズ済み環境では、フィールド構成・レコード件数・分布が異なります。
task_time_worked とは
task_time_worked(ラベルは Time Worked)は、「あるタスクに対して、誰が・どれだけの時間、作業したか」を1件ずつ記録するテーブルです。下の画面は、PDI(Zurich / OOTB)の task_time_worked を Task でグループ化したものです。INC0000009・INC0000012・INC0000013 という incident ごとに、作業時間のレコードがぶら下がっているのが分かります。

ポイントは、task_time_worked のレコードには番号(INCxxxxx のような採番)が無いことです。実機でテーブル定義(sys_db_object)を見ると number_ref は空で、これらの明細は採番されず、識別は sys_id だけで行われます。あくまで「親タスクにぶら下がる明細」だからです。

つまり task_time_worked は、タスク1件に対する作業時間のタイムシート明細にあたります。
「継承」ではなく「参照」でぶら下がる
ここが一番の勘所です。「task 系のテーブル」と聞くと、Incident や Problem のように task を継承(テーブル拡張)した子テーブルをイメージする人が多いはずです。しかし task_time_worked は継承の子ではありません。
実機で sys_db_object を確認すると、task_time_worked の super_class(継承元)は空でした。task を継承しておらず、代わりに task という参照(reference)フィールドで task テーブルを指しているだけです。これは「1つのタスク : 複数の作業時間明細」という 1対多のリレーション(外部キー)であって、テーブル継承とはまったく別の繋がり方です。

継承(incident など) … task の構造を引き継いで「task の一種」になる。詳しくは「ServiceNow の task テーブルを実機で読み解く」で検証しています。incident / problem / change が task を継承する仕組みを扱った記事です。
参照(task_time_worked) … task の構造は引き継がず、task フィールドで特定の1件を指して明細として付随する。
この違いを押さえると、フォーム上の「Time Worked 関連リスト」が、なぜ別テーブルのレコードとして表示されるのかが腑に落ちます。
主要フィールド:task / user / time_worked
task_time_worked が自分自身に持つフィールドはシンプルです。PDI 実測の主要フィールドは次のとおりでした。


中心になるのは task(どのタスクの作業か)・user(誰が作業したか)・time_worked(どれだけ作業したか)の3つです。
task … 作業対象のタスクへの参照(reference → task)。incident でも change でも、task 系なら何でも指せます。
user … 作業者(reference → sys_user)。「誰が」を表します。
time_worked … 所要時間。glide_duration 型で持たれます。
time_in_seconds … time_worked を秒数(整数)で持つフィールド。集計・レポート用です。
comments … 補足コメント(最大1000文字)。
なお、当初「category(区分)」フィールドがあると想定していました。しかし OOTB Zurich の task_time_worked に category フィールドは存在しませんでした(dict 実測で確認)。事実は実機優先で記録しています。
下は task_time_worked のレコードを1件フォームで開いたものです。Task=INC0000012、User=Beth Anglin、Time worked=10 Hours が入っているのが分かります。

time_worked は duration、秒は time_in_seconds が持つ
時間の持ち方にも特徴があります。time_worked は glide_duration 型で、内部的には「1970-01-01 を起点とした経過時間」として保持されます。たとえば6時間の作業は、値としては 1970-01-01 06:00:00、表示は 6 Hours(= 06:00:00)になります。
duration のままだと合計や平均が取りにくいので、ServiceNow は同じ時間を秒数で持つ time_in_seconds(整数)を併せて用意しています。6時間なら 21,600 という具合です。レポートやスクリプトで集計するときは、この time_in_seconds を合計するのが扱いやすくなっています。
区分 フィールド 型 6時間の例
--------------------------------------------------
表示用 time_worked glide_duration 06:00:00(6 Hours)
集計用 time_in_seconds integer 21,600ちなみに、task テーブル自身にも time_worked という同名フィールドがあります。そちらは type=timer(実行中のストップウォッチ)で、明細テーブルの time_worked(duration)とは別物です。実機では INC0000012 が17時間ぶんの明細を持っていました。一方、incident 側の time_worked(Timer)フィールドは空でした。つまり明細の合計が自動でタスク本体のタイマー欄に書き戻されるわけではありません。誰が何時間の履歴の正本は、あくまで task_time_worked 側にあると読み取れます(タイマー UI の内部挙動自体は検証範囲外です)。
フォームのタイマーから明細が1件ずつ積まれる
実運用での流れはシンプルです。担当者が作業し、フォーム下部の Time Worked タイマーを停止するか、関連リストから手動で1件追加すると、task_time_worked のレコードが1件作られます。これが関連リストに積み上がっていきます。

実際に incident(INC0000012)のフォームを開くと、Time Worked 関連リストに複数の作業時間明細が並びます。1つの incident に対して、複数の作業ログが時系列で積まれている様子が確認できます。

このように、1タスク : N 明細で積んでいくのが task_time_worked の基本動作です。
実機の8件はどう積まれていたか
PDI(Zurich / OOTB)の task_time_worked は、全部で 8件でした。その内訳は、3つの incident にきれいに分かれています。


INC0000009 … Joe Employee が 6時間 + 5時間 = 計11時間(2件)
INC0000012 … Beth Anglin が 10時間 + 5時間 + 2時間 = 計17時間(3件)
INC0000013 … Sam Sorokin が 2時間 + 4時間 + 4時間 = 計10時間(3件)
合計 8件・38時間(136,800秒)
このデモデータでは、各 incident の作業時間がすべて単一の作業者に紐づいていました(一般には、1つのタスクに複数ユーザーが工数を積めます)。「誰が・どのタスクに・何時間」という3点が、明細1行ずつに正確に残っているのが分かります。これらの incident そのものの構造は「Incident テーブルの構造を実機で読み解く」で検証しています。あわせて読むと、「チケット本体」と「その作業時間明細」の関係が立体的に見えてきます。
実機で確認するときに見るべきURL
最後に、今回見た画面を自分のインスタンスで開くためのURLをまとめます(<YourInstance> は置き換えてください)。
# task_time_worked を Task でグループ化(タスク別に明細が積まれる)
https://<YourInstance>/task_time_worked_list.do?sysparm_query=GROUPBYtask
# task_time_worked を User でグループ化(作業者別)
https://<YourInstance>/task_time_worked_list.do?sysparm_query=GROUPBYuser
# task_time_worked のフィールド定義
https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=task_time_worked^elementISNOTEMPTYまとめ
task_time_worked(Time Worked)は、task 系レコードに「誰が・何時間」作業したかを1件ずつ積む作業時間明細テーブル。番号は付かず(採番なし)、sys_id で識別。
これは テーブル継承の子ではなく、task 参照フィールドでぶら下がる 1対多の明細。継承(incident 等)とは繋がり方が違う。
主役フィールドは task(どのタスク)/ user(誰が)/ time_worked(どれだけ)。time_worked は glide_duration(HH:MM:SS)、集計用の秒数を time_in_seconds が別に持つ。OOTB に category フィールドは無い。
フォームの Time Worked 関連リスト/タイマーから1件ずつ生成され、タスクに積み上がる。タスク本体の time_worked(Timer)とは別物。
PDI 実機は 全8件、3つの incident に 38時間ぶんが「誰が・何時間」で記録されていた。
作業時間の正体が「タスクにぶら下がる明細テーブル」だと分かると、SLA やレポートで出てくる工数の数字が、どのレコードから来ているのかを自分で辿れるようになります。まずは土台である「task テーブルの基底と継承」とあわせて読むのがおすすめです。