Ali Majed HA Ответов: 4

Как узнать количество недель в месяце amd month ?


Привет
Я хочу получить данные из базы данных за определенный период времени и показать их на графиках. Мне нужно сгруппироваться по ним, исходя из недели. Например :
1-го января, 2-го января, 3-го января, 4-го января, 1-го февраля, 2-го февраля.
Как я могу этого достичь ?

Что я уже пробовал:

Group By (c => SqlFunctions.DatePart("week", c.MyDate));
// Show just the number of week continuously without showing months


заранее спасибо

4 Ответов

Рейтинг:
24

#realJSOP

Вот обещанный код. На моем сервере БД этот код живет в Reference_Tables база данных. Изменить USE утверждение, отражающее вашу собственную парадигму.

Во-первых, это скалярная функция Ишолидея. Если вам не нужны федеральные праздники, вы можете пропустить это, но если вам это действительно нужно, вы должны добавить эту функцию *перед добавлением сохраненного proc ниже.

USE [Reference_Tables]
GO
/****** Object:  UserDefinedFunction [dbo].[fn_IsHoliday]    Script Date: 01/18/2017 10:39:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- This function returns a bit value of 1 if the specified date is a federal 
-- holiday, or a 0 if it isn't a holiday.
CREATE FUNCTION [dbo].[fn_IsHoliday]
(
    @date  date
)
RETURNS bit
AS
BEGIN

    DECLARE @year  int = DATEPART(YEAR, @date);
    DECLARE @month int = DATEPART(MONTH,@date);
    DECLARE @day   int = DATEPART(DAY, @date);
    DECLARE @dayName varchar(12) = DATENAME(DW, @date );

    DECLARE @nthWeekDay int = ceiling(@day / 7.0);
    DECLARE @isThursday bit = CASE WHEN @dayName LIKE 'Thursday' THEN 1 ELSE 0 END;
    DECLARE @isFriday   bit = CASE WHEN @dayName LIKE 'Friday' THEN 1 ELSE 0 END;
    DECLARE @isSaturday bit = CASE WHEN @dayName LIKE 'Saturday' THEN 1 ELSE 0 END;
    DECLARE @isSunday   bit = CASE WHEN @dayName LIKE 'Sunday' THEN 1 ELSE 0 END;
    DECLARE @isMonday   bit = CASE WHEN @dayName LIKE 'Monday' THEN 1 ELSE 0 END;
    DECLARE @isWeekend  bit = CASE WHEN @isSaturday = 1 OR @isSunday = 1 THEN 1 ELSE 0 END;
     
    ---- New Years Day
    if (@month = 12 AND @day = 31 AND @isFriday=1) return 1;
    if (@month = 1 AND @day = 1 AND @isWeekend=0) return 1;
    if (@month = 1 AND @day = 2 AND @isMonday=1) return 1;

    ---- MLK day
    if (@month = 1 AND @isMonday = 1 AND @nthWeekDay = 3) return 1;

    ------ President’s Day ( 3rd Monday in February )
    if (@month = 2 AND @isMonday = 1 AND @nthWeekDay = 3) return 1;

    ------ Memorial Day ( Last Monday in May )
    if (@month = 5 AND @isMonday = 1 AND DATEPART(MONTH, DATEADD(DAY, 7, @Date)) = 6) return 1;

    ------ Independence Day ( July 4 )
    if (@month = 7 AND @day = 3 AND @isFriday = 1) return 1;
    if (@month = 7 AND @day = 4 AND @isWeekend = 0) return 1;
    if (@month = 7 AND @day = 5 AND @isMonday = 1) return 1;

    ------ Labor Day ( 1st Monday in September )
    if (@month = 9 AND @isMonday = 1 AND @nthWeekDay = 1) return 1;

    ------ Columbus Day ( 2nd Monday in October )
    if (@month = 10 AND @isMonday = 1 AND @nthWeekDay = 2) return 1;

    ------ Veteran’s Day ( November 11 )
    if (@month = 11 AND @day = 10 AND @isFriday = 1) return 1;
    if (@month = 11 AND @day = 11 AND @isWeekend = 0) return 1;
    if (@month = 11 AND @day = 12 AND @isMonday = 1) return 1;

    ------ Thanksgiving Day ( 4th Thursday in November )
    if (@month = 11 AND @isThursday = 1 AND @nthWeekDay = 4) return 1;

    ------ Christmas Day ( December 25 )
    if (@month = 12 AND @day = 24 AND @isFriday = 1) return 1;
    if (@month = 12 AND @day = 25 AND @isWeekend = 0) return 1;
    if (@month = 12 AND @day = 25 AND @isMonday = 1) return 1;

    return 0;
END

GO



Эта хранимая процедура возвращает таблицу дат на основе указанного диапазона дат (при желании диапазон дат может быть одним днем).

USE [Reference_Tables]
GO

/****** Object:  StoredProcedure [dbo].[sp_GetCalendar]    Script Date: 01/18/2017 10:38:19 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[sp_GetCalendar]
    @startDate DATE, -- the start of the date range
    @endDate   DATE -- the end of the date range
AS
BEGIN
    SET NOCOUNT ON;
    
    -- sanity check - if the start date is not earlier than or equal to the 
    -- end date, switch them around
    if (@startDate > @endDate)
    BEGIN
        DECLARE @temp date = @startDate;
        SET @startDate = @endDate;
        SET @endDate = @temp;
    END
    
    ;WITH n AS 
    (
        SELECT TOP (DATEDIFF(DAY, @startDate, @endDate) + 1) n = ROW_NUMBER() OVER (ORDER BY [object_id]) 
        FROM sys.all_objects
    )
    SELECT DATEADD(DAY, n-1, @startDate) AS CalendarDate
           ,DATEPART(YEAR, DATEADD(DAY, n-1, @startDate)) AS CalendarYear
           ,DATEPART(MONTH, DATEADD(DAY, n-1, @startDate)) AS CalendarMonth
           ,DATEPART(QUARTER, DATEADD(DAY, n-1, @startDate)) AS CalendarQuarter
           ,DATEPART(DAYOFYEAR, DATEADD(DAY, n-1, @startDate)) As CalendarJulianDay
           ,DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate)) AS FiscalDate
           ,DATEPART(YEAR, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalYear
           ,DATEPART(MONTH, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalMonth
           ,DATEPART(QUARTER, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalQuarter
           ,DATEPART(DAYOFYEAR, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) As FiscalJulianDay
           ,DATENAME(MONTH, DATEADD(DAY, n-1, @startDate)) AS [MonthName]
           ,DATEPART(DAY, DATEADD(DAY, n-1, @startDate)) AS [DayOfMonth]
           ,DATEPART(WEEKDAY, DATEADD(DAY, n-1, @startDate)) AS WeekDayNumber
           ,DATENAME(WEEKDAY, DATEADD(DAY, n-1, @startDate)) AS WeekDayName
           ,ceiling(DATEPART(DAY, DATEADD(DAY, n-1, @startDate)) / 7.0) As NthWeekday
           -- if you didn't need the IsHoliday function, simply comment out 
           -- the following line
           ,dbo.fn_IsHoliday(DATEADD(DAY, n-1, @startDate)) AS IsHoliday
    FROM n;
END

GO


Чтобы получить N-ю неделю (в месяце), на которую приходится дата, вы можете использовать возвращенную NthWeekday колонка.


Ali Majed HA

Привет, Джон, большое спасибо. Я ждал вашего решения. Это решило мою проблему. Спасибо.

Рейтинг:
2

#realJSOP

Какое совпадение - я просто написал какой-то SQL-код, который создает календарь, основанный на указанном диапазоне дат. Это не что иное, как хранимый процесс и функция, которую вы реализуете в своей базе данных. Просто вызовите сохраненный proc, и он вернет "календарь", который включает в себя календарный год, месяц, день, юлианский день и квартал, финансовый год, месяц, квартал и юлианский день, а также n-й будний день, N-ю неделю и независимо от того, является ли эта дата федеральным праздником (с учетом праздников, приходящихся на выходные).

Бизнес-кейс, который стимулировал это развитие, состоял в том, что аналитики использовали таблицу, в которой были данные, которые не шли дальше 31 декабря 2016 года, и которые должны были вручную обновляться каждый год. Мой подход не требует таблиц и может возвращать информацию календаря для любого диапазона дат.

Когда я вернусь на работу в понедельник,я отправлю его сюда.


Ali Majed HA

Здравствуйте, спасибо за ваш ответ, я буду ждать вашего решения. Еще раз большое спасибо

Рейтинг:
1

José Amílcar Casimiro

Привет,

Простой код:

// 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);
} 


Подробнее: Формат Недели года ISO 8601 в Microsoft .Сеть-я не Клингон[^]

С уважением,
@jafc


Ali Majed HA

Привет @jafc, большое спасибо за ваше решение.В этой конкретной задаче решение № 3 решило ее. Спасибо снова.

Рейтинг:
0

Richard MacCutchan

Видеть Номера недель в соответствии с ISO8601[^] который показывает, как найти конкретный день начала года. Из этого вы должны быть в состоянии экстраполировать даты, которые вы ищете.


Ali Majed HA

Здравствуйте, большое спасибо за ваше решение. Но он не даст мне номер недели в зависимости от месяца. Например, я не могу обозначить свой график "1-й Январь", что означает 1-ю неделю января. например, за последние 3 месяца это дает мне 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 без определения месяца

Richard MacCutchan

Многое зависит от того, где начинаются ваши недели.

Ali Majed HA

В моей стране пятница-это последняя неделя, но я еще не преобразовал DtaeTime, поэтому буду считать, что воскресенье-это последнее, и ваша ссылка на помощь отлично подходит для его определения.