Есть ли в UniVerse 11.2.4+ собственный способ преобразования времени в UTC?
В примечаниях к выпуску UniVerse версии 11.2.4 упоминается конфигурация локального часового пояса, но она находится в контексте аудита. Это цитата:
Конфигурация местного часового пояса
До UniVerse 11.2.4 данные о дате и времени, хранящиеся в записях журнала аудита, основывались только на UTC. Начиная с UniVerse 11.2.4, UniVerse добавляет данные о дате и времени, основанные на местном часовом поясе, в записи журнала аудита. Данные хранятся в ячейке 19 для каждой записи. Название словаря для этого поля данных - TZINFO. Для получения дополнительной информации см. Функции безопасности UniVerse.
Поскольку UniVerse кажется способным работать с часовыми поясами изначально, означает ли это, что может быть способ легко сгенерировать метки даты / времени в формате UTC из моих значений EST/EDT?
Я отправляю данные в систему, которая хочет, чтобы даты были отформатированы в формате даты / времени ISO-8601 yyyy-MMddTHH:mm:ssZ
, лайк 2015-06-02T15:55:22Z
, с учетом часового пояса и летнего времени.
Я перерыл руководство по функциям безопасности и обнаружил следующее:
UniVerse также добавляет глобально каталогизированную программу, чтобы помочь пользователям получать информацию о дате и времени из журнала аудита (который вызывается двумя вышеупомянутыми полями I-дескриптора):
SUBROUTINE GETLOCALTIME
(
RESULT ;* OUT: output
TZOFF ;* IN: time zone offset
DATE ;* IN: UTC date
TIME ;* IN: UTC time
OP ;* IN: operation
;* 1: get local date
;* 2: get local time
;* 3: get local timezone id
;* 4: get local timezone daylight saving flag
)
(Поскольку я не использую возможности аудита UniVerse, я не думаю, что смогу с этим многое сделать, и при этом я не смог найти подпрограмму.)
Я также играл с популярным (?) DATE.UTILITY
программа от PickWiki, но ее расчет даты начала / окончания перехода на летнее время кажется отключенным. Я сохраню эти вопросы для другого вопроса.
Это становится длинным, но я надеюсь, что кто-то может указать мне правильное направление, если есть новый параметр OCONV() или что-то, что я мог бы использовать.
На всякий случай это работает, я работаю на Windows Server 2008 R2.
Спасибо!
2 ответа
Время сложная вещь. Социально мы признали, что не только приемлемо изменять это 2 раза в год, мы уполномочили это! Все это хорошо для мясных машин, которые хотят понимать время, когда это удобно для нас, однако это заставляет нас раздражаться, когда наши репортажи "выглядят смешно".
Решение вашей проблемы не является исключительно простым, особенно если вы работаете с уже записанными датами. Даты и время во Вселенной обычно записываются на основе местного системного времени. Если это то, что вы пытаетесь сделать в будущем, вы должны отметить, какое смещение есть во время транзакции, или просто пометить элементы SYSTEM(99), что усложнило почти все остальные отчеты, которые вам понадобятся. В любом случае, это сложный вопрос, и он все еще может быть несколько несовершенным.
Вот кое-что, что могло бы помочь вам, если вы отвечаете за запись дат, в будущем.
SECONDS.SINCE.GMT.01.01.1970 = SYSTEM(99)
CRT SECONDS.SINCE.GMT.01.01.1970:" Seconds since GMT Epoch Began"
NUMBER.OF.DAYS.SINCE.01.01.1970 = DATE() -732
;* Day 0 in Pick is 12/31/1967 because Dick Pick so we subtract 732 from the pick date
SECONDS.SINCE.MIDNIGHT.LOCAL= TIME()
SECS.PER.DAY = 24 * 60 * 60
LOCAL.SECONDS.SINCE.GMT.01.01.1970 = NUMBER.OF.DAYS.SINCE.01.01.1970 * SECS.PER.DAY + FIELD(SECONDS.SINCE.MIDNIGHT.LOCAL,".",1)
;*I drop the precision
CRT LOCAL.SECONDS.SINCE.GMT.01.01.1970: " Seconds since 01/01/1970 in local time"
OFFSET = (LOCAL.SECONDS.SINCE.GMT.01.01.1970 - SECONDS.SINCE.GMT.01.01.1970)
CRT "CURRENT.OFFSET IS ":INT((OFFSET / 60 )/ 60)
END
Который выводит следующее в моей системе, которая в настоящее время является PDT (хотя OCONV(DATE(),'DZ') сообщает об этом как PST.
1434472817 Seconds since GMT Epoch Began
1434447617 Seconds since 01/01/1970 in local time
CURRENT.OFFSET IS -7
Надеюсь, вы нашли это полезным.
Спасибо за подсказки. Вот моя реализация:
SUBROUTINE FORMAT.ISO.8601 (IDATE, ITIME, RESULT, ERR.TEXT)
* Don't step on the caller's variables.
IN.DATE = IDATE
IN.TIME = ITIME
* Initialize the outbound variable.
RESULT = ''
IF NOT(NUM(IN.DATE)) THEN
ERR.TEXT = 'Non-numeric internal date ' : DQUOTE(IN.DATE) : ' when numeric required.'
RETURN
END
IF NOT(NUM(IN.DATE)) THEN
ERR.TEXT = 'Non-numeric internal time ' : DQUOTE(IN.TIME) : ' when numeric required.'
RETURN
END
* SYSTEM(99) is based on 1/1/1970.
SECONDS.SINCE.GMT.01.01.1970 = SYSTEM(99)
* Day 0 in Pick is 12/31/1967
* Subtract 732 to equalize the starting dates.
NUMBER.OF.DAYS.SINCE.01.01.1970 = DATE() - 732
SECONDS.SINCE.MIDNIGHT.LOCAL= TIME()
SECS.PER.DAY = 24 * 60 * 60
LOCAL.SECONDS.SINCE.GMT.01.01.1970 = NUMBER.OF.DAYS.SINCE.01.01.1970 * SECS.PER.DAY + FIELD(SECONDS.SINCE.MIDNIGHT.LOCAL,".",1)
OFFSET = LOCAL.SECONDS.SINCE.GMT.01.01.1970 - SECONDS.SINCE.GMT.01.01.1970
OFFSET = INT((OFFSET / 60 )/ 60)
OTIME = OCONV(IN.TIME, 'MTS')
IF OTIME = '' THEN
ERR.TEXT = 'Bad internal time ' : DQUOTE(IN.TIME) : '.'
RETURN
END
HOURS = FIELD(OTIME, ':', 1)
MINUTES = FIELD(OTIME, ':', 2)
SECONDS = FIELD(OTIME, ':', 3)
HOURS -= OFFSET
IF HOURS >= 24 THEN
IN.DATE += 1
HOURS = HOURS - 24
END
HOURS = HOURS 'R%2'
ODATE = OCONV(IN.DATE, 'D4/')
IF ODATE = '' THEN
ERR.TEXT = 'Bad internal date ' : DQUOTE(IN.DATE) : '.'
RETURN
END
DMONTH = FIELD(ODATE, '/', 1)
DDAY = FIELD(ODATE, '/',2)
DYEAR = FIELD(ODATE, '/',3)
RESULT = DYEAR : '-' : DMONTH : '-' : DDAY : 'T' : HOURS : ':' : MINUTES : ':' : SECONDS : 'Z'
RETURN
END
Вот мой тестовый комплект:
CRT 'Testing right now.'
IDATE = DATE()
ITIME = TIME()
CALL FORMAT.ISO.8601 (IDATE, ITIME, RESULT, ERR.TEXT)
IF ERR.TEXT THEN
CRT 'ERR.TEXT: ' : ERR.TEXT
END ELSE
CRT 'RESULT: ' : RESULT
END
CRT
CRT 'Testing an hour ago.'
IDATE = DATE()
ITIME = TIME()
ITIME = ITIME - (60*60)
IF ITIME < 0 THEN
ITIME += (24*60*60)
IDATE -= 1
END
CALL FORMAT.ISO.8601 (IDATE, ITIME, RESULT, ERR.TEXT)
IF ERR.TEXT THEN
CRT 'ERR.TEXT: ' : ERR.TEXT
END ELSE
CRT 'RESULT: ' : RESULT
END
CRT
CRT 'Testing an hour from now.'
IDATE = DATE()
ITIME = TIME()
ITIME = ITIME + (60*60)
IF ITIME > (24*60*60) THEN
ITIME -= (24*60*60)
IDATE += 1
END
CALL FORMAT.ISO.8601 (IDATE, ITIME, RESULT, ERR.TEXT)
IF ERR.TEXT THEN
CRT 'ERR.TEXT: ' : ERR.TEXT
END ELSE
CRT 'RESULT: ' : RESULT
END
END
Вот мой тестовый прогон:
>T$FORMAT.ISO.8601
Testing right now.
RESULT: 2017-03-29T00:47:22Z
Testing an hour ago.
RESULT: 2017-03-28T23:47:22Z
Testing an hour from now.
RESULT: 2017-03-29T01:47:22Z