tiempo online numero normal milisegundos fecha convertir conversor c++ date math

c++ - online - convertir numero a fecha unix



Matemáticas para convertir segundos desde 1970 en fecha y viceversa. (8)

Tengo segundos desde el 1 de enero de 1970 00:00 como un int64 en nanosegundos y estoy intentando convertirlo en mes / día / año / día de la semana.

Es fácil hacer esto de manera iterativa, tengo ese trabajo pero quiero hacerlo de manera formal. Estoy buscando las matemáticas reales.


ANTES DE

for (i = 0; i < (years - 1); i++) { if (LEAPYEAR((epoch + i))) countleap++; }

LUEGO:

for (i = 0; i < years; i++) { if (LEAPYEAR((epoch + i))) countleap++; }

Después de la corrección el código funcionó para mí.



En primer lugar, no almacene sus segundos como un flotador. Si necesita micro / nanosegundos, guárdelos por separado. Vas a necesitar enteros para hacer estos cálculos.

Depende de su zona horaria (reglas de DST, años bisiestos, segundos bisiestos), pero diría que primero obtenga la cantidad de días por entero dividiendo entre 86400. Luego averigüe qué queda, dividiendo el módulo entre 86400. Ahora puede calcular cuántos años han pasado por el primer entero dividiendo el número de días por 365, y luego restando el número de días bisiestos de los días restantes (calculados por el módulo dividiendo el número de días por 365). También querrá restar el número de segundos de salto del número de segundos restantes (ya calculado). Si esa resta conduce esos números por debajo de cero, entonces resta de la siguiente denominación más grande. Luego, puede calcular el día del mes utilizando la lógica explícita para su calendario. Asegúrese de agregar una hora (o lo que sea el desplazamiento DST) si aterriza en DST.

Personalmente, solo usaría Boost.Date_Time , ya que hace todo esto y más (probablemente con menos errores de los que usted o yo Boost.Date_Time en las primeras iteraciones), pero pensé que tomaría una oportunidad por su pregunta ...


Este código funciona ...

Uso: uint32_t getSecsSinceEpoch (1970, month, day, years_since_epoch, hour, minute, second);

Ejemplo: timestamp = getSecsSinceEpoch (1970, 6, 12, (2014 - 1970), 15, 29, 0)

Devoluciones: 1402586940

Puede verificarlo en www.epochconverter.com.

Tomó aproximadamente 20 minutos escribirlo y la mayor parte de eso se gastó discutiendo con un amigo sobre si debería incluir saltos de segundo, nano-segundos, etc. Blech.

Que te diviertas...

Dr. Bryan Wilcutt

#define DAYSPERWEEK (7) #define DAYSPERNORMYEAR (365U) #define DAYSPERLEAPYEAR (366U) #define SECSPERDAY (86400UL) /* == ( 24 * 60 * 60) */ #define SECSPERHOUR (3600UL) /* == ( 60 * 60) */ #define SECSPERMIN (60UL) /* == ( 60) */ #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) const int _ytab[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; /**************************************************** * Class:Function : getSecsSomceEpoch * Input : uint16_t epoch date (ie, 1970) * Input : uint8 ptr to returned month * Input : uint8 ptr to returned day * Input : uint8 ptr to returned years since Epoch * Input : uint8 ptr to returned hour * Input : uint8 ptr to returned minute * Input : uint8 ptr to returned seconds * Output : uint32_t Seconds between Epoch year and timestamp * Behavior : * * Converts MM/DD/YY HH:MM:SS to actual seconds since epoch. * Epoch year is assumed at Jan 1, 00:00:01am. ****************************************************/ uint32_t getSecsSinceEpoch(uint16_t epoch, uint8_t month, uint8_t day, uint8_t years, uint8_t hour, uint8_t minute, uint8_t second) { unsigned long secs = 0; int countleap = 0; int i; int dayspermonth; secs = years * (SECSPERDAY * 365); for (i = 0; i < (years - 1); i++) { if (LEAPYEAR((epoch + i))) countleap++; } secs += (countleap * SECSPERDAY); secs += second; secs += (hour * SECSPERHOUR); secs += (minute * SECSPERMIN); secs += ((day - 1) * SECSPERDAY); if (month > 1) { dayspermonth = 0; if (LEAPYEAR((epoch + years))) // Only counts when we''re on leap day or past it { if (month > 2) { dayspermonth = 1; } else if (month == 2 && day >= 29) { dayspermonth = 1; } } for (i = 0; i < month - 1; i++) { secs += (_ytab[dayspermonth][i] * SECSPERDAY); } } return secs; }



