在SYSTEMTIME上进行算术运算

7

我有一个用SYSTEMTIME表示的时间值,我想从中加/减1小时并得到新获取的SYSTEMTIME。我希望转换应该在加法/减法或月份变化或年份变化时考虑日期改变。

如果有一些Windows API可以对SYSTEMTIME进行算术运算,请问是否有人可以帮助我?


2
你使用的是哪种编程语言?SYSTEMTIME 是什么意思? - Andrey Marchuk
@Marco 抱歉我来晚了...还有,谢谢你,它对我很有效。 - Peter
3个回答

13
如果你在使用C#(或VB.NET,或ASP.NET),你可以使用。
DateTime dt = DateTime.Now.AddHours(1);

您可以使用负数来进行减法:

DateTime dt = DateTime.Now.AddHours(-1);

编辑: 我从这篇文章中提取了一个答案。

他们建议将SYSTEMTIME转换为FILETIME,后者是自纪元以来的一定数量的滴答声。然后,您可以添加所需数量的“ticks”(即100ns间隔)来表示您的时间,并转换回SYSTEMTIME。

ULARGE_INTEGER结构是具有QuadPart成员的联合体,它是一个64位数字,最近的硬件可以直接对其进行加法运算。

SYSTEMTIME add( SYSTEMTIME s, double seconds ) {

    FILETIME f;
    SystemTimeToFileTime( &s, &f );

    ULARGE_INTEGER u  ; 
    memcpy( &u  , &f , sizeof( u ) );

    const double c_dSecondsPer100nsInterval = 100. * 1.E-9;
    u.QuadPart += seconds / c_dSecondsPer100nsInterval; 

    memcpy( &f, &u, sizeof( f ) );

    FileTimeToSystemTime( &f, &s );
    return s;
 }

如果你想增加一个小时,使用 SYSTEMTIME s2 = add(s1, 60*60)


我正在使用 Windows 的 SYSTEMTIME 结构。 - Peter
@Peter:好的,但是你使用的是哪种编程语言? - Marco

7

在C++中添加带符号的秒数(向前或向后):

const double clfSecondsPer100ns = 100. * 1.E-9;
void iAddSecondsToSystemTime(SYSTEMTIME* timeIn, SYSTEMTIME* timeOut, double tfSeconds)
{
    union {
        ULARGE_INTEGER li;
        FILETIME       ft;
    };

    // Convert timeIn to filetime
    SystemTimeToFileTime(timeIn, &ft);

    // Add in the seconds
    li.QuadPart += tfSeconds / clfSecondsPer100ns;

    // Convert back to systemtime
    FileTimeToSystemTime(&ft, timeOut);
}

这个 union 的技巧是什么?你没有对 ft 进行任何计算,但结果却返回了它...我不明白。 - Sandburg
1
64位FILETIME的字节/位模式与ULARGE_INTEGER相同。 通过填充ft,您也正在填充li的部分,这使您可以在该点使用li。内存中的位置只是以两种不同的方式检查数据。 使用ft,您将其视为FILETIME。 通过使用li,您将其视为ULARGE_INTEGER。 - Rick C. Hodgin
这种(将FILETIME解释为ULARGE_INTEGER)方式是被MSDN所不鼓励的。 - CookiePLMonster
他们不鼓励这样做,因为他们不打算永远停留在x86上。他们希望您使用可以在其他架构上移植而无需更改的函数。如果您有这种需要(其他架构可移植性),那么这一切都很好。但是,如果您严格遵循x86(或更通用地说,小端)的话,这种方法可以正常工作。 - Rick C. Hodgin
1
MSDN 的警告与对 FILETIME 的非对齐访问有关。然而,C++ 联合体对于最严格的对齐要求进行了对齐。因此,这种解决方案可以避免 MSDN 所警告的问题。 - MSalters
MSaltes,编译器会自动对齐变量,除非明确告知将其打包在1或2字节边界上。像这样的本地变量在堆栈上始终(至少)DWORD对齐32位代码,并在64位代码中QWORD对齐。在32位代码中,它将是两个32位访问,这些访问将被对齐。在64位代码中,它将是一个64位访问,这个访问将被对齐。 - Rick C. Hodgin

5
#include <stdio.h>
#include <windows.h>
#define NSEC 60*60

main()
{
SYSTEMTIME st;
FILETIME ft;

// Get local time from system
GetLocalTime(&st);

printf("%02d/%02d/%04d %02d:%02d:%02d\n",
  st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond);

// Convert to filetime
SystemTimeToFileTime(&st,&ft);

// Add NSEC seconds
((ULARGE_INTEGER *)&ft)->QuadPart +=(NSEC*10000000LLU);

// Convert back to systemtime
FileTimeToSystemTime(&ft,&st);

printf("%02d/%02d/%04d %02d:%02d:%02d\n",
  st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond);
}

我正在使用VS2008,出现了“在你添加秒的那一行出现了错误后缀”的错误。 - Nikunj Chaklasiya
请勿将指向FILETIME结构的指针转换为ULARGE_INTEGER或__int64值,因为这可能会在64位Windows上导致对齐故障。 https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime - Piotr
在64位Windows中,64位应用程序中的ft本地变量将位于堆栈上,并且它将是QWORD对齐(8字节对齐)。它永远不会被错位。在32位应用程序中,它将至少是DWORD对齐,并且对数据的访问将以两个32位读/写进行,因此它也不会被错位。64位指针转换警告通常是普遍存在的。它有像这样(和许多其他)不是问题的情况。您必须了解您的数据。 - Rick C. Hodgin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接