web-dev-qa-db-fra.com

Math pour convertir les secondes depuis 1970 en date et vice versa

J'ai quelques secondes depuis le 1er janvier 1970 00:00 en tant que int64 en nanosecondes et j'essaie de le convertir en mois/jour/année/jour de la semaine.

C'est facile de faire cela de façon itérative, je travaille mais je veux le faire selon une formule. Je cherche les maths actuels.

24
David

La spécification Single Unix donne une formule pour secondes depuis l’époque :

Une valeur qui correspond approximativement au nombre de secondes écoulées depuis l'époque. Nom en temps universel coordonné (spécifié en termes De secondes (tm_sec), de minutes (tm_min), d'heures (tm_heure), de jours depuis le Du 1er janvier de l'année (tm_yday) et d'année civile moins 1900 (tm_year)) est liée à une heure représentée en secondes depuis le Epoque, selon l'expression ci-dessous.

Si l'année est <1970 ou si la valeur est négative, la relation est indéfini. Si l'année est> = 1970 et que la valeur est non négative, le la valeur est liée à un nom de temps universel coordonné selon le Expression en langage C, où tm_sec, tm_min, tm_hour, tm_yday et tm_year sont tous des types entiers:

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 relation entre l'heure du jour et la valeur actuelle pendant des secondes depuis l'époque est indéterminée.

Comment toutes les modifications apportées à la valeur des secondes depuis l’époque sont-elles apportées à aligner sur une relation souhaitée avec l’heure réelle actuelle est défini par la mise en œuvre. Tel que représenté en secondes depuis l’époque, chaque jour sera compté avec exactement 86400 secondes.

Remarque: Les trois derniers termes de l'expression ajoutent un jour pour chaque année qui suit une année bissextile à partir de la première année bissextile depuis le Époque. Le premier terme ajoute un jour tous les 4 ans à partir de 1973, le seconde soustrait un jour de retour tous les 100 ans à compter de 2001, et le troisième ajoute un jour de retour tous les 400 ans à compter de 2001. Le les divisions dans la formule sont des divisions entières; c'est-à-dire le reste est rejeté en ne laissant que le quotient entier.

Vous devrez convertir le mois et le jour du mois en tm_yday pour utiliser cette formule, ce qui devrait également être fait en tenant compte des années bissextiles. Le reste de la formule est trivial.

Essayez de comprendre comment récupérer la date et l'heure en secondes.

MODIFIER:

J'ai implémenté un convertisseur en arithmétique entière dans cette réponse .

Voir un test chez ideone .

10
Alexey Frunze
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;
}

Passez les secondes comme premier paramètre. Le deuxième paramètre doit être vrai pour l'heure locale et faux pour l'heure GMT. Le troisième paramètre est un pointeur sur une structure pour contenir la réponse.

Les structures de retour sont (à partir de la page de manuel):

tm_sec: nombre de secondes après la minute, généralement compris entre 0 et 59, mais peut aller jusqu'à 60 pour permettre des secondes intercalaires.

tm_min: nombre de minutes après l'heure, compris entre 0 et 59.

tm_hour: nombre d'heures après minuit, dans la plage de 0 à 23.

tm_mday: jour du mois compris entre 1 et 31.

tm_mon: nombre de mois depuis janvier, compris entre 0 et 11.

tm_year: nombre d'années depuis 1900.

tm_wday: nombre de jours depuis dimanche, compris entre 0 et 6.

tm_yday: nombre de jours écoulés depuis le 1 er janvier, compris entre 0 et 365.

tm_isdst: un drapeau qui indique si l'heure d'été est en vigueur à l'époque décrite. La valeur est positive si l'heure d'été est passée le temps est en vigueur, nul s'il ne l'est pas et négatif si le l'information n'est pas disponible.

2
David Schwartz

Dépend de l’heure de votre choix gmtime ou localtime puis il suffit de lire le struct_tm

2
Martin Beckett

Il existe de nombreuses fonctions pour ce faire, voir http://www.cplusplus.com/reference/clibrary/ctime/ , à savoir strftime .

1
Seth Carnegie

Ce code fonctionne ...

Utilisation: Uint32_t getSecsSinceEpoch (1970, mois, jour, années_since_Epoch, heure, minute, seconde);

Exemple: Timestamp = getSecsSinceEpoch (1970, 6, 12, (2014 - 1970), 15, 29, 0)

Retours: 1402586940

Vous pouvez vérifier sur www.epochconverter.com.

Il a fallu environ 20 minutes pour l'écrire et la plus grande partie a été consacrée à des discussions avec un ami sur le point de savoir si je devais inclure les secondes intercalaires, les nano-secondes, etc. Blech.

S'amuser...

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;
}
1
user3735867

AVANT

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

PLUS TARD:

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

Après la correction, le code a fonctionné pour moi.

0
Shahbaz

Tout d'abord, ne stockez pas vos secondes sous forme de float. Si vous avez besoin de micro/nanosecondes, stockez-les séparément. Vous allez avoir besoin de nombres entiers pour faire ces calculs.

Cela dépend de votre fuseau horaire (règles DST, années bissextiles, secondes bissextiles), mais je dirais d’abord obtenir le nombre de jours en divisant le nombre entier par 86400. Recherchez ensuite ce qui reste, en divisant par modulo par 86400. Vous pouvez maintenant déterminer le nombre d'années écoulées en commençant par diviser le nombre de jours par 365, puis en soustrayant le nombre de jours bissextiles des jours restants (calculé en divisant le nombre de jours par modulo par 365). Vous voudrez également soustraire le nombre de secondes intercalaires du nombre de secondes restantes (déjà calculé). Si cette soustraction conduit ces nombres en dessous de zéro, alors soustrayez de la dénomination la plus grande suivante. Ensuite, vous pouvez calculer le jour du mois en utilisant une logique explicite pour votre calendrier. Assurez-vous d'ajouter une heure (ou quel que soit le décalage de l'heure d'été) si vous atterrissez en heure d'été.

Personnellement, je voudrais juste utiliser Boost.Date_Time , puisqu’il fait tout cela et plus (probablement avec moins d’erreurs que vous ou moi je ferais dans les premières itérations), mais j’ai pensé que j’essaierais votre question...

0
gred