# پایگاه‌های داده > SQL Server > T-SQL >  تابع تبدیل شمسی به میلادی در اس کیو ال

## soheila_1643

سلام دوستان من یه جدول دارم که متاسفانه فقط تاریخ شمسی توش ذخیره شده و رکوردای زیادیم توش ثبت شده. حالا نیاز به واکشی اطلاعات در بازه زمانی از این جدول دارم اما با تاریخ شمسی امکان نداره. در ضمن تاریخها هم به این صورت ذخیره شده مثلا 1389/2/3 نه به صورت 1389/02/03 و این هم کار مقایسه رو با مشکل روبرو کرده. حالا چاره چیه؟ چیکار باید بکنم؟ تابع تبدیل شمسی به میلادی تو اس کیو ال هم پیدا نکردم

----------


## soheila_1643

خوب تابعشو پیدا کردم برای استفاده دوستان اینجا میذارم.


CREATE FUNCTION [dbo].[ShamsiToMiladi](@DateStr varchar(10))
RETURNS DATETIME
AS  
BEGIN 
   declare @YYear int
   declare @MMonth int
   declare @DDay int
   declare @epbase int
   declare @epyear int
   declare @mdays int
   declare @persian_jdn int
   declare @i int
   declare @j int
   declare @l int
   declare @n int
   declare @TMPRESULT varchar(10)
   declare @IsValideDate int
   declare @TempStr varchar(20)
   DECLARE @TmpDateStr varchar(10)
  
   SET @i=charindex('/',@DateStr)
  
   IF LEN(@DateStr) - CHARINDEX('/', @DateStr,CHARINDEX('/', @DateStr,1)+1) = 4
   BEGIN
     SET @TmpDateStr = dbo.ReversDate(@DateStr)
     IF ( ISDATE(@TmpDateStr) =1 )  
       RETURN @TmpDateStr
     ELSE
        RETURN NULL
   END
   ELSE
     SET @TmpDateStr = @DateStr
  
   IF ((@i<>0) and
       (dbo.SubStrCount('/', @TmpDateStr)=2) and
        (ISNUMERIC(REPLACE(@TmpDateStr,'/',''))=1) and 
        (charindex('.',@TmpDateStr)=0)
       )
   BEGIN
       SET @YYear=CAST(SUBSTRING(@TmpDateStr,1,@i-1) AS INT)
                IF ( @YYear< 1300 )
                      SET @YYear =@YYear + 1300
                IF @YYear > 9999
                  RETURN NULL
  
       SET @TempStr= SUBSTRING(@TmpDateStr,@i+1,Len(@TmpDateStr))
  
       SET @i=charindex('/',@TempStr)
       SET @MMonth=CAST(SUBSTRING(@TempStr,1,@i-1) AS INT)
       SET @MMonth=@MMonth-- -1
  
       SET @TempStr= SUBSTRING(@TempStr,@i+1,Len(@TempStr))   
  
       SET @DDay=CAST(@TempStr AS INT)
       SET @DDay=@DDay-- - 1
  
                 IF ( @YYear >= 0 )
                     SET @epbase = @YYear - 474
                 Else
                     SET @epbase = @YYear - 473
                 SET @epyear = 474 + (@epbase % 2820)
  
        IF (@MMonth <= 7 )
                       SET @mdays = ((@MMonth) - 1) * 31
        Else
            SET @mdays = ((@MMonth) - 1) * 30 + 6
  
        SET @persian_jdn =(@DDay)  + @mdays + CAST((((@epyear * 682) - 110) / 2816) as int)  + (@epyear - 1) * 365  +  CAST((@epbase / 2820)  as int ) * 1029983  + (1948321 - 1)
  
  
  
        IF (@persian_jdn > 2299160) 
                 BEGIN
            SET @l = @persian_jdn + 68569
            SET @n = CAST(((4 * @l) / 146097) as int)
            SET @l = @l -  CAST(((146097 * @n + 3) / 4) as int)
            SET @i =  CAST(((4000 * (@l + 1)) / 1461001) as int)
            SET @l = @l - CAST( ((1461 * @i) / 4) as int) + 31
            SET @j =  CAST(((80 * @l) / 2447) as int)
            SET @DDay = @l - CAST( ((2447 * @j) / 80) as int)
             SET @l =  CAST((@j / 11) as int)
            SET @MMonth = @j + 2 - 12 * @l
            SET @YYear = 100 * (@n - 49) + @i + @l
                 END
  
           SET @TMPRESULT=Cast(@MMonth as varchar(2))+'/'+CAST(@DDay as Varchar(2))+'/'+CAST(@YYear as varchar(4))  
           RETURN Cast(@TMPRESULT as Datetime)
  
    END
    RETURN NULL      
  
