# Sekunden in Tage, Stunden, Minuten und Sekunden umrechnen

## l3u

Hi :-)

Ich habe folgende Funktion in einem Bash-Script:

```
function printSeconds

{

   days=$(($1 / 86400))

   hours=$((($1 / 3600) - (days * 24)))

   minutes=$((($1 / 60) - (days * 1440) - (hours * 60)))

   seconds=$(($1 % 60))

   out=""

   if [[ $days -gt 0 ]]; then

      out="$days day"

      if [[ $days -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $hours -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$hours hour"

      if [[ $hours -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $minutes -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$minutes minute"

      if [[ $minutes -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $seconds -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$seconds second";

      if [[ $seconds -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ "$out" == "" ]]; then

      out="0 seconds"

   fi

   echo -n $out

}
```

Die ist aber relativ lahm, deswegen hab ich mir gedacht, daß das awk bestimmt schneller kann, und folgende Funktion ausprobiert:

```
function printSeconds

{

   awk "

      function formatValue(value, valueName, valueNamePlural)

      {

         if(value > 0) {

            plural = \"\";

            if(value > 1) {

               plural = valueNamePlural

            }

            return sprintf(\"%s %s%s\", value, valueName, plural);

         }

      }

      function joinFormattedValue(currentString, value)

      {

         if(currentString != \"\") {

            return sprintf(\"%s, %s\", currentString, value)

         }

         else {

            return value

         }

      }

      BEGIN {

         allSecs = $1;

         days    = int( allSecs / 86400)

         hours   = int((allSecs / 3600) - (days * 24))

         minutes = int((allSecs / 60)   - (days * 1440) - (hours * 60))

         seconds = int( allSecs % 60)

         timeString = \"\"

         timeString = joinFormattedValue(timeString, formatValue(days, \"day\", \"s\"))

         timeString = joinFormattedValue(timeString, formatValue(hours, \"hour\", \"s\"))

         timeString = joinFormattedValue(timeString, formatValue(minutes, \"minute\", \"s\"))

         timeString = joinFormattedValue(timeString, formatValue(seconds, \"second\", \"s\"))

         printf(\"%s\", timeString)

         exit

      }

   "

}
```

Die dauert aber tatsächlich doppelt so lang(!) wie die Bash-Variante.

Wie kann man das schneller machen?! Irgendwelche Tricks, Vorschläge? Muß nicht awk sein! Es muß nur eine Funktion sein, die Sekunden nimmt, und dann Tage, Stunden, Minuten und Sekunden ausspuckt.

MfG

----------

## 69719

Das erste Beispiel sollte schon die schnellste variante sein, da dies direkt von der bash und nicht durch ein extra programm berechnet wird.

----------

## l3u

Aber das ist echt langsam … gibt's denn da nichts schnelleres?

----------

## 69719

Das Problem ist nicht die Berechnung, sondern die Befehle die von der Bash ausgeführt werden sowie das parsen des Bashscripts.

```

PC411 ~ $ cat timecalc1.sh 

#!/bin/bash

function printSeconds

{

   days=$(($1 / 86400))

   hours=$((($1 / 3600) - (days * 24)))

   minutes=$((($1 / 60) - (days * 1440) - (hours * 60)))

   seconds=$(($1 % 60))

   out=""

   if [[ $days -gt 0 ]]; then

      out="$days day"

      if [[ $days -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $hours -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$hours hour"

      if [[ $hours -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $minutes -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$minutes minute"

      if [[ $minutes -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ $seconds -gt 0 ]]; then

      if [[ "$out" != "" ]]; then out="$out, "; fi

      out="$out$seconds second";

      if [[ $seconds -gt 1 ]]; then out="${out}s"; fi

   fi

   if [[ "$out" == "" ]]; then

      out="0 seconds"

   fi

   echo -n $out

}

printSeconds $1

echo ""

PC411 ~ $ time ./timecalc1.sh 56789

15 hours, 46 minutes, 29 seconds

real    0m0.251s

user    0m0.030s

sys     0m0.030s

```

```

PC411 ~ $ cat timecalc2.sh 

#!/bin/bash

function printSeconds

{

        echo -n $1

}

printSeconds $1

echo ""

PC411 ~ $ time ./timecalc2.sh 56789

56789

real    0m0.248s

user    0m0.046s

sys     0m0.031s

```

----------

## ScytheMan

Kurz in python implementiert:

Läuft bei mir eigentlich recht fix, wobei ich nicht weiß was du als "fix" ansiehst.

