2012-03-12 72 views
1

我試圖轉換JDE dates,並且已經積累了大量信息,並想通過嘗試執行SQL轉換函數來簡化某些任務。將JDE Julian日期轉換爲Gregorian

這是我想到了,我只需撥打「ToGregorian」

CREATE FUNCTION [dbo].[ToGregorian](@julian varchar(6)) 
RETURNS datetime AS BEGIN 
    DECLARE @datetime datetime 

    SET @datetime = CAST(19+CAST(SUBSTRING(@julian, 1, 1) as int) as varchar(4))+SUBSTRING(@julian, 2,2)+'-01-01' 
    SET @datetime = DATEADD(day, CAST(SUBSTRING(@julian, 4,3) as int)-1, @datetime) 

    RETURN @datetime 
END 
  1. 採用「朱利安」字符串的函數。
  2. 採取第一個字母,並將其添加到世紀,從19日開始。
  3. 從接下來的2個字符中增加十年和幾年。
  4. 最後添加天數,這是最後3個字符,並減去1,因爲它已經在第一個設置中有1天。 (如:2011-01-01)
  5. 結果前:111186 =>2011-07-05 00:00:00.000

在我看來,這是一個有點笨拙和矯枉過正,而且我希望有這樣做的更好的方法。也許我做了太多的轉換,或者我應該使用不同的方法?

有什麼建議如何改進功能?
也許是另一種更好的方法?
不介意它是否可讀性更好......

我也有一個內聯版本,如果例如我只有閱讀權限並且不能使用函數,凌亂,是否有可能使其更具可讀性,或更好?

CAST(REPLACE(Convert(VARCHAR, DATEADD(d,CAST(SUBSTRING(CAST([column] AS VARCHAR), 4,3) AS INT)-1, CAST(CAST(19+CAST(SUBSTRING(CAST([column] AS VARCHAR), 1,1) AS INT) AS VARCHAR)+SUBSTRING(CAST([column] AS VARCHAR), 2,2) + '-01-01' AS DATETIME)), 111), '/', '-') AS DATETIME) 
+0

如果日期是在20世紀,是主角字符0還是字符串5位數字? – 2012-03-12 17:10:06

+0

@AaronBertrand這將是5位數,但我所見到的表中沒有一個日期低於2000年,因爲我公司使用的系統是在2003年左右建立的。它不應該是一個問題,但它提出了一個問題,如果我不得不考慮這個問題,查詢將會有什麼不同? – ShadowScripter 2012-03-12 17:21:02

+0

你應該使用'RIGHT('0'+ column,6)'是安全的,或者添加一個約束來檢查'LEN(column)= 6'和/或'LEFT(column,1)='1'' 。 – 2012-03-12 17:30:55

回答

3

我認爲使用本地日期時間數學比使用各種字符串,日期和數字格式來回切換效率更高效。

DECLARE @julian VARCHAR(6) = '111186'; 

SELECT DATEADD(YEAR, 
    100*CONVERT(INT, LEFT(@julian,1)) 
    +10*CONVERT(INT, SUBSTRING(@julian, 2,1)) 
    +CONVERT(INT, SUBSTRING(@julian,3,1)), 
DATEADD(DAY, CONVERT(INT,SUBSTRING(@julian, 4, 3))-1, 
0)); 

結果:

=================== 
2011-07-05 00:00:00 

假設這個數據不經常更改,也可能是更有效的實際存儲的時間作爲計算列(這就是爲什麼我選擇的基準日0而不是某些字符串表示形式,這會導致確定性問題,阻止列被持久化並可能編入索引)。

CREATE TABLE dbo.JDEDates 
(
    JDEDate VARCHAR(6), 

    GregorianDate AS CONVERT(SMALLDATETIME, 
     DATEADD(YEAR, 
     100*CONVERT(INT, LEFT(RIGHT('0'+JDEDate,6),1)) 
     +10*CONVERT(INT, SUBSTRING(RIGHT('0'+JDEDate,6), 2,1)) 
     +CONVERT(INT, SUBSTRING(RIGHT('0'+JDEDate,6),3,1)), 
     DATEADD(DAY, CONVERT(INT, RIGHT(JDEDate, 3))-1, 
     0)) 
    ) PERSISTED 
); 

INSERT dbo.JDEDates(JDEDate) SELECT '111186'; 

SELECT JDEDate, GregorianDate FROM dbo.JDEDates; 

結果:

JDEDate GregorianDate 
======= =================== 
111186 2011-07-05 00:00:00 

即使你不索引列,它仍然隱藏醜陋的計算離你而去,而你堅持只支付,在寫的時候,因爲它不」牛逼導致每當列引用您在查詢時進行昂貴的功能操作...