END

CREATE  FUNCTION [dbo].[SubStrCount](@SubStr varchar(8000), @MainText Text)  
RETURNS  int 
AS  
BEGIN 
  DECLARE @StrCount int
  DECLARE @StrPos int
 
  SET @StrCount = 0
  SET @StrPos = 0
  SET @StrPos = CHARINDEX( @SubStr, @MainText, @StrPos)
 
  WHILE @StrPos > 0
  BEGIN
    SET @StrCount = @StrCount + 1
    SET @StrPos = CHARINDEX( @SubStr, @MainText, @StrPos+1)
  END
 
  RETURN  @StrCount  
END


CREATE FUNCTION [dbo].[ReversDate] (@DateStr varchar(10))
RETURNS varchar(10)
 
AS
 
BEGIN
  DECLARE @TempStr varchar(10)
  DECLARE @StartIndex int
  DECLARE @SubStrLen int
  DECLARE @i int
 
  SET @TempStr = ''
  SET @StartIndex = LEN(@DateStr) + 2
  SET @i = LEN(@DateStr)
  WHILE @i > 0
  BEGIN
    IF SUBSTRING(@DateStr,@i,1) IN ('/', '-')
    BEGIN
      SET @SubStrLen = @StartIndex - (@i + 2)
      SET @StartIndex = @i + 1
      SET @TempStr = @TempStr + SUBSTRING(@DateStr,@StartIndex,@SubStrLen) + SUBSTRING(@DateStr,@i,1)
    END
    SET @i = @i - 1
  END
  IF @TempStr <> ''
  BEGIN
    SET @SubStrLen = @StartIndex - 2
    SET @TempStr = @TempStr + SUBSTRING(@DateStr,1,@SubStrLen)
  END
  ELSE
    SET @TempStr = @DateStr
  RETURN @TempStr
END

----------


## masoudies

نحوه استفاده از این تابع در C#‎ چطوریه؟

----------


## masoudies

نحوه استفاده از این تابع در C#‎ چطوریه؟

----------


## یوسف زالی

سلام.
کاربهتر این بود که مقادیر رو اصلاح می کردید.
با توابع SubString , CharIndex می تونید تاریخ ها رو اصلاح کنید به اون فرمی که استاندارد خودتونه. مثلا 01/05/89
بعد به راحتی مقایسه سریعتری انجام بدید.

----------


## rahavard.anf

سلام دوست عزیز میشه لطف کنی یه مثال از 2 تابعی که گفتی بذاری

----------


## یوسف زالی

برای تبدیل یک مثال ساده شده میگذارم:

declare @D varchar(10)
set @D ='13/2/1389'
declare @Part1 varchar(5)
declare @Part2 varchar(5)
declare @Part3 varchar(5)
set @Part1 =SUBSTRING(@D, 1,CHARINDEX('/', @D)-1)
set @D =SUBSTRING(@D,CHARINDEX('/', @D)+1,LEN(@D))
set @Part2 =SUBSTRING(@D, 1,CHARINDEX('/', @D)-1)
set @Part3 =SUBSTRING(@D,CHARINDEX('/', @D)+1,LEN(@D))
declare @X varchar(10)
set @X = @Part3 +'/'+REPLICATE('0', 2-LEN(@Part2))+ @Part2 +'/'+REPLICATE('0', 2-LEN(@Part1))+ @Part1
select @X


شما می تونی این کارو در تابعی انجام بدی و در مقایسه از اون استفاده کنی.

----------


## SayeyeZohor

