W poprzednim poście poruszyłem ogólnie temat datetime w MATLABie zwracając Waszą uwagę na wygodę posługiwania się tym typem danych. Pokazałem Wam jak importować poprawnie dane opisujące czas z zewnętrznych plików. Dzisiaj czas na kilka konkretnych przykładów.
Generowanie daty i konwersja między różnymi typami danych
Nawiązując jeszcze do pracy z danymi, które są importowane do MATLABa z zewnętrznego programu, często zdarza się tak, że każdy element opisujący datę, to jest dni, miesiące, lata, godziny, itd., jest zapisany jako osobna zmienna w postaci liczby (typ numeryczny). Może być też tak, że data jest zapisana jako zwykły tekst. Miałem do czynienia z taką sytuacją, wiele razy, kiedy system pomiarowy zapisywał datę właśnie w taki sposób. Jak sobie z tym poradzić?
Załóżmy, że data jest opisana przez wektory typu kolumnowego. Rok to jeden wektor, miesiąc to inny wektor i tak dalej. Poniżej jest program, który scala te pojedyncze wektory w jedną zmienną typu datetime:
clear all; close all; clc % Mamy osobne wektory kolumnowe opisujące rok, miesiąc, itd. % Odpowiadające sobie elementy wektorów tworzą pojedynczą % datę/chwilę czasu. rok = [2021; 2021; 2021; 2021]; miesiac = [11; 11; 11; 11]; dzien = [1; 2; 3; 4]; godzina = [9; 17; 16; 23]; minuty = [44; 2; 12; 0]; sekundy = [1; 58; 57; 43]; % Użycie funkcji datetime: data1 = datetime(rok, miesiac, dzien, godzina, minuty, sekundy) % Jeżeli mamy jedną macierz zawierającą kilka kolumn, % postępujemy podobnie: data_macierz = [rok, miesiac, dzien, godzina, minuty, sekundy]; data2 = datetime(data_macierz) % Oba przekształcenia dadzą ten sam wynik.
Należy pamiętać, że typ datetime, a tym samym funkcja o tej samej nazwie wymaga podania co najmniej trzech elementów daty: roku, miesiąca i dnia lub godziny, minuty i sekundy. Oczywiście można podać wszystkie te sześć argumentów naraz. Nie da się natomiast utworzyć zmiennej datetime podając na przykład jedynie rok lub miesiąc i dzień.
Dysponując ciągiem dat w typie MATLABowskim datetime, możemy łatwo wykonywać podstawowe operacje, choćby takie o jakich była mowa w poprzednim poście, więc tutaj nie będę już o nich wspominał.
Natomiast jeżeli chcemy zmienić format daty z yyyy-MM-dd HH:mm:ss na inny, na przykład dd-MM-yyyy to wystarczy:
dd HH:mm:ss na inny, na przykład dd-MM-yyyy to wystarczy:
% Jeżeli chcemy zmienić format daty z yyyy-MM-dd na dd-MM-yyyy, % wystarczy: data3 = datetime(data2,'Format','dd-MM-yyyy') % jeśli interesuje nas opis słowny: data4 = datetime(data2,'Format','eeee, MMMM d, y')
Pominięcie godziny w formacie nie oznacza, że informacja ta zostaje utracona w nowej zmiennej. Możemy powrócić do pierwotnego zapisu formatu:
data4 = datetime(data4,'Format','yyyy-MM-dd HH:mm:ss')
Oznacza to, że zmienna datetime, zawsze przechowuje pełną (źródłową) informację o dacie/godzinie. Argument Format określa tylko jak te informacje będą wyświetlane w MATLABie.
Dostęp do poszczególnych elementów danej daty można uzyskać na kilka sposobów. Dokumentacja MATLABa sugeruje użycie funkcji year, month i innych. Ja jednak wolę zastosować indeksowanie z kropką w połączeniu z tradycyjnym wskazaniem wiersza, o który chodzi. Najlepiej wyjaśni to przykład:
% Aby ten program zadziałał, wcześniej musi być uruchomiony program % poprzedni z posta. % cała kolumna określająca dzień/dni: dni = data1.Day % dzień z konkretnego wiersza: wybrany_dzienA = data1.Day(2) % ten sam efekt uzyskamy poprzez: wybrany_dzienB = day(data1(2))
Jeżeli chcemy wykonać operację polegającą na konwersji zmiennej typu datetime na dane numeryczne, to można to zrobić na kilka sposobów.
Jeżeli chcemy zbiorczo odczytać datę lub czas i każdy element zapisać do osobnej zmiennej to można użyć funkcji ymd lub hms:
% Jeżeli chcemy zbiorczo odczytać datę lub czas i każdy element % zapisać do osobnej zmiennej to można użyć funkcji ymd lub hms: [rok2, miesiac2, dzien2] = ymd(data1) [godzina2, minuty2, sekundy2] = hms(data1)
Jeżeli chcemy odczytać tylko jeden element daty/czasu, to można użyć predefiniowanych funkcji i również zapisać dane do osobnych zmiennych:
% Jeżeli chcemy odczytać tylko jeden element daty/czasu, to można użyć % predefiniowanych funkcji i również zapisać dane do osobnych zmiennych: rok3 = year(data1) miesiac3 = month(data1) dzien3 = day(data1) godzina3 = hour(data1) minuty3 = minute(data1) sekundy3 = second(data1)
Jeżeli chcemy natomiast przekonwertować zmienną zawierającą daty/czas w formacie datetime na jedną macierz numeryczną należy użyć funkcji datevec:
% Jeżeli chcemy natomiast przekonwertować macież zawierającą daty/czas % w formacie datetime na jedną macierz numeryczną należy użyć % funkcji datevec: macierz_daty = datevec(data1)
W ten sposób otrzymaliśmy jedną zmienną – macierz o sześciu kolumnach, które odpowiadają kolejnym elementom daty/czasu. Załóżmy teraz, że z tej macierzy chcemy wyekstrahować konkretne kolumny i zapisać je do zmiennych/wektorów, każdy o innej nazwie. W ten sposób otrzymamy wektory analogiczne, jak te wygenerowane w programie pierwszym. Proces jest więc w pełni odwracalny, choć użycie funkcji eval wymaga nieco gimnastyki.
% Jeżeli z jakiegoś powodu z takiej "dużej" macierzy chcielibyśmy wyekstrahować % poszczególne elementy daty (jak w przykładzie powyżej) to trzeba się trochę % nagimnastykować: nazwy = ["rok4"; "miesiac4"; "dzien4"; "godzina4"; "minuty4"; "sekundy4"] % i użyć funkcji eval, do wykonania komendy z nawiasu kwadratowego: for k = 1:size(nazwy,1) eval([char(nazwy(k)) '= macierz_daty(:,' num2str(k) ')']) end
Oczywiście to samo można uzyskać wprost za pomocą wspomnianych powyżej funkcji ymd i hms, ale tylko w przypadku gdy dysponujemy oryginalną zmienną typu datetime. Jeżeli mamy macierz numeryczną, to wyodrębnienie poszczególnych kolumn do zmiennych o różnych nazwach wykonujemy w pętli z użyciem funkcji eval.
Obliczanie przedziału czasu
Druga grupa funkcji dotycząca typu datetime dotyczy obliczania przedziału czasu. Jak pokazałem to w poprzednim poście, można to zrobić posługując się operatorem arytmetycznym „minus” lub funkcją diff:
t1 = datetime(2021,06:09,1) % Domyślnie różnica jest wyrażana w godzinach: roznica1 = diff(t1) % ale możmy ja przeliczyć na lata, miesiące, dni, minuty, sekundy: years(roznica1) days(roznica1) minutes(roznica1) seconds(roznica1)
Zwróćcie uwagę: do obliczania przedziału czasu używamy funkcji z końcówką „s”: years … days, w odróżnieniu od year … day, używanych wcześniej do konwersji daty na typ numeryczny.
Aby policzyć ile czasu upłynęło od konkretnych dat do dnia dzisiejszego należy natomiast:
t2 = datetime('now') roznica2 = t2 - t1 days(roznica2)
Temat uważam za wyczerpany, a więcej informacji znajdziecie w dokumentacji. Powodzenia!