ISOWeekは.NET Standard 2.1/.NET Core 3.0より導入されたクラスで、ISO 8601によって定められる週番号・週暦を扱うためのクラスです。 このクラスには、DateTimeで表される日付と、ISO週暦での年(週年)・週番号との相互変換を行うメソッドが用意されています。
以下この文書では、年月日のみ(date)を表すために日付、時分秒のみ(time)を表すために時刻、日付と時刻の組み合わせ(date and time)を表すために日時の各用語を用います。
ISO 8601 週番号・週暦・週年
ここではISO 8601における週番号および関連する用語の整理と簡単な解説をします。 一部非公式な用語を用いている箇所もあるため、正式な用語・厳密な定義についてはISO 8601を参照してください。
ISO 8601における週番号(ISO週番号, week number)は、ある年の日付が、その年の第何週であるかを表すものです。 慣用的には日付を年・月・日の3要素から構成される値(y年m月d日)として表す一方、ISO週番号に基づく暦(ISO週暦, week calendar)では日付を年・週・曜日の3要素(y年第w週d曜日、あるいはy年第w週d日目)で表します。
ISO 8601における週(ISO週, week)では、月曜日が週の第一日、つまり週は月曜日から始まるとされます。 慣用的に用いられる曜日では日曜日や月曜日が週における第一日とされるなど、分野や実装によって週の始まりの定義が異なり、また場合によっては任意に選択可能なこともある中、ISO週・ISO週暦では月曜日が週の始まりであり、これに従って週番号と週年(後述)が定められます。 一方、週が常に7日(7つの曜日)で構成される点は慣用的な週と同じです。
.NETにおいては、曜日を表す列挙体DayOfWeekは日曜日(DayOfWeek.Sunday)が0
となっています。 また、DateTimeFormatInfo.FirstDayOfWeekで暦(DateTimeFormatInfo.Calendar)における最初の曜日を任意に変更することができます。
ISO週暦では、週を基準にした年=週年(ISO週年, week-year)が用いられます。 これにより、ある日付における年月日の年と、それと同一日付の週年は異なる場合があります。
例えば日付2020年1月1日(水曜日)はISO週暦では2020年第1週水曜日(同週3日目)となる一方で、その前日の日付2019年12月31日(火曜日)は2020年第1週火曜日(同週2日目)となります。 逆の例で言えば日付2020年第1週月曜日(同週1日目)は2019年12月30日となります。 このように、ISO週暦における最初週・最終週の週年は、年月日の年とは一致しない場合があります。
ISO週暦では、年(週年)によって週の数が異なり、52または53のいずれかになります。 また、第1週はその年における最初の木曜日が含まれる週とされます。
ISO週年・週 | 月曜日 | 火曜日 | 水曜日 | 木曜日 | 金曜日 | 土曜日 | 日曜日 | 年・月 |
---|---|---|---|---|---|---|---|---|
週第1日目 | 週第2日目 | 週第3日目 | 週第4日目 | 週第5日目 | 週第6日目 | 週第7日目 | ||
2019年第52週 | 12月23日 | 12月24日 | 12月25日 | 12月26日 | 12月27日 | 12月28日 | 12月29日 | 2019年12月 |
2020年第1週 | 12月30日 | 12月31日 | ||||||
1月1日 | 1月2日 | 1月3日 | 1月4日 | 1月5日 | 2020年1月 | |||
2020年第2週 | 1月6日 | 1月7日 | 1月8日 | 1月9日 | 1月10日 | 1月11日 | 1月12日 | |
︙ ︙ |
︙ ︙ |
︙ ︙ |
||||||
2020年第53週 | 12月28日 | 12月29日 | 12月30日 | 12月31日 | 2020年12月 | |||
1月1日 | 1月2日 | 1月3日 | 2021年1月 | |||||
2021年第1週 | 1月4日 | 1月5日 | 1月6日 | 1月7日 | 1月8日 | 1月9日 | 1月10日 | |
ISO週年・週 | 月曜日 | 火曜日 | 水曜日 | 木曜日 | 金曜日 | 土曜日 | 日曜日 | 年・月 |
年・週・曜日の表記
ISO 8601では年・月・日の表記(YYYY-MM-DD)と同様に、年・週・曜日の表記としてYYYY-Www-DDが定められています。 年月日の表記とは異なり、YYYY部分には週年、W
を前置してww部分には週番号、DD部分には曜日番号(weekday number)を代入します。 曜日番号は曜日を1〜7の数字で表す番号で、週の月曜日(第1日)が1
、日曜日(第7日)が7
となります。
日付 | 年・月・日 | 年・週・曜日 |
---|---|---|
2019年12月31日 2020年第1週火曜日(2日目) |
2019-12-31
|
2020-W01-02
|
2020年1月1日 2020年第1週水曜日(3日目) |
2020-01-01
|
2020-W01-03
|
ISOWeekクラス (System.Globalization.ISOWeek)
ISOWeekクラスはISO週・ISO週暦を扱うクラスで、DateTimeで表される日付とISO週番号・週年の変換などを行うことができます。
ISOWeekクラスではDateTimeからの/への変換を行うことができますが、単純に日付のみが扱われます。 そのため、時刻の種類(DateTime.Kind)やオフセット値(DateTimeOffset.Offset)は考慮されません。
DateTimeOffsetで表される日付を変換したい場合は、DateTimeOffset.DateプロパティまたはDateTimeOffset.DateTimeプロパティを参照して日付・日時のみを表すDateTimeを取得して使用します。
ISO週番号・週年の取得 (GetWeekOfYear/GetYear)
GetWeekOfYearメソッドを使用すると、DateTimeの表す日付に対応するISO週番号を取得することができます。 同様に、GetYearメソッドを使用するとISO週年(ISO週暦に基づく年)を取得することができます。
この2つのメソッドを用いることにより、ある日付がISO週暦での何年第何週であるかを求めることができます。
曜日(DayOfWeek列挙体)あるいはDateTimeからISO曜日番号を取得するメソッドは存在しないため、DateTime.DayOfWeekプロパティから得られる値を元に計算する必要があります。 (.NET 5の時点)
この例で使用している、書式と書式プロバイダを指定した書式化については日時・文字列の変換と書式 §.書式とローカライズ、カルチャについてはカルチャの基本・種類・カルチャ情報の取得、日付と時刻の書式についてはカルチャと書式・テキスト処理・暦 §.日付と時間の書式 (DateTimeFormatInfo)を参照してください。
ISO週暦での日付からDateTimeへの変換 (ToDateTime)
ToDateTimeメソッドを使うことにより、ISO週暦でのyear年・第week週・dayOfWeek曜日に対応する日付をDateTimeで取得することができます。
このメソッドでは曜日番号(week number)ではなく曜日(DayOfWeek列挙体)を引数にとるため、曜日番号から日付を求める場合は事前にDayOfWeekに変換する必要があります。
指定された値に該当する日付がDateTimeの最小値・最大値を超える場合や、週番号・曜日が範囲外の場合は、例外ArgumentOutOfRangeExceptionがスローされます。
この例で使用しているGetWeeksInYearメソッドについては§.ISO週暦での年の開始日/終了日/週数の取得 (GetYearStart/GetYearEnd/GetWeeksInYear)を参照してください。
この例で使用している、書式と書式プロバイダを指定した書式化については日時・文字列の変換と書式 §.書式とローカライズ、カルチャについてはカルチャの基本・種類・カルチャ情報の取得、日付と時刻の書式についてはカルチャと書式・テキスト処理・暦 §.日付と時間の書式 (DateTimeFormatInfo)を参照してください。
ISO週暦での年の開始日/終了日/週数の取得 (GetYearStart/GetYearEnd/GetWeeksInYear)
GetYearStartメソッド/GetYearEndメソッドを使用することで、ある年(ISO週年)の開始日・終了日をDateTimeで取得することができます。 また、GetWeeksInYearメソッドを使用することで、ある週年における週の数を求めることができます。
GetYearStartメソッドが返す日付の曜日・DateTime.DayOfWeekプロパティは常に月曜日(DayOfWeek.Monday)、GetYearEndメソッドは常に日曜日(DayOfWeek.Sunday)となります。
ISO週暦・ISO形式での文字列化
DateTime/DateTimeOffsetでは、標準の書式指定子O
/o
(書式指定子 §.O, o (round-trip date/time))またはs
(書式指定子 §.s (sortable date/time))によってISO 8601の拡張形式で文字列化することができます。 ただし、いずれの書式でも日付部分には(グレゴリオ暦での)年月日が用いられます。
ISOWeekクラスには日付をISO週暦での年・週・曜日を用いた形式で文字列化するメソッドは用意されておらず、また(少なくとも.NET 5時点では)標準の書式指定子にもそういった書式は用意されていません。 そのため、必要な場合はISOWeekクラスのメソッドを組み合わせて独自に実装する必要があります。