Matlab: Как сравнивать даты (YMD), игнорируя время (HMS)?

#matlab #datetime #comparison

Вопрос:

Для двух массивов (разной длины) со значениями datetime я хочу отметить те записи, в которых дата (год, месяц, день) в обоих одинакова, игнорируя значения времени. Проблема в том, что datetime тип внутренне всегда также содержит время (даже конструктор datetime(Y,M,D) внутренне установит время 00:00:00). Поэтому прямое сравнение времени () даст результат только в том случае, если время также совпадает. dt1 == dt2 true

Напр.:

 arDt1 = datetime(2021,5,1:10,0,0,0);     % 1. to 10. May, always at time 00:00:00
arDt2 = datetime(2021,5,1:2:10,12,0,0);  % 1.,3.,5.,7.,9. May always at time 12:00:00
 

Таким образом, желаемым логическим массивом флагов для arDt1 будет

 [ 1 0 1 0 1 0 1 0 1 0]  % days in arDt1 which are also in arDt2, *never mind the time* 
 

Реальные данные охватывают несколько месяцев и лет, поэтому одного только числа дней месяца недостаточно (даже если бы это было в приведенном выше примере).

Я могу придумать различные обходные пути (преобразования datetime в строку и синтаксический анализ, используя ymd() и затем сравните год, месяц, день «кусочно», или вынудив всех времен, по крайней мере временно, чтобы быть таким же, например, 00:00:00), но все это становится немного неуклюжей, ЭСП. когда задействованы массивы разной длины, это означает ismember() , что их следует использовать вместо прямого сравнения массивов один к одному.

Проблема обработки только части datetime значений даты, независимо от части времени, должна быть довольно общей, но я не могу найти никаких примеров или ссылок. Может ли кто-нибудь посоветовать более элегантный/эффективный способ?

Комментарии:

1. Можете ли вы просто не конвертировать в datenum то floor и использовать ismember ? ismember(floor(datenum(arDt1)), floor(datenum(arDt2)))

2. Да, действительно, спасибо! — Я знал , что должно быть что-то простое. 🙂 И я уже проверил datenum , надеясь на «целыми днями только» (доктор говорит, что он «представляет каждый момент времени, так как количество дней в январе 0, 0000.»), но потом обнаружил, что она также содержит доли день, поэтому (преждевременно) разочаровался в ней, не думая о пол(). Кроме того, я думал datenum , что в любом случае больше не рекомендуется (док говорит, что «лучший способ представления точек во времени-это использование datetime типа данных»). Но для этой конкретной цели это,конечно, правильно.

Ответ №1:

Вы можете использовать функцию СДВИГА дат, чтобы переместить все даты в начало дня, а затем выполнить сравнение.

 ismember(dateshift(arDt1,'start','day'),dateshift(arDt2,'start','day'))
ans =

  1×10 logical array

   1   0   1   0   1   0   1   0   1   0
 

Комментарии:

1. Спасибо. До сих пор совершенно не замечал этого.

Ответ №2:

Альтернативным решением было бы использовать свойства datetime напрямую. Это означает сравнение свойств года, месяца и дня. Я предпочитаю этот подход, так как он позволяет мне, например, также фильтровать данные за данный месяц (пренебрегая днем).

 arDt1 = datetime(2021,5,1:10,0,0,0);     % 1. to 10. May, always at time 00:00:00
arDt2 = datetime(2021,5,1:2:10,12,0,0);  % 1.,3.,5.,7.,9. May always at time 12:00:00

arDtYMD1 = [arDt1.Year', arDt1.Month', arDt1.Day'];     % 10x3 double
arDtYMD2 = [arDt2.Year', arDt2.Month', arDt2.Day'];     % 5x3 double
all(ismember(arDtYMD1, arDtYMD2),2)                     % 10x1 logical array
 

Комментарии:

1. Спасибо. Это будет очень полезно и в других контекстах.