Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > C/C++ > 自己写的日期相加函数(C语言)_根据ORACLE数据库的方式改进版
【标  题】:自己写的日期相加函数(C语言)_根据ORACLE数据库的方式改进版
【关键字】:ORACLE
【来  源】:http://blog.csdn.net/Kuaidc/archive/2006/08/18/1092377.aspx

自己写的日期相加函数(C语言)_根据ORACLE数据库的方式改进版

Your Ad Here 由于原来写的日期相加函数,处理的日期来自ORACLE数据库,得到的结果最后也得存到数据库里。
ORACLE里是分开相加的,可以先加年,再加月,再加天。年的结果与天的结果相加都相同,但是加月的时候,结果就不相同了!造成这个情况的原因是函数没有像数据库那样处理月末这天的特殊性。
ORACLE数据库是这样处理月末的:
1.如果加上某个月份前(就是源日期),当天是该月的月末,则不管加上几个月,都把结果设置为此月的月末这天。
如:020131加上一个月,则其结果是020128;
另:020228加上一个月,结果为:020331。


2.如果加上某个月份后(就是结果日期),原来的月里的天数已经超过了当月的最大天数,则自动把天数写成当月的月末。
如:020129,加上一个月,不是020229,而是020228,虽然020129不是一月份的月末,但是29号超过了2月的最大天数。

根据这两点,我在程序里加入了一点判断,得到的结果就与ORACLE的相同了!

改进后函数如下:


#define TRUE 1
#define true 1
#define false 0
#define SUCCESS 0

#include <stdio.h>

unsigned char *asc_bcd(unsigned char *Ptd ,unsigned char Lgd,unsigned char *Pts,unsigned char Lgs)
{
    unsigned char I;

    if( Lgd > Lgs/2)
    {
        memset( Ptd, 0x00, Lgd ) ;
        Ptd = Ptd + Lgd - ((Lgs + 1) / 2) ;
    }
    for ( I = 0 ; I < ((Lgs+1) / 2) ; I++)
    {
        if ( (!(Lgs % 2) && !I) || I ) *Ptd =  (*Pts++ << 4) & 0xF0 ;
        *Ptd = *Ptd + (*Pts++ & 0x0F)  ;
        Ptd++ ;
    }
    return((unsigned char*)Ptd);
}

unsigned long bcd_long( unsigned char *Pts, unsigned char Ls )
{
    unsigned char I,Oct;
    unsigned long Lg1,Lg2;

    Lg1 = 0 ;
    Lg2 = 1 ;
    Pts += (Ls+1)/2;
    for (I = 0; I< Ls ; I++)
    {
        if ( I % 2) Oct = (*Pts >> 4 ) & 0x0F;
        else Oct = *--Pts & 0x0F;
        Lg1 += Lg2 * Oct ;
        if (Lg2 == 1000000000L ) Lg2 = 0 ;
        else Lg2 *= 10 ;
    }
    return (Lg1) ;
}

unsigned char *long_bcd(unsigned char *Ptd ,unsigned char Lgd,unsigned long *Pts)
{
    unsigned int I;
    unsigned char *Pt0,Tb[5];
    unsigned long Lg1,Lg2;

    Lg1 = *Pts;
    Lg2 = 100000000L ;
    for (I = 0; I< 5; I++)
    {
        Tb[I] = (unsigned char)(Lg1 / Lg2) ;
        Tb[I] = ((Tb[I] / 10 ) << 4 ) + (Tb[I] % 10);
        Lg1 = Lg1 % Lg2;
        Lg2 = Lg2 / 100;
    }

    memset( Ptd, 0x00, Lgd ) ;
    Ptd += Lgd ;
    Pt0 = Ptd ;
    if ( Lgd > 5) Lgd = 5 ;
    for ( I=0; I < Lgd;I++) *--Ptd = Tb[4-I] ;

    return((unsigned char*)Pt0);
}

unsigned char UTIL_IsLeapYear(unsigned short Year)
{
    if(  (Year%4) != 0)
    {
        return false;
    }else
    {
        if(  (Year%100) != 0)
        {
            return true;
        }else
        {
            if(  (Year%400) != 0)
                return false;
            else
                return true;
        }
    }
}


unsigned char UTIL_Date_Add(unsigned char *pucSrcDate,unsigned char *pucAddDate,unsigned char *pucDesDate)
{
    unsigned char ucYear,ucMonth,ucDay;
    unsigned char ucAddYear,ucAddMonth,ucAddDay;
   
    unsigned char ucYearResult,ucMonthResult,ucDayResult;
    unsigned char ucMonthTmp,ucDayTmp;
    unsigned char ucDayPerMonth,ucMonthToYear;
   
    unsigned short uiYear;
    unsigned long  ulYear,ulMonth,ulDay;
    unsigned char ucFirstFlag;
    unsigned char ucLastDayFlag;
   
   
    ucYear = bcd_long(pucSrcDate,2);
    ucMonth = bcd_long(pucSrcDate+1,2);
    ucDay = bcd_long(pucSrcDate+2,2);
    printf("Source Date: Year=%2d,Month=%2d,Day=%2d\n",ucYear,ucMonth,ucDay);
   
    ucAddYear = bcd_long(pucAddDate,2);
    ucAddMonth = bcd_long(pucAddDate+1,2);
    ucAddDay = bcd_long(pucAddDate+2,2);
    printf("Dest Date: AddYear=%2d,AddMonth=%2d,AddDay=%2d\n",ucAddYear,ucAddMonth,ucAddDay);
   
    if(ucMonth>12)
        return 1;
    if(ucDay>31)
        return 2;   
   
    ucYearResult = ucYear + ucAddYear;
    ucMonthResult = ucMonth + ucAddMonth;
   
    if(ucMonthResult > 12)
    {       
        ucYearResult += (ucMonthResult / 12); //如果月相加的结果大于12,则向前进位一年
    }   
   
    uiYear = 2000 + ucYear;//原始年的数据

    ucMonthTmp = ucMonth;//第一次计算原月份的天数,看是否最后一天
   
    ucFirstFlag = 1;
    ucLastDayFlag = false;
   
    do{   
        switch(ucMonthTmp)
        {
            case 0://12月
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
                ucDayPerMonth = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                ucDayPerMonth = 30;
                break;
            case 2:
                if(UTIL_IsLeapYear(uiYear)==TRUE)//用完整表示的年计算是不是闰年
                    ucDayPerMonth = 29;
                else
                    ucDayPerMonth = 28;
                break;
            default:
                break;   
        }
       
        if(ucFirstFlag == 1)
        {//输入的年份的情况
            ucFirstFlag = 2;
            if(ucDay == ucDayPerMonth)//2月28号加一个月的情况
                ucLastDayFlag = true;          
           
            uiYear = 2000 + ucYearResult;
            continue;
           
        }else if(ucFirstFlag == 2)
        {//年份相加,月份相加后的情况
            ucFirstFlag = 3;
            ucMonthTmp = ucMonthResult % 12;

            if(ucDay > ucDayPerMonth)//1月29号加一个月的情况
                ucDay = ucDayPerMonth;
           
            if(ucLastDayFlag == true)//2月28号加一个月的情况
                ucDay = ucDayPerMonth;

            ucDayTmp = ucDay + ucAddDay;//最后算得的天数
             continue;
        }
       
        if(ucDayTmp > ucDayPerMonth)
        {
            ucDayTmp = ucDayTmp - ucDayPerMonth;
            ucMonthTmp ++;   
            ucMonthTmp %= 12;
           
            if(ucMonthTmp == 1)
            {
                uiYear++;//如果当月是12月,且天数大于31,则年进位
                if(uiYear>2099)
                      return 3;
            }               
        }
        else
        {
            break;
        }
    }
    while(1);
   
    ucMonthResult = ucMonthTmp;
    if(ucMonthResult == 0)//如果是0表示是12月
        ucMonthResult = 12;
       
    ucDayResult = ucDayTmp;
    ucYearResult = uiYear - 2000;
   
    printf("\nResult: Year=%2d,Month=%2d,Day=%2d\n",ucYearResult,ucMonthResult,ucDayResult);
    ulYear = ucYearResult;
    ulMonth = ucMonthResult;
    ulDay = ucDayResult;
   
    long_bcd(pucDesDate,1,&ulYear);
    long_bcd(pucDesDate+1,1,&ulMonth);
    long_bcd(pucDesDate+2,1,&ulDay);
   
    return SUCCESS;
}






int main()
{
    unsigned char aucSrcDate[7],aucAddDate[7],aucSrcDateTmp[4],aucAddDateTmp[4],aucDesDate[4];
    unsigned char ucFlag = 1;
    unsigned char ucResult,ucI;
   
    printf("\n----------------------------------------------------\n");
    printf("           Add Year Function Test\n");
    printf("----------------------------------------------------\n");
   
    while(ucFlag)
    {
        memset(aucSrcDate,0,sizeof(aucSrcDate));
        memset(aucAddDate,0,sizeof(aucAddDate));
        memset(aucSrcDateTmp,0,sizeof(aucSrcDateTmp));
        memset(aucAddDateTmp,0,sizeof(aucAddDateTmp));
        memset(aucDesDate,0,sizeof(aucDesDate));
       
        printf("\nPlease Input Now Date with Format YYMMDD:\n");
        scanf("%s",aucSrcDate);
        printf("\n");
        printf("Please Input You Want Add Date with Format YYMMDD:\n");
        scanf("%s",aucAddDate);
        printf("\n");
        asc_bcd(aucSrcDateTmp,3,aucSrcDate,6);
        asc_bcd(aucAddDateTmp,3,aucAddDate,6);
       
        ucResult = UTIL_Date_Add(aucSrcDateTmp,aucAddDateTmp,aucDesDate);
        printf("\n\n====================================\n");
        for(ucI=0;ucI<4;ucI++)
            printf("%02x ",aucDesDate[ucI]);
        printf("\n\n====================================\n");
        if(ucResult == 0)           
            printf("\n==============================================\nPlease Manual Count The Result is Right or Not!\n");
        if(ucResult == 1)
            printf("\n!!!Error!! Error Input Month!Please Check!\n");
        if(ucResult ==2)
            printf("\n!!!Error !! Error Input Day Value,Please Check!\n");
        if(ucResult == 3)
            printf("\n!!!Error!! Error Year Value,Please Re Input!\n");  
        printf("\n-----------------------------------------------\n");
        printf("If You Want To Continue?(Y/N)");
        ucFlag = getch();
       
        if(ucFlag == 'Y'|| ucFlag=='y')
            ucFlag = 1;
        else
            ucFlag = 0;
    }
    return 0;
}

虽然这样处理后,误差会小很些,但是,由于数据库每次只能加天或加月,这样的结果就与相加的顺序有关。
比如:060130 + 000102
如果先加月:060130 加一个月结果是:060228,再加2天,结果是:060302
如果反过来,先加天:060130 加两天结果:060201,再加一个月:060301,这样就会有一天的误差了!

但是上面改进过的程序,对于加年来说,就不会产生误差,因为每次加过年后会检查日期有效性,把产生误差的因素消除了!
C语言中对时间和日期的处理:【上一篇】
异常处理的一些不错的文章:【下一篇】
【相关文章】
  • Oracle 10gR2 RAC + RHEL AS4U2
  • ORACLE 乱码问题的解决
  • ORA-01110: data file 1: 'D:\ORACLE\ORADATA\OLIVE\S
  • Oracle9i优化器介绍
  • hpux 11.23 Itanium下Oracle 10gr2的安装简说
  • Oracle Number类型的讨论
  • Oracle表分区学习笔记
  • 重新安装OS,ORACLEL软件恢复数据
  • 在 linux 下卸载 oracle10g
  • 监控Oracle数据库的常用shell脚本
  • 【随机文章】
  • 你是不是用别的工具把MP3压缩过
  • SOA技术两年内将普遍应用于ERP中
  • C/C++书籍下载地址
  • sco 丢失分区表的问题
  • 深入了解JUnit 4
  • 软链接与硬链接的区别
  • 优秀的个人防火墙软件—ZoneAlarm(1)
  • 2.4内核中proc的简单读写操作
  • JAVA中浅复制与深复制
  • 使用对称加/解密时,要注意考虑填充
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.