La especificación de Unix único proporciona una fórmula para segundos desde la época :

Un valor que se aproxima al número de segundos que han transcurrido desde la Época. Un nombre de hora universal coordinada (especificado en segundos (tm_sec), minutos (tm_min), horas (tm_hour), días desde el 1 de enero del año (tm_yday) y año calendario menos 1900 (tm_year)) está relacionado con una hora representado como segundos desde la Época, de acuerdo con la siguiente expresión.

Si el año es <1970 o el valor es negativo, la relación no está definida. Si el año es> = 1970 y el valor no es negativo, el valor se relaciona con un nombre de Tiempo Universal Coordinado de acuerdo con la expresión en lenguaje C, donde tm_sec, tm_min, tm_hour, tm_yday y tm_year son todos tipos de enteros:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

La relación entre la hora real del día y el valor actual por segundos desde la época no está especificada.

Cómo se define la implementación de cualquier cambio en el valor de segundos desde la Época para alinearse con una relación deseada con el tiempo real actual. Según lo representado en segundos desde la Época, cada día se contabilizará por exactamente 86400 segundos.

Nota: Los últimos tres términos de la expresión suman un día para cada año que sigue a un año bisiesto que comienza con el primer año bisiesto desde la Época. El primer término agrega un día cada 4 años a partir de 1973, el segundo resta un día cada 100 años a partir de 2001 y el tercero agrega un día cada 400 años a partir de 2001. Las divisiones en la fórmula son divisiones enteras ; es decir, el resto se descarta dejando solo el cociente entero.

Deberá convertir el mes y el día del mes a tm_yday para usar esta fórmula y eso también debe hacerse teniendo en cuenta los años bisiestos. El resto en la fórmula es trivial.

Trate de averiguar a partir de esto cómo recuperar la fecha y la hora en segundos.

EDITAR :

He implementado un convertidor en aritmética de enteros en esta respuesta .

Ver una prueba de funcionamiento en ideone .


Nueva respuesta para la vieja pregunta:

Razón para esta nueva respuesta: Las respuestas existentes no muestran los algoritmos para la conversión de nanosegundos a año / mes / día (por ejemplo, usan bibliotecas con la fuente oculta), o usan iteración en los algoritmos que muestran.

Esta respuesta no tiene iteración alguna.

Los algoritmos están aquí , y se explican con un detalle insoportable. También se someten a pruebas de unidad para verificar su corrección en un lapso de +/- un millón de años (mucho más de lo que necesita).

Los algoritmos no cuentan segundos de salto. Si lo necesita, puede hacerlo, pero requiere una búsqueda en la tabla, y esa tabla crece con el tiempo.

Los algoritmos de fecha solo tratan con unidades de días y no con nanosegundos. Para convertir los días a nanosegundos, multiplique por 86400*1000000000 (teniendo cuidado de asegurarse de que está usando aritmética de 64 bits). Para convertir nanosegundos a días, divida por la misma cantidad. O mejor aún, use la biblioteca <chrono> ++ <chrono> C ++ 11.

Hay tres algoritmos de fecha de este documento que son necesarios para responder a esta pregunta.

1. days_from_civil :

// Returns number of days since civil 1970-01-01. Negative values indicate // days prior to 1970-01-01. // Preconditions: y-m-d represents a date in the civil (Gregorian) calendar // m is in [1, 12] // d is in [1, last_day_of_month(y, m)] // y is "approximately" in // [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366] // Exact range of validity is: // [civil_from_days(numeric_limits<Int>::min()), // civil_from_days(numeric_limits<Int>::max()-719468)] template <class Int> constexpr Int days_from_civil(Int y, unsigned m, unsigned d) noexcept { static_assert(std::numeric_limits<unsigned>::digits >= 18, "This algorithm has not been ported to a 16 bit unsigned integer"); static_assert(std::numeric_limits<Int>::digits >= 20, "This algorithm has not been ported to a 16 bit signed integer"); y -= m <= 2; const Int era = (y >= 0 ? y : y-399) / 400; const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399] const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365] const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] return era * 146097 + static_cast<Int>(doe) - 719468; }