declare @D varchar(10)
set @D ='13/2/1389'
declare @Part1 varchar(5)
declare @Part2 varchar(5)
declare @Part3 varchar(5)
set @Part1 =SUBSTRING(@D, 1,CHARINDEX('/', @D)-1)
set @D =SUBSTRING(@D,CHARINDEX('/', @D)+1,LEN(@D))
set @Part2 =SUBSTRING(@D, 1,CHARINDEX('/', @D)-1)
set @Part3 =SUBSTRING(@D,CHARINDEX('/', @D)+1,LEN(@D))
declare @X varchar(10)
set @X = @Part3 +'/'+REPLICATE('0', 2-LEN(@Part2))+ @Part2 +'/'+REPLICATE('0', 2-LEN(@Part1))+ @Part1
select @X

----------


## SayeyeZohor

تابع تبدیل میلادی به شمسی



USE [master] 
GO
/****** Object:  UserDefinedFunction [dbo].[IsLeapYear]    Script Date: 08/25/2011 12:16:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        Reza Rad
-- Create date: 8/25/2011
-- Description:    IsLeapYear
-- =============================================
CREATE FUNCTION [dbo].[IsLeapYear] 
(
    @Year int
)
RETURNS bit
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar bit


    -- Add the T-SQL statements to compute the return value here
    if @Year % 400 = 0
       Begin 
            set @ResultVar=1
       end
    else if @Year % 100 = 0
       Begin 
            set @ResultVar=0
       end
    else if @Year % 4 = 0
       Begin 
            set @ResultVar=1
       end
    else
       Begin 
            set @ResultVar=0
       end


    -- Return the result of the function
    RETURN @ResultVar


END
GO
/****** Object:  UserDefinedFunction [dbo].[NumberOfDaysInMonthGregorian]    Script Date: 08/25/2011 12:16:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        Reza Rad
-- Create date: 8/25/2011
-- Description:    Fetch number of days in gregorian month
-- =============================================
CREATE FUNCTION [dbo].[NumberOfDaysInMonthGregorian] 
(
    @Year int
    ,@Month int
)
RETURNS int
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar int


    -- Add the T-SQL statements to compute the return value here
    if(@Month<>2)
    begin
        set @ResultVar=30+((@Month + FLOOR(@Month/8)) % 2)
    end
    else
    begin
        if(dbo.IsLeapYear(@Year)=1)
        begin
            set @ResultVar=29
        end
        else
        begin
            set @ResultVar=28
        end
    end


    -- Return the result of the function
    RETURN @ResultVar


END
GO
/****** Object:  UserDefinedFunction [dbo].[NumberOfDayInMonthPersian]    Script Date: 08/25/2011 12:16:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        Reza Rad
-- Create date: 8/25/2011
-- Description:    Fetch number of days in Persian month
-- =============================================
CREATE FUNCTION [dbo].[NumberOfDayInMonthPersian]
(
    @Year int,-- Gregorian Year
    @Month int -- Presian Month
)
RETURNS int
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar int


    -- Add the T-SQL statements to compute the return value here
    if(@Month<=6)
        set @ResultVar=31
    else
        if(@Month=12)
            if(dbo.IsLeapYear(@Year-1)=1)
                set @ResultVar=30
            else
                set @ResultVar=29
        else
            set @ResultVar=30


    -- Return the result of the function
    RETURN @ResultVar


END
GO
/****** Object:  UserDefinedFunction [dbo].[GregorianToPersian]    Script Date: 08/25/2011 12:16:25 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        Reza Rad
-- Create date: 8/25/2011
-- Description:    Convert gregorian date in type of yyyy-MM-dd format to persian/shamsi date string
-- =============================================
CREATE FUNCTION [dbo].[GregorianToPersian] 
(
    @Date varchar(10)
)
RETURNS varchar(10)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar varchar(10)


    -- Add the T-SQL statements to compute the return value here
    declare @Year int
    declare @Month int
    declare @Day int
    declare @PersianYear int
    declare @PersianMonth int
    declare @PersianDay int
    declare @StartMonthGregorianDateInPersianCalendar int=10
    declare @StartDayGregorianDateInPersianCalendar int=11


    set @Year=convert(int,substring(@Date,1,4))
    set @Month=convert(int,substring(@Date,6,2))
    set @Day=convert(int,substring(@Date,9,2))


    --print @year
    --print @month
    --print @day
    declare @GregorianDayIndex int=0


    if(dbo.IsLeapYear(@Year)=1)
        set @StartDayGregorianDateInPersianCalendar=11
    else
        if(dbo.IsLeapYear(@Year-1)=1)
            set @StartDayGregorianDateInPersianCalendar=12
        else
            set @StartDayGregorianDateInPersianCalendar=11


    --print @StartDayGregorianDateInPersianCalendar            


    declare @m_index int=1
    while @m_index<=@Month-1
    begin
        set @GregorianDayIndex=@GregorianDayIndex+dbo.NumberOf  DaysInMonthGregorian(@Year,@m_index)
        set @m_index=@m_index+1
    end
    set @GregorianDayIndex=@GregorianDayIndex+@Day


    if(@GregorianDayIndex>=80)
    begin
        set @PersianYear=@Year-621
    end
    else
    begin
        set @PersianYear=@Year-622
    end


    declare @mdays int
    declare @m int
    declare @index int=@GregorianDayIndex
    set @m_index=0
    while 1=1
    begin
        if(@m_index<=2)
            set @m=@StartMonthGregorianDateInPersianCalendar+@m_in  dex
        else
            set @m=@m_index-2


        --print 'm='+convert(varchar(max),@m    )
        set @mdays=dbo.NumberOfDayInMonthPersian(@Year,@m)
        if(@m=@StartMonthGregorianDateInPersianCalendar)
            set @mdays=@mdays-@StartDayGregorianDateInPersianCalendar+1


        --print 'mday='+convert(varchar(max),@mdays)
        --print 'index='+convert(varchar(max),@index)
        --print 'm_index='+convert(varchar(max),@m_index)


        if(@index<=@mdays)
        begin
            set @PersianMonth=@m
            if(@m=@StartMonthGregorianDateInPersianCalendar)
                set @PersianDay=@index+@StartDayGregorianDateInPersian  Calendar-1
            else
                set @PersianDay=@index
            break
        end
        else
        begin
            set @index=@index-@mdays
            set @m_index=@m_index+1
        end            
    end


    set @ResultVar=
    convert(varchar(4),@PersianYear)+'/'+
    right('0'+convert(varchar(2),@PersianMonth),2)+'/'+
    right('0'+convert(varchar(2),@PersianDay),2)


    -- Return the result of the function
    RETURN @ResultVar


END
GO



مثال :


select dbo.GregorianToPersian('2014-06-29')


منبع :

http://www.rad.pasfu.com/index.php?/...Converter.html

----------


## SayeyeZohor

http://girlfromoutofthisworld.com/ge...regorian-date/

----------


## علی فتحی

اضافه کردم این اختارو میده

----------


## یوسف زالی

هیچ ربطی به تابع یا دلفی نداره. returns نباید اونجا باشه.

----------


## علی فتحی

کاش حوه استفاده رو هم قرار میدادی چون هی اخطار میده

----------


## علی فتحی

در فانکشن مربوطه چگونه تاریخ رو دون زمان نشون بدم ؟

----------


## mortezamsp

نمیدونستم طور باید این پستم رو پاک کنم.

----------


## seydmohamad1

> سلام دوستان من یه جدول دارم که متاسفانه فقط تاریخ شمسی توش ذخیره شده و رکوردای زیادیم توش ثبت شده. حالا نیاز به واکشی اطلاعات در بازه زمانی از این جدول دارم اما با تاریخ شمسی امکان نداره. در ضمن تاریخها هم به این صورت ذخیره شده مثلا 1389/2/3 نه به صورت 1389/02/03 و این هم کار مقایسه رو با مشکل روبرو کرده. حالا چاره چیه؟ چیکار باید بکنم؟ تابع تبدیل شمسی به میلادی تو اس کیو ال هم پیدا نکردم


سلام اگر تاریخ فارسی را بصورت عددی وارد می کردید با فرمت عددی (13990122) که تشکیل دهنده یک عدد 8 رقمی می شد هم برای سورت کردن خیلی ساده میشد هم استفاده ازش آسان بود

----------

