Przeliczanie sekund do dowolnego formatu

|
Robert
| komentarze | JavaScript

Potrzeba matką wynalazków mawiają, a tak się złożyło, że potrzebowałem funkcji która przeliczy mi czas podany w sekundach na dowolny format, na przykład H:M:S. Na StackOverflow nic ciekawego co by mnie satysfakcjonowało, więc postanowiłem się za to zabrać samodzielnie. Wpis krótki lecz treściwy.

Jednym z głównym z założeń jest spełnieniem zasady Open/Close którą, wydaje się, udało mi się spełnić. Wejściem funkcji jest oczywiście czas podany w sekundach (choć mogą to być dowolne jednostki, funkcja wydaje się być uniwersalna i elastyczna) oraz drugi parametr jakim są jednostki, a dokładniej ich wielkość względem poprzedniej. Na przykład tablica [60,60,24,7] która reprezentuje minuty, godziny, dobę(dzień) oraz tydzień.

function(time, units = [60,60,24,7]) {}

W tym miejscu zasada OC zostaje spełniona. Następnie wprowadzamy pomocniczą zmienną r która będzie przechowywała nam tablicę z obliczeniami oraz d która będzie przechowywała resztę z dzielenia. Jednostki (units) traktujemy pętlą for in.

let r = [], d;
for (let i in units) {}

Kolejnym krokiem są obliczenia czyli danie główne funkcji. Obliczamy resztę z jednostki, tak, że jeśli na wejściu będziemy mieli 72 sekundy to w pierwszym przebiegu pętli wiadomym jest, że to minuta i 12 sekund. Różnicę umieszczamy w zmiennej r, następnie czas dzielimy przez jednostkę zaokrąglając w dół.

d = time % units[i];
r.push(d);
time = Math.floor(time / units[i]);

Pojawią się przypadki kiedy na przykład funkcja zostanie potraktowana przykładem 180 sekund, wówczas to są 3 minuty, lecz funkcja zwróci 0. Nie chcemy też, aby pętla liczyła do samego końca tablicy jednostek, kiedy nie ma w zasadzie już co liczyć (doby, kiedy czas zamknął się w mniej niż 24 godzin). Wstawimy sobie następującą instrukcję warunkową if tuż po obliczeniu różnicy d:

if (d <= 0 && time == 0 && r.length > 1) break;

Dobrze, pora na zwrot akcji (plot twist hehe). Zwracamy wynik:

return r.reverse().join(':');

Co tu się stało? Odwracamy tablicę r ponieważ pętla zaczyna od sekund, następnie łączymy ją dwukropkiem. Możemy również rozbudować funkcję o kolejny parametr delimiter. Gotowa funkcja prezentuje się następująco:

function(time, units = [60,60,24,7], delimiter = ':') {

    let r = [], d;

    for (let i in units) {
      d = time % units[i];
      if (d <= 0 && time == 0 && r.length > 1) break;
      r.push(d);
      time = Math.floor(time / units[i]);
    }

    return r.reverse().join(delimiter);
  };

TL;DR: Funkcja po podaniu czasu w sekundach (132) zwróci nam domyślnie wynik w formacie W:H:M:S (2:12). Może pojawić się sytuacja, kiedy w wyniku ilość sekund będzie wyłącznie jednością, wówczas dla estetyki dopisałem funkcję pomocniczą:

function(cv,j) {
    return j > 0 && cv.toString().length == 1 ? '0'+cv : cv;
};

Aby skorzystać z funkcjonalności wynik z funkcji głównej należy potraktować metodą split(), map() stosując powyższą funkcję, a następnie join(). Dla przykładu całość:

function convert (time, units = [60,60,24,7], delimiter = ':') {

  let r = [], d;

  for (let i in units) {
    d = time % units[i];
    if (d <= 0 && time == 0 && r.length > 1) break;
    r.push(d);
    time = Math.floor(time / units[i]);
  }

  return r.reverse().join(delimiter);
};

function beforeZero (cv,j) {
  return j > 0 && cv.toString().length == 1 ? '0'+cv : cv;
};

let = convert(182).split(':').map(beforeZero).join(':');

Proste i przyjemne.