2. civil_from_days :

// Returns year/month/day triple in civil calendar // Preconditions: z is number of days since 1970-01-01 and is in the range: // [numeric_limits<Int>::min(), numeric_limits<Int>::max()-719468]. template <class Int> constexpr std::tuple<Int, unsigned, unsigned> civil_from_days(Int z) noexcept { static_assert(std::numeric_limits<unsigned>::digits >= 18, "This algorithm has not been ported to a 16 bit unsigned integer"); static_assert(std::numeric_limits<Int>::digits >= 20, "This algorithm has not been ported to a 16 bit signed integer"); z += 719468; const Int era = (z >= 0 ? z : z - 146096) / 146097; const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096] const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] const Int y = static_cast<Int>(yoe) + era * 400; const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] const unsigned mp = (5*doy + 2)/153; // [0, 11] const unsigned d = doy - (153*mp+2)/5 + 1; // [1, 31] const unsigned m = mp + (mp < 10 ? 3 : -9); // [1, 12] return std::tuple<Int, unsigned, unsigned>(y + (m <= 2), m, d); }

3. weekday_from_days :

// Returns day of week in civil calendar [0, 6] -> [Sun, Sat] // Preconditions: z is number of days since 1970-01-01 and is in the range: // [numeric_limits<Int>::min(), numeric_limits<Int>::max()-4]. template <class Int> constexpr unsigned weekday_from_days(Int z) noexcept { return static_cast<unsigned>(z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6); }

Estos algoritmos están escritos para C ++ 14. Si tiene C ++ 11, quite el constexpr . Si tiene C ++ constexpr , elimine constexpr , noexcept y static_assert s.

Tenga en cuenta la falta de iteración en cualquiera de estos tres algoritmos.

Se pueden usar así:

#include <iostream> int main() { int64_t z = days_from_civil(2015LL, 8, 22); int64_t ns = z*86400*1000000000; std::cout << ns << ''/n''; const char* weekdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; unsigned wd = weekday_from_days(z); int64_t y; unsigned m, d; std::tie(y, m, d) = civil_from_days(ns/86400/1000000000); std::cout << y << ''-'' << m << ''-'' << d << '' '' << weekdays[wd] << ''/n''; }

que produce:

1440201600000000000 2015-8-22 Sat

Los algoritmos están en el dominio público. Úsalos como quieras. El documento de algoritmos de fecha tiene varios algoritmos de fecha más útiles si es necesario (por ejemplo, la weekday_difference es muy simple y útil).

Estos algoritmos se envuelven en una biblioteca de fechas de código abierto, multiplataforma, de tipo seguro, si es necesario.

Si se necesita compatibilidad con la zona horaria o el segundo paso, existe una biblioteca de zona horaria construida sobre la biblioteca de fechas .

Actualización: diferentes zonas locales en la misma aplicación

Vea cómo convertir entre diferentes zonas horarias .

Actualización: ¿Hay algún inconveniente en ignorar los segundos de salto al hacer cálculos de fecha de esta manera?

Esta es una buena pregunta de los comentarios a continuación.

Respuesta: Hay algunas trampas. Y hay algunos beneficios. Es bueno saber lo que ambos son.

Casi todas las fuentes de tiempo de un sistema operativo se basan en Unix Time . Unix Time es un recuento de tiempo desde 1970-01-01 excluyendo los segundos de salto. Esto incluye funciones como la time(nullptr) C time(nullptr) y C ++ std::chrono::system_clock::now() , así como POSIX clock_gettime y clock_gettime . Este no es un hecho especificado por el estándar (excepto que está especificado por POSIX), pero es el estándar de facto.