```

def change(sec):

        days = int(sec / 86400)

        hours = int((sec /3600) - (days * 24))

        minutes = int((sec / 60) - (days * 1440) - (hours*60))

        seconds = int(sec%60)

        return "Tage: %i Stunden: %i Minuten: %i Sekunden: %i" %(days,hours,minutes,seconds)

print change(float(raw_input("Sekunden eingeben: ")))

```

----------

## l3u

Und wie erklärst du dann, daß die Bash-Variante bei einem Test hier (zieht paar Zeilen aus einer Logdatei raus und macht 27 solche Berechnungen) eine knappe halbe Sekunde dauert, die awk-Variante aber eine ganze? Liegt das bloß daran, daß für die awk-Variante ein zusätzlicher Prozeß gestartet wird?

@ScytheMan: Läuft's schneller als die Bash-Variante, wenn's von einem Bash-Script aufgerufen wird? Wenn man's 100 mal oder so aufruft?

----------

## ScytheMan

das weiß ich nicht wie kriegst du denn deine eingabe genau? gibst du die sekundenzahl ein oder liest du aus ner tabelle o.ä.?

wenn ich das einmal mit ner vorgegebenen sekundenzahl von 12345678910 ausführe:

Python:

time python seconds.py

real    0m0.086s

user    0m0.025s

sys     0m0.007s

Bash:

time /home/scytheman/timecalc.sh 12345678910

real    0m0.009s

user    0m0.003s

sys     0m0.003s

awk hab ich nu nich ausprobiert, bash is aber schneller als die python varianteLast edited by ScytheMan on Tue Dec 02, 2008 3:26 pm; edited 1 time in total

----------

## 69719

 *l3u wrote:*   

> Und wie erklärst du dann, daß die Bash-Variante bei einem Test hier (zieht paar Zeilen aus einer Logdatei raus und macht 27 solche Berechnungen) eine knappe halbe Sekunde dauert, die awk-Variante aber eine ganze? Liegt das bloß daran, daß für die awk-Variante ein zusätzlicher Prozeß gestartet wird?
> 
> @ScytheMan: Läuft's schneller als die Bash-Variante, wenn's von einem Bash-Script aufgerufen wird? Wenn man's 100 mal oder so aufruft?

 

Um awk zu starten muss einiges in gang gesetzt werden, schließlich muss ja auch das filesystem awk erstmal finden, laden anschupsen... Da ist in jedem Fall mehr rechenaufwand nötig als wenn es die bash macht, die im übrigen zu dem Zeitpnunkt schon geladen ist.

----------

## l3u

Na dann fragen wir doch mal andersrum: ist das mit der Bash das Schnellste (TM), oder geht's noch schneller?

----------

## ScytheMan

geht sicherlich noch schneller mit kompiliertem code, bash interpretiert ja auch nur.

----------

## l3u

Naja, aber dafür müßt man halt wieder nen externen Prozeß starten, weil's ja von einem Bash-Script aus aufgerufen werden soll

----------

## 69719

Aber eventuell ist dies dann schneller, wenn der binärcode direkt darauf zugeschnitten ist und es eine masse an daten ist die berechnet werden soll.

----------

## toralf

perldoc -f localtime, also z.B.: 

```
tfoerste@n22 ~ $ SEC=$(date +%s) perl -we 'my ($s, $m, $h, $d) = (localtime '$SEC')[0,1,2,7]; print "$d $h:$m:$s\n"'

336 19:47:21

```

?

----------

## 69719

 *toralf wrote:*   

> perldoc -f localtime, also z.B.: 
> 
> ```
> tfoerste@n22 ~ $ SEC=$(date +%s) perl -we 'my ($s, $m, $h, $d) = (localtime '$SEC')[0,1,2,7]; print "$d $h:$m:$s\n"'
> 
> ...

 

Also 336 Tage ist ein bischen wenig seit 1970..., du hast was falsch verstanden. Außerdem will er keine Ausgabe wenn z.B. die Minute 0 ist.

Nachtag, hier mal was zum probieren ob es mittels zugeschnittenem Binary schneller geht.

```

#include <stdio.h>

#include <stdlib.h>