+0

不幸的是,我只有在官方工作服務器上讀取權限。我有一個服務器,我是管理員,但我直接使用格雷戈裏來代替。你的解決方案看起來很優雅,你能否帶我走過你正在做的事情,爲什麼? :P – ShadowScripter 2012-03-12 17:36:17

+0

我完全按照你所描述的公式描述,但順序相反。從右到左工作,我將基準日期(0 = 1900-01-01)加上天數(JDE的最後3位數)減1,然後加上年數(第三位數)+數十年(這是第二位數字的10倍+數百年(這是第一位數字) – 2012-03-12 17:40:33

+0

PS僅僅因爲您沒有在服務器上寫入權限並不意味着您不能在那裏實現某些功能。*你寫的任何*到服務器的方式如何? – 2012-03-12 17:42:56

0
USE [master] 
GO 
/****** Object: UserDefinedFunction [dbo].[ToGregorian] Script Date: 08/18/2015 14:33:17 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER FUNCTION [dbo].[ToGregorian](@julian varchar(6),@time varchar(6)) 
RETURNS datetime 
AS 
BEGIN 
    DECLARE @datetime datetime,@hour int, @minute int, @second int 

    set @time = ltrim(rtrim(@time)); 
    set @julian = ltrim(rtrim(@julian)); 

    if(LEN(@julian) = 5) 
     set @julian = '0' + @julian 


    IF(LEN(@time) = 6) 
     BEGIN 
      SET @hour = Convert(int,LEFT(@time,2)); 
      SET @minute = CONVERT(int,Substring(@time,3,2)); 
      SET @second = CONVERT(int,Substring(@time,5,2)); 
     END 
    else IF(LEN(@time) = 5) 
     BEGIN 
      SET @hour = Convert(int,LEFT(@time,1)); 
      SET @minute = CONVERT(int,Substring(@time,2,2)); 
      SET @second = CONVERT(int,Substring(@time,4,2)); 
     END 
    else IF(LEN(@time) = 4) 
     BEGIN 
      SET @hour = 0; 
      SET @minute = CONVERT(int,LEFT(@time,2)); 
      SET @second = CONVERT(int,Substring(@time,3,2)); 
     END 
    else IF(LEN(@time) = 3) 
     BEGIN 
      SET @hour = 0; 
      SET @minute = CONVERT(int,LEFT(@time,1)); 
      SET @second = CONVERT(int,Substring(@time,2,2)); 
     END 
    else 
     BEGIN 
      SET @hour = 0; 
      SET @minute = 0; 
      SET @second = @time; 
     END 

    SET @datetime = DATEADD(YEAR,100*CONVERT(INT, LEFT(@julian,1))+10*CONVERT(INT, SUBSTRING(@julian, 2,1))+CONVERT(INT, SUBSTRING(@julian,3,1)),0);      
    SET @datetime = DATEADD(DAY, CONVERT(INT,SUBSTRING(@julian, 4, 3))-1,@datetime);     
    SET @datetime = DATEADD(hour,@hour,@datetime) 
    SET @datetime = DATEADD(minute,@minute,@datetime); 
    SET @datetime = DATEADD(second,@second,@datetime); 

    RETURN @datetime 
END 
1

DATE(CHAR(190萬+ GLDGJ)),其中GLDGJ是Julian日期值

+1

首先,歡迎來到社區:)有一個對這個問題已經有了幾個高質量的答案,其中大部分答案都是三年前發佈時提出的問題。雖然嘗試回答諸如此類的簡單問題可能是一種有價值的練習,但爲了提高編程能力,在當前狀態下發布此答案並不會增加任何問題。如果您的答案中有些新穎的話,請花幾個句子來解釋它的不同之處,以及爲什麼會使它更好。另外,請解釋你是如何達到這個魔術常數的。 – MTCoster 2015-12-15 15:33:47

2

接受的答案不正確。它將無法給出2016年2月29日116060的正確答案,而是返回2016年3月1日。

JDE似乎存儲日期爲整數,因此而不是從字符串轉換我總是直接從整數

DATEADD(DAY, @Julian % 1000, DATEADD(YEAR, @Julian/1000, '31-dec-1899')) 

要從VARCHAR去(6)我使用:

DATEADD(DAY, CAST(RIGHT(@Julian,3) AS int), DATEADD(YEAR, CAST(LEFT(@Julian,LEN(@Julian)-3) AS int), '31-dec-1899')) 
+0

我也許應該說,接受答案不正確的原因是因爲它將日期添加到基年,然後增加年份。因爲一年的正確日期取決於哪一年(不管它是不是閏年);你必須首先添加年份,然後是日期。 – 2016-02-15 14:00:18

相關問題