c++ - studio - visual c ubuntu
Convertir Windows Filetime a segundo en Unix/Linux (9)
Tengo un archivo de rastreo que cada tiempo de transacción representa en formato de tiempo de archivo de Windows. Estos números de tiempo son algo como esto:
- 128166372003061629
- 128166372016382155
- 128166372026382245
¿Podría por favor avisarme si hay alguna biblioteca C / C ++ en Unix / Linux para extraer el tiempo real (especialmente el segundo) de estos números? ¿Puedo escribir mi propia función de extracción?
(Descubrí que no puedo ingresar un código legible en un comentario, así que ...)
Tenga en cuenta que Windows puede representar tiempos fuera del rango de los tiempos de época de POSIX y, por lo tanto, una rutina de conversión debería devolver una indicación de "fuera de rango" según corresponda. El método más simple es:
... (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;
Básicamente, esta es la misma solución, excepto que esta codifica correctamente los números negativos de Ldap y corta los últimos 7 dígitos antes de la conversión.
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);
}
El tipo de FILETIME es el número de incrementos de 100 ns desde enero 1 1601.
Para convertir esto en un tiempo unix puede usar lo siguiente.
#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;
}
luego puede usar las funciones ctime para manipularlo.
La solución que divide y agrega no funcionará correctamente con el horario de verano.
Aquí hay un fragmento que funciona, pero es para windows.
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;
}
Nueva respuesta para la vieja pregunta.
Usando <chrono>
C ++ 11 más esta biblioteca gratuita de código abierto:
https://github.com/HowardHinnant/date
Uno puede convertir fácilmente estas marcas de tiempo a std::chrono::system_clock::time_point
, y también puede convertir estas marcas de tiempo a un formato legible por humanos en el calendario gregoriano:
#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'';
}
Para mí esto da como resultado:
2007-02-22 17:00:00.306162
2007-02-22 17:00:01.638215
2007-02-22 17:00:02.638224
En Windows, puede omitir el floor
y obtener el último dígito decimal de precisión:
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
Con las optimizaciones (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})
se traducirá en el tiempo de compilación a los days{134774}
que se convertirá en tiempo de compilación a cualquier unidad que sea. -expresión requiere (segundos, 100 nanosegundos, lo que sea). En pocas palabras: esto es muy legible y muy eficiente.
Si alguien necesita convertirlo en MySQL.
SELECT timestamp,
FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER)))
- CAST(11644473600 AS UNSIGNED INTEGER),0))
AS Converted FROM events LIMIT 100
Suponiendo que esté preguntando acerca de la estructura de FILETIME , entonces FileTimeToSystemTime hace lo que desea, puede obtener los segundos de la estructura SYSTEMTIME que produce.
También aquí hay una manera pura de hacerlo.
(Int32)(DateTime.FromFileTimeUtc(129477880901875000).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
Aquí está el resultado de ambos métodos en mi ventana inmediata:
(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
es bastante simple: la época de las ventanas comienza 1601-01-01T00: 00: 00Z. Son 11644473600 segundos antes de la época de UNIX / Linux (1970-01-01T00: 00: 00Z). Las marcas de Windows están en 100 nanosegundos. Por lo tanto, una función para obtener segundos de la época de UNIX será la siguiente:
#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL
unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
}