web-dev-qa-db-ja.com

与えられた日付の正しい週番号を取得する

私はグーグルで多くの解決策を見つけましたが、どれも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);
}
181
Amberlamps

これに記されているように 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);
} 
265
il_guru

一年で52週間以上あるかもしれません。各年は52全週+ 1または+ 2(うるう年)日が追加されています。彼らは53週目を補います。

  • 52週間* 7日= 364日。

ですから、毎年少なくとも1日余分な日があります。うるう年に2つ。これらの余分な日数は、それぞれ別の週として数えられますか

何週間あるかは、実際にはその週の開始日によって異なります。これを2012年について考えてみましょう。

  • 米国(日曜日 - >土曜日):2012-12-30および2012-12-31の場合、52週間+短い2日間の週。これにより、合計53週間になります。今年の最後の2日間(日曜日+月曜日)は、それぞれ短い週を構成します。

現在のCultureの設定をチェックして、週の最初の日として何が使用されているかを確認してください。

ご覧のとおり、結果として53が得られるのは普通です。

  • ヨーロッパ(月曜日 - >日曜日):1月2日(2012-1-2)は最初の月曜日なので、これは最初の週の最初の日です。 1月1日の週番号を尋ねると、先週の2011年の一部と見なされるので52に戻ります。

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");
28

これが方法です:

public int GetWeekNumber()
{
    CultureInfo ciCurr = CultureInfo.CurrentCulture;
    int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    return weekNum;
}

最も重要なのは、CalendarWeekRuleパラメーターです。

こちらをご覧ください: https://msdn.Microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=IT-IT&k=k(System.Globalization.CalendarWeekRule); k(TargetFrameworkMoniker-.NETFramework

15
daniele3004

正しい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#では、整数の計算結果は暗黙的に切り捨てられます。

11
realbart

良い知らせです。 プルリクエスト .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);
    }
}

あなたはソースコードを見つけることができます ここ

6
khellang

上記のコードの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
}
3
Rainer

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;
2
user6887101
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も正しいでしょう、 `ロシアの週は月曜日に始まります。

1
Donskikh Andrei

これは 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);
}

NULL可能:

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
0
Jogge

問題は、1週間が2012年と2013年のどちらであるかをどのように定義するのですか?あなたの仮定は、私が思うに、週の6日は2013年ですので、今週は2013年の最初の週としてマークされるべきです。

これが正しい方法であるかどうかわからない。その週は2012年(月曜日の12月31日)に始まったので、それは2012年の最後の週としてマークされるべきであり、それ故にそれは2012年の53日であるべきです。

これで、曜日情報を使用して、Edge週の特定のケース(年の最初と最後の週)を処理できます。それはすべてあなたの論理次第です。

0
Samy Arous
  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));      
0
Imran