Вопрос

Я пытаюсь обратить Даты JDE, и накопил большое количество информации, и решил, что попробую выполнить функцию преобразования SQL, чтобы упростить некоторые задачи.

Вот функция, которую я придумал, которую я просто называю "тогрегорианской".

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. Принимает строку "julian".
  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)
Это было полезно?

Решение

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

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

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

Другие советы

Принятый ответ неверен.Он не сможет дать правильный ответ на 116060, что должно быть 29 февраля 2016 года. Вместо этого он возвращается 1 марта 2016 года.

JDE, кажется, хранит даты как целые числа, поэтому, вместо преобразования от струн, я всегда иду направляюсь от целого числа:

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

Перейти от варра (6) Я использую:

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

Дата (char (1900000 + gldgj)), где gldgj - это значение даты Джулиана

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
.

Я не думаю, что кто-то упомянул об этом, но у JDE есть таблица только для этого.

Это таблица данных F00365.Насколько я знаю, это таблица перевода только для этого вопроса.

Чтобы получить григорианскую дату, вы присоединитесь к таблице F00365, используя поле OnDTej (который является джулианской датой), и вы возвращаете значение Ondate, которое является Gregorian. например.

SELECT 
    DateReq.ONDATE 
FROM F00101 NamesData 
INNER JOIN F00365 DateReq 
    ON DateReq.ONDTEJ = NamesData.ABUPMJ
.

Нет необходимой математики.Нет странных проблем с прыжками.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top