Как вы получаете номер календарной недели, как в Outlook? - PullRequest
0 голосов
/ 14 марта 2020

Мне нужно показать календарную неделю даты, используя ту же нумерацию, что и в Outlook.
Нумерация должна соответствовать итальянской (it-IT) культуре.
Календарь Outlook настроен с использованием понедельника в качестве первого дня неделю и «1 января всегда в неделю 1».
Пример другого календаря, использующего те же логики нумерации c , приведен здесь (возможно, вам нужно включить номера недели).

Я пробовал разные методы, но я не получаю правильный номер недели с некоторыми датами.
В частности, я пытался использовать:

  • Calendar возвращено с CultureInfo.GetCulture("it-IT")
  • GregorianCalendar
  • ISOWeek

Некоторые даты, которые я пробовал:

  • 31 декабря 200
  • 29 марта 2021
  • 31 декабря 2012
  • 21 декабря 1992
  • 30 декабря 2019

Единственный надежный способ Я нашел правильный номер недели, чтобы вычислить его сам, но мне не очень нравится идея зависеть от моего кода вычисления даты (я не могу быть на 100% уверен, что нашел правильный лог c Я не могу проверить каждую возможную дату).

Ниже приведена программа, показывающая различные результаты для каждого метода, который я пробовал, и способ вычисления номеров недель вручную.
Вы также можете попробовать его здесь.

Вывод примера (в виде изображения для отображения различных цветов):
Example program output

Так что вопрос: есть ли встроенный способ получить номера недели из даты, используя те же номера нумерации c, используемые Outlook?

РЕДАКТИРОВАТЬ:

Я уже пытался использовать CalendarWeekRule.FirstFourDayWeek и CalendarWeekRule.FirstFullWeek

Пример программы, о которой я говорил:

    public sealed class Program
    {
        private static Calendar italianCalendar = CultureInfo.GetCultureInfo("it-IT").Calendar;
        private static Calendar plainGregorianCalendar = new GregorianCalendar();

        public static void Main()
        {
            var _31stOfDecember2000 = new DateTime(2000, 12, 31);
            var _29thOfMarch2021 = new DateTime(2021, 3, 29);
            var _31stOfDecember2012 = new DateTime(2012, 12, 31);
            var _21stDecember1992 = new DateTime(1992, 12, 21);
            var _30thDecember2019 = new DateTime(2019, 12, 30);
            var _1stOfJanuary2013 = new DateTime(2013, 1, 1);

            PrintWeek(_31stOfDecember2000, 53);
            PrintWeek(_29thOfMarch2021, 14);
            PrintWeek(_31stOfDecember2012, 1);
            PrintWeek(_21stDecember1992, 52);
            PrintWeek(_30thDecember2019, 1);
            PrintWeek(_1stOfJanuary2013, 1);

            Console.ReadKey();
        }

        private static void PrintWeek(DateTime date, int expectedWeek)
        {
            var isoWeek = ISOWeek.GetWeekOfYear(date);
            var italianCalendarWeek = italianCalendar.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
            var gregorianCalendarWeek = plainGregorianCalendar.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
            var manuallyCalculatedWeek = CalculateWeek(date);

            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("Date: {0:yyyy MMMM dd} - Expected week {1}", date, expectedWeek);

            Console.ForegroundColor = isoWeek == expectedWeek ? ConsoleColor.Green : ConsoleColor.Red;
            Console.WriteLine("ISO Week: {0}", isoWeek);

            Console.ForegroundColor = italianCalendarWeek == expectedWeek ? ConsoleColor.Green : ConsoleColor.Red;
            Console.WriteLine("Italian calendar Week: {0}", italianCalendarWeek);

            Console.ForegroundColor = gregorianCalendarWeek == expectedWeek ? ConsoleColor.Green : ConsoleColor.Red;
            Console.WriteLine("Gregorian calendar Week: {0}", gregorianCalendarWeek);

            Console.ForegroundColor = manuallyCalculatedWeek == expectedWeek ? ConsoleColor.Green : ConsoleColor.Red;
            Console.WriteLine("Manually calculated Week: {0}", manuallyCalculatedWeek);

            Console.WriteLine();
        }

        public static int CalculateWeek(DateTime date)
        {
            var firstDayOfFirstWeekOfDateYear = StartOfWeekOfYear(date.Year, 1);
            var firstDayOfFirstWeekOfNextYear = StartOfWeekOfYear(date.Year + 1, 1);
            var lastDayOfLastWeekOfDateYear = firstDayOfFirstWeekOfNextYear.AddDays(-1);

            var timePassedSinceFirstWeek = date - firstDayOfFirstWeekOfDateYear;
            var daysPassedSinceFirstWeek = timePassedSinceFirstWeek.Days;

            var timePassedBetweenFirstAndEndOfYear = lastDayOfLastWeekOfDateYear - firstDayOfFirstWeekOfDateYear;
            var daysPassedBetweenFirstAndEndOfYear = timePassedBetweenFirstAndEndOfYear.Days;

            var weeksOfDateYear = (daysPassedBetweenFirstAndEndOfYear / 7) + 1;

            //If the week number surpasses the effective number of weeks of the year it is wrapped around the next year using modulo operator
            //Modulo will wrap the week number around the Year weeks leaving the reminder of the calculation as the Week number of the next year.
            var week = (daysPassedSinceFirstWeek / 7 % weeksOfDateYear) + 1;

            return week;
        }

        private static DateTime StartOfWeekOfYear(int year, int week)
        {
            var firstOfJanuary = new DateTime(year, 1, 1);

            var dayOfWeekFirstOfJanuary = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(firstOfJanuary);

            //Sunday is 0 instead of 7, screwing calculations over
            var dayOfWeekOffset = dayOfWeekFirstOfJanuary == DayOfWeek.Sunday ? -6 : DayOfWeek.Monday - dayOfWeekFirstOfJanuary;

            var daysOffset = (7 * (week - 1)) + dayOfWeekOffset;

            return firstOfJanuary.AddDays(daysOffset);
        }

1 Ответ

1 голос
/ 14 марта 2020

Я адаптировал ответ из приведенного выше в соответствии с вашими требованиями. Результаты совпадают со всеми приведенными выше ручными расчетами.

using System;
using System.Globalization;

public class Program
{
    public static void Main()
    {
        var today = new DateTime(2000, 12, 31);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
        today = new DateTime(2021, 3, 29);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
        today = new DateTime(2012, 12, 31);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
        today = new DateTime(1992, 12, 21);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
        today = new DateTime(2009, 12, 30);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
        today = new DateTime(2013, 1, 1);
        Console.WriteLine(string.Format("{0} {1} {2} {3}", today, today.GetWeekOfYear("it-it"), today.DayOfWeek, today.DayOfYear));
    }
}

static class DateTimeExtensions
{
    public static int GetWeekOfYear(this DateTime time, string languageTag)
    {
        // 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
        var culture = CultureInfo.GetCultureInfoByIetfLanguageTag(languageTag);
        var day = culture.Calendar.GetDayOfWeek(time);
        if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
        {
            time = time.AddDays(3);
        }

        // Return the week of our adjusted day
        return culture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...