微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL – 将24小时(“军事”)时间(2145)转换为“上午/下午时间”(晚上9:45)

我有两个我正在使用的字段存储为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)变量

编辑
这可以工作几个小时> = 1300(除了2230 !!)

select substr((beg_tm-1200),1)||":"||substr((beg_tm-1200),2,2) from mtg_rec where beg_tm>=1300;

这工作了几个小时< 1200(有时...... 10:40失败)

select substr((mtg_rec.beg_tm),(length(cast(beg_tm as varchar(4)))-2))||":"||(substr((mtg_rec.beg_tm),2))||" am" beg_tm from mtg_rec where mtg_no = 1;

编辑
Jonathan Leffler表达方法中使用的转换语法的变化

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;

解决方法

请注意,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’给你am / pm指标.我还找到了一个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)
 +' '
 +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,100) + 100)::CHAR(3) FROM 2) ||
        SUBSTRING(' am pm' FROM (MOD((begin_tm/1200)::INT,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,100) + 100;
    LET i2 = tm / 1200;
    LET am = MOD(i2,3] || a3);
END PROCEDURE;

这是在Solaris 10上的IDS 7.31.UD8上测试的,并且工作正常.我不明白报告的语法错误;但是存在版本依赖的外部机会 – 为了以防万一,报告版本号和平台始终是至关重要的.请注意,我要小心记录各种工作的位置;这不是偶然的,也不仅仅是繁琐的 – 它基于多年的经验.

原文地址:https://www.jb51.cc/mssql/83328.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