我有2个我正在使用的字段存储为smallint军事结构化时间。
编辑我在IBM Informix Dynamic Server Version 10.00.FC9上运行
beg_tm和end_tm
样本值
beg_tm 545
end_tm 815
beg_tm 1245
end_tm 1330
样品输出
beg_tm 5:45 am
end_tm 8:15 am
beg_tm 12:45 pm
end_tm 1:30 pm
我在Perl中使用它,但我正在寻找一种方法来使用SQL和case语句。
这甚至可能吗?
<小时/> 修改
基本上,此格式必须在ACE报告中使用。我找不到使用简单的
块在输出部分中对其进行格式化的方法if(beg_tm>=1300) then
beg_tm = vbeg_tm - 1200
其中vbeg_tm是声明的char(4)变量
<小时/> 修改的 这适用于小时&gt; = 1300(除了2230 !!)
select substr((beg_tm-1200),0,1)||":"||substr((beg_tm-1200),2,2) from mtg_rec where beg_tm>=1300;
这可以工作几个小时&lt; 1200(有时...... 10:40失败)
select substr((mtg_rec.beg_tm),0,(length(cast(beg_tm as varchar(4)))-2))||":"||(substr((mtg_rec.beg_tm),2,2))||" am" beg_tm from mtg_rec where mtg_no = 1;
<小时/> 修改
SELECT beg_tm,
cast((MOD(beg_tm/100 + 11, 12) + 1) as VARCHAR(2)) || ':' ||
SUBSTRING(cast((MOD(beg_tm, 100) + 100) as CHAR(3)) FROM 2) ||
SUBSTRING(' am pm' FROM (MOD(cast((beg_tm/1200) as INT), 2) * 3) + 1 FOR 3),
end_tm,
cast((MOD(end_tm/100 + 11, 12) + 1) as VARCHAR(2)) || ':' ||
SUBSTRING(cast((MOD(end_tm, 100) + 100) as CHAR(3)) FROM 2) ||
SUBSTRING(' am pm' FROM (MOD(cast((end_tm/1200) as INT), 2) * 3) + 1 FOR 3)
FROM mtg_rec
where mtg_no = 39;
答案 0 :(得分:7)
请注意,SO 440061有关于在12小时和24小时之间进行转换的有用信息(与此转换相反);这不是小事,因为凌晨12:45凌晨1点15分半小时到来。
接下来,请注意Informix(IDS - Informix Dynamic Server)版本7.31终于在2009-09-30服务终止了;它不再是受支持的产品。
您应该更准确地使用您的版本号;例如,7.30.UC1和7.31.UD8之间存在相当大的差异。
但是,您应该可以使用TO_CHAR()功能根据需要设置时间格式。虽然这个引用是IDS 12.10 Information Center,但我相信你可以在7.31中使用它(不一定是在7.30中,但在过去十年的大部分时间里你都不应该使用它。)
它表示,24小时有一个'%R'格式说明符。它还会引用“GL_DATETIME”,其中“%I”为您提供12小时的时间,“%p”为您提供上午/下午指示。我还找到了一个7.31.UD8的IDS实例来验证这一点:
select to_char(datetime(2009-01-01 16:15:14) year to second, '%I:%M %p')
from dual;
04:15 PM
select to_char(datetime(2009-01-01 16:15:14) year to second, '%1.1I:%M %p')
from dual;
4:15 PM
我从重新阅读的问题看到你实际上有0000..2359范围内的SMALLINT值并需要转换。通常,我会指出Informix有一个用于存储这些值的类型 - DATETIME HOUR TO MINUTE - 但我承认它在磁盘上占用3个字节而不是2个,因此它不像SMALLINT表示法那样紧凑。
Steve Kass展示了SQL Server符号:
select
cast((@milTime/100+11)%12+1 as varchar(2))
+':'
+substring(cast((@milTime%100+100) as char(3)),2,2)
+' '
+substring('ap',@milTime/1200%2+1,1)
+'m';
让小时变得正确的诀窍很巧妙 - 感谢史蒂夫!
转换为Informix for IDS 11.50,假设表格为:
CREATE TEMP TABLE times(begin_tm SMALLINT NOT NULL);
SELECT begin_tm,
(MOD(begin_tm/100 + 11, 12) + 1)::VARCHAR(2) || ':' ||
SUBSTRING((MOD(begin_tm, 100) + 100)::CHAR(3) FROM 2) || ' ' ||
SUBSTRING("ampm" FROM (MOD((begin_tm/1200)::INT, 2) * 2) + 1 FOR 2)
FROM times
ORDER BY begin_tm;
使用FROM和FOR的SUBSTRING表示法是标准的SQL表示法 - 很奇怪,但是也是如此。
示例结果:
0 12:00 am
1 12:01 am
59 12:59 am
100 1:00 am
559 5:59 am
600 6:00 am
601 6:01 am
959 9:59 am
1000 10:00 am
1159 11:59 am
1200 12:00 pm
1201 12:01 pm
1259 12:59 pm
1300 1:00 pm
2159 9:59 pm
2200 10:00 pm
2359 11:59 pm
2400 12:00 am
警告:值559-601在列表中,因为在没有强制转换为整数时遇到了舍入而不是截断的问题。
现在,这是在IDS 11.50上测试的; IDS 7.3x不会有演员表示法。 但是,这不是问题;下一条评论将要处理......
作为如何在没有条件等的情况下在SQL中编写表达式的练习,这很有趣,但是如果有人在整个套件中不止一次地写了这个,我会因为缺乏模块化而拍摄它们。显然,这需要一个存储过程 - 并且存储过程不需要(显式)强制转换或其他一些技巧,尽管赋值强制执行隐式强制转换:
CREATE PROCEDURE ampm_time(tm SMALLINT) RETURNING CHAR(8);
DEFINE hh SMALLINT;
DEFINE mm SMALLINT;
DEFINE am SMALLINT;
DEFINE m3 CHAR(3);
DEFINE a3 CHAR(3);
LET hh = MOD(tm / 100 + 11, 12) + 1;
LET mm = MOD(tm, 100) + 100;
LET am = MOD(tm / 1200, 2);
LET m3 = mm;
IF am = 0
THEN LET a3 = ' am';
ELSE LET a3 = ' pm';
END IF;
RETURN (hh || ':' || m3[2,3] || a3);
END PROCEDURE;
Informix'[2,3]'表示法是子字符串运算符的原始形式;原始因为(由于仍然无法理解的原因)下标必须是文字整数(不是变量,而不是表达式)。它恰好在这里有用;总的来说,这很令人沮丧。
此存储过程应适用于您可以使用的任何版本的Informix(OnLine 5.x,SE 7.x,IDS 7.x或9.x,10.00,11.x,12.x)。
说明表达式和存储过程的(一个次要变体)的等价性:
SELECT begin_tm,
(MOD(begin_tm/100 + 11, 12) + 1)::VARCHAR(2) || ':' ||
SUBSTRING((MOD(begin_tm, 100) + 100)::CHAR(3) FROM 2) ||
SUBSTRING(' am pm' FROM (MOD((begin_tm/1200)::INT, 2) * 3) + 1 FOR 3),
ampm_time(begin_tm)
FROM times
ORDER BY begin_tm;
产生结果:
0 12:00 am 12:00 am
1 12:01 am 12:01 am
59 12:59 am 12:59 am
100 1:00 am 1:00 am
559 5:59 am 5:59 am
600 6:00 am 6:00 pm
601 6:01 am 6:01 pm
959 9:59 am 9:59 pm
1000 10:00 am 10:00 pm
1159 11:59 am 11:59 pm
1200 12:00 pm 12:00 pm
1201 12:01 pm 12:01 pm
1259 12:59 pm 12:59 pm
1300 1:00 pm 1:00 pm
2159 9:59 pm 9:59 pm
2200 10:00 pm 10:00 pm
2359 11:59 pm 11:59 pm
2400 12:00 am 12:00 am
此存储过程现在可以在ACE报告中的单个SELECT语句中多次使用,而无需进一步操作。
[在原始海报上发表关于不起作用的评论...... ]
IDS 7.31不处理传递给MOD()函数的非整数值。因此,除法必须存储在显式整数变量中 - 因此:
CREATE PROCEDURE ampm_time(tm SMALLINT) RETURNING CHAR(8);
DEFINE i2 SMALLINT;
DEFINE hh SMALLINT;
DEFINE mm SMALLINT;
DEFINE am SMALLINT;
DEFINE m3 CHAR(3);
DEFINE a3 CHAR(3);
LET i2 = tm / 100;
LET hh = MOD(i2 + 11, 12) + 1;
LET mm = MOD(tm, 100) + 100;
LET i2 = tm / 1200;
LET am = MOD(i2, 2);
LET m3 = mm;
IF am = 0
THEN LET a3 = ' am';
ELSE LET a3 = ' pm';
END IF;
RETURN (hh || ':' || m3[2,3] || a3);
END PROCEDURE;
这是在Solaris 10上的IDS 7.31.UD8上测试的,并且工作正常。我不明白报告的语法错误;但是存在版本依赖的外部机会 - 为了以防万一,报告版本号和平台总是至关重要。请注意,我要小心记录各种工作的位置;这不是偶然,也不仅仅是繁琐 - 它是基于多年的经验。
答案 1 :(得分:3)
这是Steve Kass解决 Informix 的未经测试的端口。
Steve的解决方案本身在MS SQL Server下经过了充分测试。我比以前的解决方案更喜欢它,因为转换为上午/下午时间是以代数方式完成,不需要任何分支的帮助(使用CASE语句等)。 / p>
如果数字“军事时间”来自数据库,则用列名替换@milTime。 @变量仅用于测试。
--declare @milTime int
--set @milTime = 1359
SELECT
CAST(MOD((@milTime /100 + 11), 12) + 1 AS VARCHAR(2))
||':'
||SUBSTRING(CAST((@milTime%100 + 100) AS CHAR(3)) FROM 2 FOR 2)
||' '
|| SUBSTRING('ap' FROM (MOD(@milTime / 1200, 2) + 1) FOR 1)
|| 'm';
这里的参考是我的[已修复],基于CASE的SQL Server解决方案
SELECT
CASE ((@milTime / 100) % 12)
WHEN 0 THEN '12'
ELSE CAST((@milTime % 1200) / 100 AS varchar(2))
END
+ ':' + RIGHT('0' + CAST((@milTime % 100) AS varchar(2)), 2)
+ CASE (@milTime / 1200) WHEN 0 THEN ' am' ELSE ' pm' END
答案 2 :(得分:3)
这是一个应该更好的T-SQL解决方案。它可以通过使用适当的连接语法和SUBSTRING来适应其他方言。
它也适用于军事时间2400(凌晨12:00),这可能很有用。
select
cast((@milTime/100+11)%12+1 as varchar(2))
+':'
+substring(cast((@milTime%100+100) as char(3)),2,2)
+' '
+substring('ap',@milTime/1200%2+1,1)
+'m';
答案 3 :(得分:3)
-sw
{
Revision Information (Automatically maintained by 'make' - DON'T CHANGE)
-------------------------------------------------------------------------
$Header$
-------------------------------------------------------------------------
}
procedure se_get_inttime
privilege owner
description "Get time from an integer field and return as datetime"
inputs param_time integer "Integer formatted time"
returns datetime hour to minute "Time in datetime format"
notes "Get time from an integer field and return as datetime"
begin procedure
DEFINE tm_str VARCHAR(255);
DEFINE h INTEGER;
DEFINE m INTEGER;
IF (param_time < 0 OR param_time > 2359) THEN
RAISE EXCEPTION -746, 0, "Invalid time format. Should be: 0 - 2359";
END IF
LET tm_str = LPAD(param_time, 4, 0);
LET h = SUBSTR(tm_str, 1, 2);
IF (h < 0 OR h > 23) THEN
RAISE EXCEPTION -746, 0, "Invalid time format. Should be: 0 - 2359";
END IF
LET m = SUBSTR(tm_str, 3, 4);
IF (m < 0 OR m > 59) THEN
RAISE EXCEPTION -746, 0, "Invalid time format. Should be: 0 - 2359";
END IF
RETURN TO_DATE(h || ':' || m , '%R');
end procedure
grant
execute to (group public)
答案 4 :(得分:1)
不确定informix,这是我在Oracle中会做的事情(一些例子,但我在家里没有经过测试):
To_Char (milTime)
,例如1->'1',545-&gt; '545',1215 - &gt; '1215'Right('0000'||To_Char(milTime), 4)
,例如1→ '0001',545 - &gt; '0545',1215 - &gt; '1215'To_Date (Right('0000'||To_Char(milTime), 4), 'HH24:MI')
To_Char(To_Date(..),'HH:MI AM')
例如。 1-> '00:01 AM',545-&gt; '05:45 AM',1215 - &gt; '12:15 PM'Oracle的To_Date和To_Char是专有的,但我确信有标准的SQL或Informix函数可以实现相同的结果而无需求助于“计算”。
答案 5 :(得分:1)
CheeseWithCheese表示必须在ACE报告中完成,所以这是我的ACE报告......
select beg_tm, end_tm ...
define
variable utime char(4)
variable ftime char(7)
end
format
on every row
let utime = beg_tm {cast beg_tm to char(4). do same for end_tm}
if utime[1,2] = "00" then let ftime[1,3] = "12:"
if utime[1,2] = "01" then let ftime[1,3] = " 1:"
if utime[1,2] = "02" then let ftime[1,3] = " 2:"
if utime[1,2] = "03" then let ftime[1,3] = " 3:"
if utime[1,2] = "04" then let ftime[1,3] = " 4:"
if utime[1,2] = "05" then let ftime[1,3] = " 5:"
if utime[1,2] = "06" then let ftime[1,3] = " 6:"
if utime[1,2] = "07" then let ftime[1,3] = " 7:"
if utime[1,2] = "08" then let ftime[1,3] = " 8:"
if utime[1,2] = "09" then let ftime[1,3] = " 9:"
if utime[1,2] = "10" then let ftime[1,3] = "10:"
if utime[1,2] = "11" then let ftime[1,3] = "11:"
if utime[1,2] = "12" then let ftime[1,3] = "12:"
if utime[1,2] = "13" then let ftime[1,3] = " 1:"
if utime[1,2] = "14" then let ftime[1,3] = " 2:"
if utime[1,2] = "15" then let ftime[1,3] = " 3:"
if utime[1,2] = "16" then let ftime[1,3] = " 4:"
if utime[1,2] = "17" then let ftime[1,3] = " 5:"
if utime[1,2] = "18" then let ftime[1,3] = " 6:"
if utime[1,2] = "19" then let ftime[1,3] = " 7:"
if utime[1,2] = "20" then let ftime[1,3] = " 8:"
if utime[1,2] = "21" then let ftime[1,3] = " 9:"
if utime[1,2] = "22" then let ftime[1,3] = "10:"
if utime[1,2] = "23" then let ftime[1,3] = "11:"
let ftime[4,5] = utime[3,4]
if utime[1,2] = "00"
or utime[1,2] = "01"
or utime[1,2] = "02"
or utime[1,2] = "03"
or utime[1,2] = "04"
or utime[1,2] = "05"
or utime[1,2] = "06"
or utime[1,2] = "07"
or utime[1,2] = "08"
or utime[1,2] = "09"
or utime[1,2] = "10"
or utime[1,2] = "11" then let ftime[6,7] = "AM"
if utime[1,2] = "12"
or utime[1,2] = "13"
or utime[1,2] = "14"
or utime[1,2] = "15"
or utime[1,2] = "16"
or utime[1,2] = "17"
or utime[1,2] = "18"
or utime[1,2] = "19"
or utime[1,2] = "20"
or utime[1,2] = "21"
or utime[1,2] = "22"
or utime[1,2] = "23" then let ftime[6,7] = "PM"
print column 1, "UNFORMATTED TIME: ", utime," = FORMATTED TIME: ", ftime
答案 6 :(得分:0)
LONG-hand方法......但是有效
select substr((mtg_rec.beg_tm-1200),0,1)||":"||substr((mtg_rec.beg_tm-1200),2,2)||" pm" beg_tm,
substr((mtg_rec.end_tm-1200),0,1)||":"||substr((mtg_rec.end_tm-1200),2,2)||" pm" end_tm
from mtg_rec
where mtg_rec.beg_tm between 1300 and 2159
and mtg_rec.end_tm between 1300 and 2159
union
select substr((mtg_rec.beg_tm-1200),0,1)||":"||substr((mtg_rec.beg_tm-1200),2,2)||" pm" beg_tm,
substr((mtg_rec.end_tm-1200),0,2)||":"||substr((mtg_rec.end_tm-1200),3,2)||" pm" end_tm
from mtg_rec
where mtg_rec.beg_tm between 1300 and 2159
and mtg_rec.end_tm between 2159 and 2400
union
select substr((mtg_rec.beg_tm-1200),0,2)||":"||substr((mtg_rec.beg_tm-1200),3,2)||" pm" beg_tm,
substr((mtg_rec.end_tm-1200),0,2)||":"||substr((mtg_rec.end_tm-1200),3,2)||" pm" end_tm
mtg_rec.days
from mtg_rec
where mtg_rec.beg_tm between 2159 and 2400
and mtg_rec.end_tm between 2159 and 2400
union
select substr((mtg_rec.beg_tm),0,1)||":"||(substr((mtg_rec.beg_tm),2,2))||" am" beg_tm,
substr((mtg_rec.end_tm),0,1)||":"||(substr((mtg_rec.end_tm),2,2))||" am" end_tm
mtg_rec.days
from mtg_rec
where mtg_rec.beg_tm between 0 and 959
and mtg_rec.end_tm between 0 and 959
union
select substr((mtg_rec.beg_tm),0,2)||":"||(substr((mtg_rec.beg_tm),3,2))||" am" beg_tm,
substr((mtg_rec.end_tm),0,2)||":"||(substr((mtg_rec.end_tm),3,2))||" am" end_tm
mtg_rec.days
from mtg_rec
where mtg_rec.beg_tm between 1000 and 1259
and mtg_rec.end_tm between 1000 and 1259
union
select cast(beg_tm as varchar(4)),
cast(end_tm as varchar(4))
from mtg_rec
where mtg_rec.beg_tm = 0
and mtg_rec.end_tm = 0
into temp time_machine with no log;