私はグーグルで多くの解決策を見つけましたが、どれも2012-12-31の正しい週番号を教えてくれませんでした。 MSDNの例( link )でも失敗します。
2012年12月31日は月曜日なので、1週目になるはずですが、私が試したすべての方法で53が得られます。
MDSNライブラリから:
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = dfi.Calendar;
return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
解決策2:
return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
解決策3:
CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;
更新
次のメソッドは、dateが2012-12-31のときに実際には1を返します。言い換えれば、私の問題は私の方法がISO-8601規格に準拠していないことでした。
// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
これに記されているように MSDNページ ISO 8601週と.Net週の番号付けの間にはわずかな違いがあります。
あなたはより良い説明のためにMSDNブログでこの記事を参照することができます: " Microsoft .NetのISO 8601年の週形式 "
簡単に言えば、ISO規格ではそうではありませんが、.NETでは何週間にもわたる週の分割が可能です。この記事には、その年の最後の週の正しいISO 8601週番号を取得するための単純な関数もあります。
Update次のメソッドは実際には2012-12-31
に1を返します。これはISO 8601(ドイツなど)で正しいものです。
// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
一年で52週間以上あるかもしれません。各年は52全週+ 1または+ 2(うるう年)日が追加されています。彼らは53週目を補います。
ですから、毎年少なくとも1日余分な日があります。うるう年に2つ。これらの余分な日数は、それぞれ別の週として数えられますか
何週間あるかは、実際にはその週の開始日によって異なります。これを2012年について考えてみましょう。
現在のCultureの設定をチェックして、週の最初の日として何が使用されているかを確認してください。
ご覧のとおり、結果として53が得られるのは普通です。
54週目もあります。 1月1日と12月31日が別々の週として扱われるとき、28年ごとに起こります。それもうるう年です。
たとえば、2000年は54週間でした。 1月1日(土)が最初の1週間の日で、12月31日(日)が2番目の1週間の日でした。
var d = new DateTime(2012, 12, 31);
CultureInfo cul = CultureInfo.CurrentCulture;
var firstDayWeek = cul.Calendar.GetWeekOfYear(
d,
CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
int weekNum = cul.Calendar.GetWeekOfYear(
d,
CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
int year = weekNum == 52 && d.Month == 1 ? d.Year - 1 : d.Year;
Console.WriteLine("Year: {0} Week: {1}", year, weekNum);
プリントアウト年:2012年週:54
上記の例のCalendarWeekRuleをFirstFullWeekまたはFirstFourDayWeekに変更すると、53に戻ります。ドイツを扱っているので、月曜日の開始日を保ちましょう。
そのため、週53は月曜日の2012-12-31に始まり、1日続き、その後停止します。
正解は53です。試してみたい場合は、カルチャーをドイツに変更してください。
CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");
これが方法です:
public int GetWeekNumber()
{
CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;
}
最も重要なのは、CalendarWeekRule
パラメーターです。
正しいISO-8601の週番号を生成する.Net-cultureがあるようには思われないので、部分的に正しいものを修正するのではなく、組み込みの週の決定を完全に回避して手動で計算します結果。
最後になったのは以下の拡張方法です。
/// <summary>
/// Converts a date to a week number.
/// ISO 8601 week 1 is the week that contains the first Thursday that year.
/// </summary>
public static int ToIso8601Weeknumber(this DateTime date)
{
var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset());
return (thursday.DayOfYear - 1) / 7 + 1;
}
/// <summary>
/// Converts a week number to a date.
/// Note: Week 1 of a year may start in the previous year.
/// ISO 8601 week 1 is the week that contains the first Thursday that year, so
/// if December 28 is a Monday, December 31 is a Thursday,
/// and week 1 starts January 4.
/// If December 28 is a later day in the week, week 1 starts earlier.
/// If December 28 is a Sunday, it is in the same week as Thursday January 1.
/// </summary>
public static DateTime FromIso8601Weeknumber(int weekNumber, int? year = null, DayOfWeek day = DayOfWeek.Monday)
{
var dec28 = new DateTime((year ?? DateTime.Today.Year) - 1, 12, 28);
var monday = dec28.AddDays(7 * weekNumber - dec28.DayOfWeek.DayOffset());
return monday.AddDays(day.DayOffset());
}
/// <summary>
/// Iso8601 weeks start on Monday. This returns 0 for Monday.
/// </summary>
private static int DayOffset(this DayOfWeek weekDay)
{
return ((int)weekDay + 6) % 7;
}
まず第一に、((int)date.DayOfWeek + 6) % 7)
は曜日番号を決定します、0 =月曜日、6 =日曜日。
date.AddDays(-((int)date.DayOfWeek + 6) % 7)
は、要求された週番号に先行する月曜日の日付を決定します。
3日後が目標の木曜日で、その週が何年になるかを決定します。
年内の(ゼロベースの)日数を7(切り捨て)で除算すると、その年の(ゼロベースの)週番号が得られます。
C#では、整数の計算結果は暗黙的に切り捨てられます。
良い知らせです。 プルリクエスト .NET CoreにSystem.Globalization.ISOWeek
を追加することはマージされたばかりで、現在3.0リリースの予定です。うまくいけば、それはそれほど遠くない将来的に他の.NETプラットフォームにも広がるでしょう。
この型には次のシグネチャがあります。これは、ほとんどの--- ISO週 のニーズをカバーするはずです。
namespace System.Globalization
{
public static class ISOWeek
{
public static int GetWeekOfYear(DateTime date);
public static int GetWeeksInYear(int year);
public static int GetYear(DateTime date);
public static DateTime GetYearEnd(int year);
public static DateTime GetYearStart(int year);
public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek);
}
}
あなたはソースコードを見つけることができます ここ 。
上記のコードのC#からPowershellへの移植il_gur:
function GetWeekOfYear([datetime] $inputDate)
{
$day = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetDayOfWeek($inputDate)
if (($day -ge [System.DayOfWeek]::Monday) -and ($day -le [System.DayOfWeek]::Wednesday))
{
$inputDate = $inputDate.AddDays(3)
}
# Return the week of our adjusted day
$weekofYear = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($inputDate, [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday)
return $weekofYear
}
C#とDateTimeクラスを使用して週番号のISO 8601スタイルを決定する最も簡単な方法。
これを尋ねてください。その年の木曜日は今週の木曜日です。答えは、希望の週番号に相当します。
var dayOfWeek = (int)moment.DayOfWeek;
// Make monday the first day of the week
if (--dayOfWeek < 0)
dayOfWeek = 6;
// The whole nr of weeks before this thursday plus one is the week number
var weekNumber = (moment.AddDays(3 - dayOfWeek).DayOfYear - 1) / 7 + 1;
var cultureInfo = CultureInfo.CurrentCulture;
var calendar = cultureInfo.Calendar;
var calendarWeekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
var firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek;
var lastDayOfWeek = cultureInfo.LCID == 1033 //En-us
? DayOfWeek.Saturday
: DayOfWeek.Sunday;
var lastDayOfYear = new DateTime(date.Year, 12, 31);
var weekNumber = calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek);
//Check if this is the last week in the year and it doesn`t occupy the whole week
return weekNumber == 53 && lastDayOfYear.DayOfWeek != lastDayOfWeek
? 1
: weekNumber;
それはアメリカとロシアの文化の両方にうまくいきます。 ISO 8601も正しいでしょう、 `ロシアの週は月曜日に始まります。
これは il_gur の答えの拡張バージョンとnull許容バージョンです。
public static int GetIso8601WeekOfYear(this DateTime time)
{
var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
public static int? GetIso8601WeekOfYear(this DateTime? time)
{
return time?.GetIso8601WeekOfYear();
}
new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null
問題は、1週間が2012年と2013年のどちらであるかをどのように定義するのですか?あなたの仮定は、私が思うに、週の6日は2013年ですので、今週は2013年の最初の週としてマークされるべきです。
これが正しい方法であるかどうかわからない。その週は2012年(月曜日の12月31日)に始まったので、それは2012年の最後の週としてマークされるべきであり、それ故にそれは2012年の53日であるべきです。
これで、曜日情報を使用して、Edge週の特定のケース(年の最初と最後の週)を処理できます。それはすべてあなたの論理次第です。
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
DateTime date1 = new DateTime(2011, 1, 1);
Calendar cal = dfi.Calendar;
Console.WriteLine("{0:d}: Week {1} ({2})", date1,
cal.GetWeekOfYear(date1, dfi.CalendarWeekRule,
dfi.FirstDayOfWeek),
cal.ToString().Substring(cal.ToString().LastIndexOf(".") + 1));