web-dev-qa-db-fra.com

Convertir l'horodatage Unix en heure lisible par l'homme

Je voudrais afficher un fichier texte avec awk/grep qui contient un horodatage Unix dans la première colonne. Comment puis-je le convertir en une heure lisible par l'homme lors de la visualisation?

16
TheRojam

Si la ligne commence par l'horodatage Unix, alors cela devrait le faire:

Perl -pe 's/^(\d+)/localtime $1/e' inputfilename

Perl -p appelle une boucle sur l'expression passée avec -e qui est exécuté pour chaque ligne de l'entrée et imprime le tampon à la fin de la boucle.

L'expression utilise la commande de sous-station s/// pour faire correspondre et capturer une séquence de chiffres au début de chaque ligne, et la remplacer par la représentation de l'heure locale de ces chiffres interprétée comme un horodatage Unix. /e indique que le modèle de remplacement doit être évalué comme une expression.

19
wurtel

Si votre AWK est Gawk , vous pouvez utiliser strftime:

gawk '{ print strftime("%c", $1) }'

convertira l'horodatage de la première colonne en la représentation par défaut de la date/heure des paramètres régionaux actuels.

Vous pouvez l'utiliser pour transformer le contenu avant de le visualiser:

gawk '{ print gensub($1, strftime("%c", $1), 1) }' inputfile
18
Stephen Kitt

Comme Dan mentionne dans sa réponse , la commande Gnu date(1) peut recevoir un paramètre -d Avec une date ou un horodatage qu'elle traitera comme la date à sortir . (Ceci n'est cependant pas disponible dans les commandes POSIX ou BSD date(1).) @1571806800 Est le format utilisé pour spécifier un entier time_t.

Voici une fonction Bash Shell qui agit comme un filtre, lisant les lignes de l'entrée, en supposant que tout mot commençant une ligne composée de tous les chiffres est un horodatage et le convertissant en sortie lisible par l'homme dans l'un de mes formats préférés.

ts2hr() {
    while read n rest; do
        if [[ $n =~ ^[0-9][0-9]*$ ]]; then
            echo "$(date -d @"$n" +"%Y-%m-%d %T")" "$rest"
        else
            echo "$n" "$rest"
        fi
    done
}

Voici à quoi ressemblent certaines entrées et sorties:

ts2hr <<____
1571806123 first line
# A comment?
1571720456 second date's here
Just a regular sentence.
1571547789 The last line.
____
2019-10-23 13:48:43 first line
# A comment?
2019-10-22 14:00:56 second date's here
Just a regular sentence.
2019-10-20 14:03:09 The last line.

Vous pouvez modifier la fonction si nécessaire pour gérer les formats d'entrée et de sortie particuliers dont vous avez besoin, ainsi que les outils dont vous disposez. La fonction ci-dessus est Bash principalement parce que l'opérateur =~ A rendu la correspondance de motif plus facile; si vous en avez besoin dans Bourne Shell, vous devrez coder le chèque différemment, si vous en avez vraiment besoin.

8
cjs

utiliser "date"

Vous n'avez pas besoin de Perl, awk, php ou d'une longue expression arithmétique pour cela. Vous pouvez le faire avec gnu "date", ce qui est vraiment très utile pour ce genre de chose. Pour les autres versions de "date", votre YMMV.

$ date -d '1/1/1970 GMT 1571889039 seconds'
Wed Oct 23 20:50:39 PDT 2019

Ce qui se passe ici, c'est que vous spécifiez une heure et un ajustement. Il est minuit le 1er janvier 1970 GMT, l'époque unix. (Minuit n'est pas explicitement indiqué; il est utilisé implicitement chaque fois que vous omettez l'heure de la journée.)

L'ajustement, 1571889039 secondes, est ajouté à l'heure. Utilisez plutôt votre horodatage. Les documents utilisent le mot "relatif" pour cette fonctionnalité.

Il existe une version plus concise, documentée uniquement par un exemple dans la page de manuel, qui fonctionne pour les nouvelles versions de gnu date:

$ date -d @2147483647
Mon Jan 18 19:14:07 PST 2038

Si vous devez souvent manipuler des dates, découvrez votre commande date. C'est plus qu'une simple horloge; c'est une bibliothèque de date/heure pour le Shell.

5
Dan

Pour une version portable de cela, dans le pire des cas, vous pouvez faire le calcul vous-même. Les horodatages Unix sont définis dans POSIX XBD 4,16 secondes depuis l'époque :

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

C'est l'inverse du mappage que vous voulez, donc un peu de travail* est nécessaire pour l'inverser. Cela vous amènera à "POSIX UTC", mais vous aurez peut-être besoin d'un moyen de le formater dans le fuseau horaire actuel. Il semble date -d n'est pas portable, donc je ne sais pas s'il y a un bon moyen de le faire.

* Ok cela peut être un euphémisme.

Si vous n'avez pas de date gnu ou d'accès à un langage de programmation avec strftime ou équivalent, vous devez faire le calcul vous-même, qui va dans le territoire de golf de code.

unix_to_iso_utc () {
    local day_unix=$(($1 / 86400))
    local day_offset=$(($1 % 86400))
    local d=$(($day_unix + 719468))
    local y=$((($d - ($d+2+3*$d/146097)/1461 + ($d-$d/146097)/36524 - ($d+1)/146097)/365))
    local y_d=$((365*$y + $y/4 - $y/100 + $y/400))
    local y_offset=$(($d - $y_d))
    local m=$((($y_offset - ($y_offset+20)/50) / 30))
    local m_d=$((30*$m + 3*($m+4)/5 - 2))
    local day=$(($y_offset - $m_d + 1))
    local m_cont=$((12*$y + $m + 2))
    local year=$(($m_cont/12))
    local month=$(($m_cont%12 + 1))
    local hour=$(($day_offset / 3600))
    local hour_offset=$(($day_offset % 3600))
    local minute=$(($hour_offset / 60))
    local second=$(($hour_offset % 60))
    DATE=$(printf "%04d-%02d-%02dT%02d:%02d:%02d" $year $month $day $hour $minute $second)
}

Vous n'avez probablement pas non plus de base de données de fuseau horaire à ce stade, ce qui peut être un énorme problème pratique, sauf si vous pouvez coder en dur ce dont vous avez besoin.

2
Teemu Kalvas

Comme cela a été dit, il n'y a pas vraiment de moyen portable de le faire en utilisant Shell, ou même AWK. GAWK peut le faire, mais GAWK strftime n'est pas disponible avec certaines versions d'AWK, à savoir MAWK. Et MAWK est utilisé avec certaines distributions populaires, par exemple Debian.

J'accepte qu'une solution Shell ou AWK portable soit disponible pour cela. Mais comme ce n'est pas le cas et ne le sera probablement pas pendant de nombreuses années, voire jamais, la meilleure solution consiste à simplement utiliser un langage de programmation. Perl a été suggéré, une autre option est PHP:

$ cat input.txt
1571806800 blue
1571720400 green
1571634000 orange
1571547600 red
1571461200 yellow

$ cat app.php
<?php
$r1 = fopen('input.txt', 'r');
while (true) {
   $s1 = fgets($r1);
   if ($s1 === false) {
      break;
   }
   $a1 = explode(' ', $s1);
   $n1 = + $a1[0];
   echo date(DATE_W3C, $n1), "\n";
}

$ php app.php
2019-10-23T05:00:00+00:00
2019-10-22T05:00:00+00:00
2019-10-21T05:00:00+00:00
2019-10-20T05:00:00+00:00
2019-10-19T05:00:00+00:00
1
Nine