公開日の間の暦日数を数えるには、経過時間を24で割るのではなく、それぞれの日付を比較します。MacのNumbersでは日付のみの入力を扱えます。タイムスタンプは、まず選択したタイムゾーンで解釈する必要があります。
このガイドでは、架空の公開日とグレゴリオ暦を使います。ここで答えるのは「この2つの公開日は暦上で何日離れていますか?」という問いです。既定の数え方は符号付きの差です。同じ日付なら0、翌日なら1になります。
どの種類の日付情報がありますか?
計算する前に、入力の種類を選びます。出版物に記載された日付と、公開された瞬間を記録したタイムスタンプでは、事前の処理が異なります。
| 入力 | 意味 | 準備 |
|---|---|---|
2025-03-09 |
暦日:年、月、日 | 別のグレゴリオ暦の日付と直接比較する |
2025-03-09T05:00:00Z |
ある瞬間を特定するタイムスタンプ | 選択したレポート用タイムゾーンの日付に変換する |
-05:00 |
UTCオフセット | ある瞬間における現地時刻とUTCの時差を表す |
America/New_York |
名前付きタイムゾーン | 現地の日付やオフセットの切り替わりを解釈するための規則を示す |
オフセットと名前付きタイムゾーンが持つ情報は異なります。あるタイムスタンプに付いたオフセットは、別の日付でのオフセットを示すものではありません。名前付きタイムゾーンは、夏時間の切り替わりを含む、その関係を定める規則を示します。この違いは、RFC 9557「Date and Time on the Internet: Timestamps with Additional Information」で明示されています。
公開日を記録するスプレッドシートでは、次のルールを定めます。すでに暦日として与えられた日付はそのまま使い、タイムスタンプから日付を求める場合は、明示的に選んだ1つのレポート用タイムゾーンを使います。日付だけの値を引き算するために、根拠のない午前0時やオフセットを付けないでください。
暦の標準規格でも日付と日時は区別されます。iCalendar標準では、暦の各要素を含む別個の DATE 値が定義されています。シリアライズ形式では区切り記号なしの数字を使います。このガイドで示すハイフン付きの日付は読みやすさのためのものです。RFC 5545、第3.3.4節を参照してください。
経過秒数を86,400で割るとなぜうまくいかないのですか?
暦日の差は、カレンダー上で何日進んだかを測ります。経過時間の差は、2つの瞬間の間隔を測ります。夏時間の切り替わりをまたぐと、日付が1日進んでも24時間の経過とは限りません。RFC 5545では、タイムゾーンの変更があると、名目上1日の反復間隔が24時間より長くも短くもなり得ることが明記されています。反復に関する説明を参照してください。
America/New_Yorkでの架空の公開日の組み合わせを2つ考えてみましょう。以下では、各端点の現地時刻の午前0時を使って計算しています。オフセットは、IANAのタイムゾーンデータベースにあるニューヨークのタイムゾーン規則と切り替わり規則に従っています。
| 架空の公開日の間隔 | 開始時のオフセット | 終了時のオフセット | 経過時間 | 暦日の差 |
|---|---|---|---|---|
| 2025年3月9日〜10日 | -05:00 |
-04:00 |
23時間 | 1 |
| 2025年11月2日〜3日 | -04:00 |
-05:00 |
25時間 | 1 |
3月の組み合わせに対応するUTCの瞬間は 2025-03-09T05:00:00Z と 2025-03-10T04:00:00Z で、23時間の間隔があります。これを24で割ると約 0.9583 になります。11月の組み合わせで同様に計算すると、約 1.0417 になります。どちらの小数も、暦日についての問いへの答えにはなりません。
これらの例では、丸めると誤りが隠れることがありますが、それで信頼できる数え方が定まるわけではありません。連続する日付の午後11時55分と午前0時5分に公開された2つの出版物は、わずか10分しか離れていませんが、暦日の差は1です。まず日付を取り出してから、その差を計算してください。
Numbersで公開日の間隔を数えるには?
意図する公開日がすでに分かっている場合は、次の方法を使います。Appleの説明によると、DAYS(end-date, start-date)は引数間の日数を返し、終了日が開始日より前なら負の値も返します。NumbersのDAYSリファレンスを参照してください。
空のテーブルがあるNumbersのスプレッドシートを開きます。1行目に項目名を入れ、2行目に以下の数式を1つずつ入力します。数式を入力するには、セルを選択して先頭の = を入力し、式を完成させて Return キーを押します。これはAppleが説明するMac版Numbersでの数式入力手順です。
| セル | 推奨する列名 | 入力する数式 | 期待される値 |
|---|---|---|---|
A2 |
先の公開日 | =DATE(2025,3,9) |
2025年3月9日 |
B2 |
後の公開日 | =DATE(2025,3,10) |
2025年3月10日 |
C2 |
暦日数の差 | =DAYS(B2,A2) |
1 |
DATEを使うと、曖昧な文字列の解釈に頼らず、年、月、日から入力値を構成できます。Appleは日付と時刻の関数一覧で、日付形式の設定が異なっても一貫して解釈できるよう、この関数の使用を勧めています。
3行目で、=DATE(2025,11,2)をA3に、=DATE(2025,11,3)をB3に、=DAYS(B3,A3)をC3に入力して確認します。答えは再び 1 です。与えられた暦日を比較しているため、経過時間の補正は必要ありません。
補助セルを使わずにすばやく計算するには、空のセルに =DAYS(DATE(2025,3,10),DATE(2025,3,9)) を入力します。複数の公開日の組み合わせに使う場合は、列を分ける方法のほうが確認や再利用がしやすくなります。
日付の間隔と、両端を含む日数のどちらを求めますか?
通常の差では、開始日は数える単位に含まれません。3月9日から3月10日までは1日離れています。代わりに、3月9日から3月10日までに含まれる日付ラベルの数を尋ねているなら、答えは2です。
終了日が開始日以降の範囲で両端を含めて数えるには、=DAYS(B2,A2)+1を使います。この式を使う前に、日付の順序を確認してください。差が負なら、入力の順序が逆であることを示す手がかりになります。自動的に絶対値を取ると、その情報が失われます。
1日だけの範囲でも同じ違いがあります。日付の差は0ですが、両端を含む数え方では1日です。スプレッドシートで必要な結果を決め、それに応じた列名を付けてください。
入力がタイムスタンプの場合は?
時刻を取り除く前に、タイムスタンプをレポート用タイムゾーンに変換する必要があります。たとえば、2025-03-10T00:30:00Zは、その日の-04:00オフセットを使うと、America/New_Yorkでは3月9日午後8時30分にあたります。タイムスタンプの先頭10文字をコピーすると、ニューヨークでの公開日ではなくUTCの日付が選ばれてしまいます。
NumbersのDAYSは、ドキュメントに記載された形式では2つの日付引数を受け取り、名前付きタイムゾーンの引数はありません。意図する日付を確定した後で使ってください。Macでタイムスタンプを繰り返し計算するには、FoundationのカレンダーAPIが必要です。
FoundationのDateは、その名前にかかわらず、カレンダーやタイムゾーンに依存しない瞬間を表します。Appleは、暦の計算にはCalendarを使うよう案内しています。公式のDateドキュメントを参照してください。
通常の夏時間の切り替わりには、Foundationで次の手順を使います。グレゴリオ暦とレポート用タイムゾーンを選び、両端の日付それぞれについて現地日の開始時刻を求めてから、日コンポーネントだけを指定して差を求めます。Appleのドキュメントでは、startOfDay(for:)とdateComponents(_:from:to:)の両方が説明されています。
TerminalでFoundationの例を実行する
この任意の方法には、Swiftツールチェーンがインストールされている必要があります。Terminalを開き、Swiftの入門ガイドにある説明に従ってswift --versionを実行し、確認してください。必要であれば、Appleの説明に従ってxcode-select --installでコマンドラインツールをインストールします。続行する前に、インストール画面の操作を完了してください。コマンドラインツールのインストールを参照してください。
以下のブロック全体をTerminalに貼り付けてください。完全なプログラムと架空の入力データが含まれています。小数秒を含まない、明示的なオフセット付きのタイムスタンプを解析します。Appleは、このタイムスタンプ形式での.withInternetDateTimeについて、ISO8601DateFormatterのオプションリファレンスに記載しています。
swift - <<'SWIFT'
import Foundation
let zoneID = "America/New_York"
guard let zone = TimeZone(identifier: zoneID) else {
fatalError("Unknown reporting zone: \(zoneID)")
}
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = zone
let parser = ISO8601DateFormatter()
parser.formatOptions = [.withInternetDateTime]
let samples = [
("Spring", "2025-03-09T00:00:00-05:00",
"2025-03-10T00:00:00-04:00"),
("Autumn", "2025-11-02T00:00:00-04:00",
"2025-11-03T00:00:00-05:00")
]
for (label, startText, endText) in samples {
guard let start = parser.date(from: startText),
let end = parser.date(from: endText) else {
fatalError("Could not parse timestamps for \(label)")
}
let startDay = calendar.startOfDay(for: start)
let endDay = calendar.startOfDay(for: end)
guard let days = calendar.dateComponents(
[.day], from: startDay, to: endDay
).day else {
fatalError("Could not calculate civil days for \(label)")
}
let hours = end.timeIntervalSince(start) / 3600
print("\(label): \(days) civil day(s), \(hours) elapsed hours")
}
SWIFT
実行時には、次の出力が想定されます。数値例は日付計算を使って個別に確認しました。Swiftプログラムは内容を確認しましたが、ここではmacOS上で実行していません。
春:暦日数 1、経過時間 23.0 時間
秋:暦日数 1、経過時間 25.0 時間
プログラムを変更するには、タイムスタンプ文字列を置き換え、レポート用タイムゾーンを慎重に選んでください。タイムスタンプのオフセットは瞬間を特定し、カレンダーのタイムゾーンは、その瞬間がどの現地日付にあたるかを決めます。パーサーが失敗を報告した場合、現在の日付で代用したりレコードを飛ばしたりせず、プログラムは停止します。
この例が受け付けるのは、指定されたオフセット付き形式です。小数秒には別のパーサーオプションが必要です。また、RFC 9557の角括弧付きタイムゾーン注釈には対応していません。ここで示したように、パーサー設定がそれらに対応すると想定せず、名前付きタイムゾーンを別途指定してください。
結果が間違っているように見えるときは、何を確認すべきですか?
以下の順に確認してください。それぞれ異なる原因に対処します。
- 求められている数え方を確認します。 日付の差と両端を含む日数は、開始日より後の日付を対象にする範囲では1日分異なります。
- 入力値を確認します。 日付のみの出版物には、実際の年、月、日を使います。インポートしたタイムスタンプが意図する現地日付をすでに表していると思い込まないでください。
- レポート用タイムゾーンを確認します。 日付を取り出す前に、両方の瞬間を同じ選択済みのタイムゾーンで変換します。
- 計算方法を確認します。 時刻の影響を取り除いてから暦日を数えます。瞬間の間隔を
86,400で割ると、経過時間についての答えになります。 - 順序を確認します。 先の日付と後の日付が逆になっていないか判断するまで、負の結果を保持します。
暦計算のコードでは、現地日の始まりを一意の午前0時と仮定せず、日の開始時刻を求めるAPIを使います。Appleのドキュメントによると、startOfDay(for:)は午前0時が2回存在する場合は最初の時刻を、午前0時が存在しない場合は存在する最初の時刻を選びます。これにより、時刻を手動で0時に設定するだけでは見落とす境界条件に対応できます。startOfDay(for:)を参照してください。
Foundationの例は、通常の夏時間の変更に対応しています。過去に現地日付が丸ごと飛ばされた変更については、グレゴリオ暦の日付ラベルを数えるのか、実際に存在した現地日数を数えるのかをまず決めてください。これは異なる要件です。前者を意図する場合は、日付のみの入力を暦上の日付ラベルとして保持してください。
公開日を扱うスプレッドシートでは、最後の計算はシンプルに保ちます。意図する2つのグレゴリオ暦の日付を確定し、順序を保ったうえで、DAYSを使って間隔を求めます。入力が瞬間を表す場合は、計算前にレポート用タイムゾーンを明示してください。そうすれば、途中で時計が切り替わっても、結果は公開日に基づいたままになります。
出典
DAYS — Apple。
MacのNumbersでテーブルのセル内のデータを使って値を計算する — Apple。
カテゴリ別の関数一覧 — Apple。
RFC 9557: Date and Time on the Internet: Timestamps with Additional Information — IETF。
RFC 5545: Internet Calendaring and Scheduling Core Object Specification (iCalendar) — RFC Editor。
タイムゾーンデータベース:northamerica — IANA。
Date — Apple。
startOfDay(for:) — Apple。
dateComponents(_:from:to:) — Apple。
formatOptions — Apple。
入門 — Swift.org。
コマンドラインツールのインストール — Apple。