Entonces, si su fuente de segundos (nanosegundos, lo que sea) descuida los segundos de salto, es exactamente correcto ignorar los segundos de salto cuando se convierte a tipos de campo como {year, month, day, hours, minutes, seconds, nanoseconds} . De hecho, tener en cuenta los segundos de los saltos en ese contexto en realidad introduciría errores.

Por lo tanto, es bueno saber su fuente de tiempo y, especialmente, saber si también descuida los segundos de salto como lo hace el Tiempo de Unix .

Si su fuente de tiempo no descuida los segundos de salto, aún puede obtener la respuesta correcta hasta el segundo. Solo necesitas saber el conjunto de segundos de salto que se han insertado. Aquí está la lista actual .

Por ejemplo, si obtiene un conteo de segundos desde 1970-01-01 00:00:00 UTC que incluye segundos de salto y sabe que esto representa "ahora" (que actualmente es 2016-09-26), el número actual de saltos los segundos insertados entre ahora y 1970-01-01 son 26. Por lo tanto, puede restar 26 de su conteo y luego seguir estos algoritmos para obtener el resultado exacto.

Esta biblioteca puede automatizar los cálculos en segundo lugar para usted. Por ejemplo, para obtener el número de segundos entre 2016-09-26 00:00:00 UTC y 1970-01-01 00:00:00 UTC, incluidos los segundos de salto, puede hacer esto:

#include "date/tz.h" #include <iostream> int main() { using namespace date; auto now = clock_cast<utc_clock>(sys_days{2016_y/September/26}); auto then = clock_cast<utc_clock>(sys_days{1970_y/January/1}); std::cout << now - then << ''/n''; }

que produce:

1474848026s

Si se descuidan los segundos de salto ( tiempo de Unix ) se ve así:

#include "date/date.h" #include <iostream> int main() { using namespace date; using namespace std::chrono_literals; auto now = sys_days{2016_y/September/26} + 0s; auto then = sys_days{1970_y/January/1}; std::cout << now - then << ''/n''; }

que produce:

1474848000s

Por una diferencia de 26s .

Este próximo Año Nuevo (2017-01-01) insertaremos el 27º salto en segundo lugar.

Entre 1958-01-01 y 1970-01-01 se insertaron 10 "segundos de salto", pero en unidades más pequeñas que un segundo, y no solo a fines de diciembre o junio. Documentación sobre exactamente cuánto tiempo se insertó y cuándo. es incompleto, y no he podido rastrear una fuente confiable.

Los servicios de mantenimiento de la hora atómica se iniciaron experimentalmente en 1955, y el primer TAI estándar internacional basado en atómicos tiene una época de 1958-01-01 00:00:00 GMT (que ahora es UTC). Antes de eso, lo mejor que teníamos eran relojes de cuarzo que no eran lo suficientemente precisos como para preocuparnos por los segundos de salto.


bool FloatToTime(float seconds_since_epoch, bool local_time, struct tm *timest) { struct tm *ret; time_t t=(time_t) seconds_since_epoch; if (local_time) ret=localtime(&t); else ret=gmtime(&t); if(ret==NULL) return false; memcpy(timest, ret, sizeof(struct tm)); return true; }

Pásale los segundos como primer parámetro. El segundo parámetro debe ser verdadero para la hora local, falso para GMT. El tercer parámetro es un puntero a una estructura para contener la respuesta.

Las estructuras de retorno son (desde la página del manual):

tm_sec: el número de segundos después del minuto, normalmente en el rango de 0 a 59, pero puede ser de hasta 60 para permitir segundos de salto.

tm_min: El número de minutos después de la hora, en el rango de 0 a 59.

tm_hour: El número de horas pasadas la medianoche, en el rango de 0 a 23.

tm_mday: El día del mes, en el rango de 1 a 31.

tm_mon: El número de meses desde enero, en el rango de 0 a 11.

tm_year: El número de años desde 1900.

tm_wday: el número de días desde el domingo, en el rango de 0 a 6.

tm_yday: El número de días desde el 1 de enero, en el rango de 0 a 365.

tm_isdst: un indicador que indica si el horario de verano está vigente a la hora descrita. El valor es positivo si el horario de verano está vigente, cero si no lo está, y negativo si la información no está disponible.