我正在尝试转换JDE dates,并积累了大量信息,并认为我会尝试执行SQL转换功能来简化某些任务。
这是我提出的功能,我简称为“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
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 :(得分:4)
我认为使用本机日期时间数学比使用各种字符串,日期和数字格式来回切换更有效。
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
即使你没有为列编制索引,它仍然会将丑陋的计算隐藏起来,因为它只是在写入时支付,因为它不会导致你在查询时执行昂贵的函数操作列被引用...
答案 1 :(得分:3)
接受的答案不正确。它将无法给出应该是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'))
答案 2 :(得分:1)
DATE(CHAR(1900000 + GLDGJ))其中GLDGJ是朱利安日期值
答案 3 :(得分: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
答案 4 :(得分:0)
我认为没有人提到过它,但是JDE为此提供了一个表格。
这是F00365数据表。据我所知,这是一个转换表只是这个问题。
要获取公历日期,请使用ONDTEJ字段(这是儒略日期)联接F00365表,并返回ONDATE值,即公历日期。 例如
SELECT
DateReq.ONDATE
FROM F00101 NamesData
INNER JOIN F00365 DateReq
ON DateReq.ONDTEJ = NamesData.ABUPMJ
无需数学。 leap年没有奇怪的问题。