• 【实时数据库PISDK】关于PITime的悲剧


    不知道为什么,在PISDK的文档中如果仅看目录发现不了PITime,只有通过索引进行查找方能找到。而如果想通过PISDK插入实时数据的话,必须要同时插入当前时间。如何获取当前时间着实是一个问题,想规范地显示所获取的时间也是一个问题。目前我是这样解决的:

    获取当前时间:(typedef long time_t;/* time value */)

    #include <time.h>
    
    time_t now;
    time(&now);

    显示查询所得时间:(DATE类型转字符串,typedef double DATE;)

    #include <afxdisp.h>
    
    void showDateTime(DATE datetime)
    {
    	// 输出时间
    	COleDateTimeSpan timespan(datetime);
    	COleDateTime tm = timespan;
    	char szTime[24];
    	sprintf(szTime,"%04i-%02i-%02i %02i:%02i:%02i",
    			tm.GetYear(),tm.GetMonth(),tm.GetDay(),
    			tm.GetHour(),tm.GetMinute(),tm.GetSecond());
    	printf("输出时间:%s\n",szTime);
    }

    可以看到time_t实际上是long类型,而DATE实际上是double类型。由于向上兼容,我将time_t当做DATE进行传参没有问题。但这里需要额外引入两个头文件。尤其是后者,与windows.h的兼容性还不是很好。如果能在SDK中找到相关类型就好了。

    所以还是看看PITime吧:

    PITime是在PI-SDK上为表示特殊时间而设计的最简单的类。其内部存储了UTC世界时间。该对象是“服务器独立”的,这意味着当它设计之初时就没有时区的概念。PITime的属性提供了对一些用基本格式存储的时间进行读、写的访问方式。当对一个属性读或写时,时间将呈现本地时间格式,所有的转换操作基于对象执行的系统所设置的时区。用PITimeFormat 接口的对象可在不同的时区中将PITime转化为一个本地时间,该对象可用PITime类来设置。

    以上是PITime的介绍,其中比较有用的属性是LocalDate,方法是SetToCurrent

    通过tagName查询时间时,便可定义_PITimePtr:

    _PITimePtr pTime = pValue->TimeStamp;

    然后需要取得当前时间的地方,调用SetToCurrent即可:

    pTime->SetToCurrent();

    然后pTime->LocalDate便可返回当前时间了(DATE类型的)。

    此时我以为问题完美的解决了,并可以代替time.h那个方案。但是接下来发生的事情却是始料未及的:

    无法插入了!UpdateValue函数的第二个参数用了pTime->LocalDate之后,插入莫名其妙的失效了。虽然返回值仍是正常的。这让我一度怀疑是PI数据库本身的问题,恰好此时数据库真的出现了一些问题…,但第二天我偶然将参数二换回了time.h方案中的now,插入却正常了。

    我们千辛万苦的想用PI提供的类和函数,但事实却证明它并不及C标准库函数来的有效。甚至我可以直接用windows提供的函数实现;

    #include <windows.h>
    
    SYSTEMTIME sys;
    GetLocalTime(&sys);
    char nowtime[24];
    sprintf(nowtime,"%4d-%02d-%02d %02d:%02d:%02d.%03d",
    		sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute, sys.wSecond,
    		sys.wMilliseconds);
    printf("当前时间:%s\n",nowtime);

    上述的nowtime强制转换为(_bstr_t)之后也可以作为UpdateValue的参数二使用,也能使插入正常。

    这不由得让我想到了几天前我在解决如何查询某时间段内的一组数据时遇到的问题:

    我使用的是RecordedValues,代码如下:

    _PIValuesPtr pValues_recorded = pPoint->Data->
    RecordedValues("2011-10-20 11:32:14","2011-10-20 11:35:54",
    btAuto,"",fvShowFilteredState,NULL);

    可以看到,参数一和参数二我都没有使用DATE类型的数据,而编码之初,我却优先考虑使用DATE类型,当时我试图将查询所得的pTime->LocalDate作为其中之一的参数。但没有任何效果,我以为是函数本身的问题,细致读了好几遍文档后才确定用对了函数。也是很偶然的使用了字符串直接作为参数后,才得以查询成功。当时没细想DATE类型的事,今日回忆方能得出以下结论:

    虽然PISDK文档中诸多函数的参数提供了DATE类型的选项,但DATE类型参数实际上会使函数无法正常运行,且不会报出任何错误。这也许是PISDK的bug,或是什么我无法想到的原因。

    所以不要对PITime报以希望了,维持原方案,如果不想引入过多的头文件,可以用windows函数的那套方案(还可以看到毫秒数)。

    接下来还有一个问题:如何将DATE类型的数据转换为字符串型进行输出。幸运的是,PISDK里给出了提示

    or VariantChangeType() in C++ to convert between DATE and string types.

    不幸的是,看完VariantChangeType的介绍之后:我发现这个函数仅仅起到一个转换的作用,我得到的DATE类型数据(实际是double)为40843.4324101158,转化为string类型,仍旧是40843.4324101158,这样的东西输出出来没有任何参考价值。我完全可以直接来一个强制转换,加上(_bstr_t)即可。它无法如我原方案那样给出一个格式化的功能。

    得出这样的结论,无疑让我倍受打击。PISDK给出的建议并非能够解决实际问题。我们依旧需要#include <afxdisp.h>(至少在VC6中如此),才能在控制台方便得显示出我们查询出的时间数据。

    就这样算了么?这不符合我的风格,至少要解决原方案中引入的头文件与windows.h的冲突。能不能也用windows函数来解决DATE类型显示的问题呢?

    还真有这样的函数:VariantTimeToSystemTime(_int DATE,_out &SYSTEMTIME),重新写showDateTime吧:

    void showDateTime(DATE datetime)
    {
    	// 输出时间
    	SYSTEMTIME sys;
    	VariantTimeToSystemTime(datetime,&sys);
    	char thetime[24];
    	sprintf(thetime,"%4d-%02d-%02d %02d:%02d:%02d",
    		sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond);
    	printf("获取时间:%s\n",thetime);
    }

    这个问题总算是有了一个交代。不知大家是否满意呢?

    作者:pezy 出处:http://www.cnblogs.com/pezy 欢迎转载,也请保留这段声明。谢谢!
  • 相关阅读:
    删除CSDN上传图片水印
    Win10任务栏中隐藏/恢复日期显示
    使用idea和gradle编译spring5源码
    错误:找不到或无法加载主类
    判断字符串是否为数字
    mysql根据json数据过滤
    mysql当不存在时插入
    org.apache.xerces.parsers.SAXParser
    mybatis mapper判断if条件写法
    《Java面向对象编程》
  • 原文地址:https://www.cnblogs.com/pezy/p/2226204.html
Copyright © 2020-2023  润新知