int main( int argc, char *argv[] ) {

   int d, h, m, s;

   int wrote = 0;

   if ( argc != 2 )

      return 1;

   else

      s = atoi( argv[ 1 ] );

   d = s / 86400;

   h = ( s / 3600 ) - ( d * 24 );

   m = ( s / 60 ) - ( d * 1440 ) - ( h * 60 );

   s %= 60;

   if ( d )

      wrote = printf( "%d day%c", d, d > 1 ? 's' : '\0' );

   if ( h )

      wrote = printf( "%s%d hour%c", wrote ? ", " : "", h, h > 1 ? 's' : '\0' );

   if ( m )

      wrote = printf( "%s%d minute%c", wrote ? ", " : "", m, m > 1 ? 's' : '\0' );

   if ( s )

      wrote = printf( "%s%d second%c", wrote ? ", " : "", s, s > 1 ? 's' : '\0' );

   return 0;

}

```

----------

## toralf

 *escor wrote:*   

> Also 336 Tage ist ein bischen wenig seit 1970..., du hast was falsch verstanden. 

 Nun gut

```
tfoerste@n22 ~ $ perl -e '$t = time; my ($s, $m, $h) = (localtime $t)[0,1,2]; $d = int $t / 86400; print "$d $h:$m:$s\n"'

14215 20:32:41

```

 *escor wrote:*   

> Außerdem will er keine Ausgabe wenn z.B. die Minute 0 ist.

 Das paßt nicht  mehr in eine (kurze) Zeile.

----------

## l3u

Langsamer als die Bash-Variante … 0,5 sec vs. 0,8 sec. – aber immerhin schneller als awk ;-)

----------

## toralf

 *l3u wrote:*   

> Langsamer als die Bash-Variante … 0,5 sec vs. 0,8 sec. – aber immerhin schneller als awk 

 Jo, wenn der Perl Interpreter jedesmal aufgerufen werden muß ..., besser wäre es natürlich, alle Integer-Werte als Stream an den Interpreter zu geben, also z.B.

```
tfoerste@n22 ~ $ echo -e "1234567890\n1234567891" | perl -ne 'my ($s, $m, $h) = (localtime $_)[0,1,2]; $d = int ($_ / 86400); print "$d $h:$m:$s\n"'

14288 0:31:30

14288 0:31:31

```

----------

## Knieper

Ich koennte noch eine C-Variante anbieten, statisch kompiliert keine 3k:

```

#include <buffer.h>

#include <stdbool.h>

#include <stdlib.h>

bool first = true;

void foo(unsigned long int t, const char *s) {

   if(t > 0) {

      if(first) { first = false;

      } else { buffer_puts(buffer_1,", "); }

      buffer_putulong(buffer_1,t);

      buffer_puts(buffer_1,s);

      if(t > 1) { buffer_puts(buffer_1,"s"); }

   }

}

int main(int argc, char *argv[]) { 

   unsigned long int r;

   if(argc != 2) { return 1; }

   r = abs(atoi(argv[1]));

   foo(r/86400," day"); r %= 86400;

   foo(r/3600," hour"); r %= 3600;

   foo(r/60," minute");

   foo(r%60," second");

   buffer_putnlflush(buffer_1);

   return 0; 

}

```

Test ueber 20 Werte (ohne Auslesen aus Datei) in einem Shell-Skript: 0.005s.

----------

## 69719

buffer.h und str.h kommen aber nicht ausm c, da werden wohl wieder spezielle biliotheken verwendet. Das es unter 3k im statisch gelinkten Modus sind bezweifel ich. Es werden mindestens um die ~500k sein. Eine einfache main optimiert auf size und stripped sind schon 5k.

----------

## Knieper

 *escor wrote:*   

> buffer.h und str.h kommen aber nicht ausm c, da werden wohl wieder spezielle biliotheken verwendet. Das es unter 3k im statisch gelinkten Modus sind bezweifel ich. Es werden mindestens um die ~500k sein. Eine einfache main optimiert auf size und stripped sind schon 5k.

 

http://www.fefe.de/libowfat/

http://www.fefe.de/dietlibc/

Und ja, es sind weniger als 3k. Aber str.h gehoert sowieso nicht mehr hinein...

----------

## 69719

Beim verwenden einer anderen libc sollte man dies wenigstens dazuschreiben und auch den compiler Aufruf, sonst bring der Code gar nicht.

----------

## Knieper

Libowfat kann man an den markanten Bezeichnern herausfinden und wer nimmt fuer solche Sachen schon eine der Standardlibc()en? Ausser -Wall -Os -pipe -fomit-frame-pointer und -lowfat -s war auch nichts weiter dabei und gcc hat "diet" aufgerufen...

----------

## 69719

Hättest du das auch in deinen Anfangszeiten der Programmierung gewußt? Ich denke nicht, daher  würde ich dies nicht als normal bezeichnen. Und wie weit sich l3u mit so etwas auskennt kann man auch nicht am Thread festmachen.

----------

