programing

Unix/Linux에서 Windows 파일 시간을 두 번째로 변환

stoneblock 2023. 6. 13. 21:57

Unix/Linux에서 Windows 파일 시간을 두 번째로 변환

각 트랜잭션 시간이 Windows 파일 시간 형식으로 표시된 추적 파일이 있습니다.다음 시간 숫자는 다음과 같습니다.

  • 128166372003061629
  • 128166372016382155
  • 128166372026382245

이 숫자들에서 실제 시간(특히 두 번째)을 추출할 수 있는 C/C++ 라이브러리가 유닉스/리눅스에 있는지 알려주시겠습니까?제가 직접 추출 기능을 써도 될까요?

매우 간단합니다. Windows 시대는 1601-01-01T00:00Z로 시작합니다.UNIX/Linux 시대(1970-01-01T00:00:00Z)보다 1,64473600초 전입니다.Windows 눈금은 100나노초입니다.따라서 UNIX epoch에서 초를 가져오는 함수는 다음과 같습니다.

#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL

unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
     return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
}

FILETIME 유형은 1601년 1월 11일 이후로 증가한 100ns 수입니다.

이를 unix time_t로 변환하려면 다음을 사용합니다.

#define TICKS_PER_SECOND 10000000
#define EPOCH_DIFFERENCE 11644473600LL
time_t convertWindowsTimeToUnixTime(long long int input){
    long long int temp;
    temp = input / TICKS_PER_SECOND; //convert from 100ns intervals to seconds;
    temp = temp - EPOCH_DIFFERENCE;  //subtract number of seconds between epochs
    return (time_t) temp;
}

그런 다음 ctime 함수를 사용하여 조작할 수 있습니다.

(댓글에 읽을 수 있는 코드를 입력할 수 없습니다. 그래서...)

Windows는 POSIX epoch time 범위 밖의 시간을 나타낼 수 있으므로 변환 루틴은 적절한 "범위 외" 표시를 반환해야 합니다.가장 간단한 방법은 다음과 같습니다.

   ... (as above)
   long long secs;
   time_t t;

   secs = (windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
   t = (time_t) secs;
   if (secs != (long long) t)    // checks for truncation/overflow/underflow
      return (time_t) -1;   // value not representable as a POSIX time
   return t;

오래된 질문에 대한 새로운 대답입니다.

C++11의 사용<chrono>또한 이 무료 오픈 소스 라이브러리:

https://github.com/HowardHinnant/date

이러한 타임스탬프를 매우 쉽게 변환할 수 있습니다.std::chrono::system_clock::time_point또한 그레고리력에서 이러한 타임스탬프를 사람이 읽을 수 있는 형식으로 변환합니다.

#include "date.h"
#include <iostream>

std::chrono::system_clock::time_point
from_windows_filetime(long long t)
{
    using namespace std::chrono;
    using namespace date;
    using wfs = duration<long long, std::ratio<1, 10'000'000>>;
    return system_clock::time_point{floor<system_clock::duration>(wfs{t} -
                        (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}))};
}

int
main()
{
    using namespace date;
    std::cout << from_windows_filetime(128166372003061629) << '\n';
    std::cout << from_windows_filetime(128166372016382155) << '\n';
    std::cout << from_windows_filetime(128166372026382245) << '\n';
}

저의 경우 다음과 같은 출력을 제공합니다.

2007-02-22 17:00:00.306162
2007-02-22 17:00:01.638215
2007-02-22 17:00:02.638224

Windows에서 실제로 다음을 건너뛸 수 있습니다.floor정밀도의 마지막 소수 자릿수를 구합니다.

    return system_clock::time_point{wfs{t} -
                        (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})};

2007-02-22 17:00:00.3061629
2007-02-22 17:00:01.6382155
2007-02-22 17:00:02.6382245

최적화가 설정된 경우 하위 표현식(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})컴파일 시간에 다음으로 변환합니다.days{134774}이는 전체 변환에 필요한 단위(초, 100나노초 등)로 추가로 컴파일 시간을 연장합니다.결론:이것은 매우 읽기 쉽고 매우 효율적입니다.

분할하고 추가하는 솔루션은 일광 절약 시간제에서는 제대로 작동하지 않습니다.

여기에 작동하는 코드 조각이 있지만, 이것은 윈도우용입니다.

time_t FileTime_to_POSIX(FILETIME ft)
{
    FILETIME localFileTime;
    FileTimeToLocalFileTime(&ft,&localFileTime);
    SYSTEMTIME sysTime;
    FileTimeToSystemTime(&localFileTime,&sysTime);
    struct tm tmtime = {0};
    tmtime.tm_year = sysTime.wYear - 1900;
    tmtime.tm_mon = sysTime.wMonth - 1;
    tmtime.tm_mday = sysTime.wDay;
    tmtime.tm_hour = sysTime.wHour;
    tmtime.tm_min = sysTime.wMinute;
    tmtime.tm_sec = sysTime.wSecond;
    tmtime.tm_wday = 0;
    tmtime.tm_yday = 0;
    tmtime.tm_isdst = -1;
    time_t ret = mktime(&tmtime);
    return ret;
}

FILETIME Structure에 대해 질문한다고 가정하면 FileTime은SystemTime은 원하는 작업을 수행하기 위해 생성되는 SYSTEMTIME 구조에서 초를 얻을 수 있습니다.

여기에 기본적으로 동일한 솔루션이 있습니다. 단, 이 솔루션은 LDAP에서 음수를 올바르게 인코딩하고 변환 전 마지막 7자리 숫자를 제거합니다.

    public static int LdapValueAsUnixTimestamp(SearchResult searchResult, string fieldName)
    {
        var strValue = LdapValue(searchResult, fieldName);
        if (strValue == "0") return 0;
        if (strValue == "9223372036854775807") return -1;

        return (int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600);
    }

MySQL에서 변환이 필요한 경우

SELECT timestamp, 
       FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER))) 
         - CAST(11644473600 AS UNSIGNED INTEGER),0)) 
       AS Converted FROM events  LIMIT 100

또한 여기에 순수한 C# 방식이 있습니다.

(Int32)(DateTime.FromFileTimeUtc(129477880901875000).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;

다음은 바로 내 창에 있는 두 가지 방법의 결과입니다.

(Int32)(DateTime.FromFileTimeUtc(long.Parse(strValue)).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
1303314490
(int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600)
1303314490
DateTime.FromFileTimeUtc(long.Parse(strValue))
{2011-04-20 3:48:10 PM}
    Date: {2011-04-20 12:00:00 AM}
    Day: 20
    DayOfWeek: Wednesday
    DayOfYear: 110
    Hour: 15
    InternalKind: 4611686018427387904
    InternalTicks: 634389112901875000
    Kind: Utc
    Millisecond: 187
    Minute: 48
    Month: 4
    Second: 10
    Ticks: 634389112901875000
    TimeOfDay: {System.TimeSpan}
    Year: 2011
    dateData: 5246075131329262904

언급URL : https://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux