0

For two arrays (of different length) with datetime values, I want to flag those entries where the date (year, month, day) in both is the same while ignoring the time values. The issue is that the datetime type internally always also contains a time (even the constructor datetime(Y,M,D) will internally set the time to 00:00:00). Therefore a direct comparison of datetimes (dt1 == dt2) will give true only if the times are also the same.

E.g.:

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

The desired logical array of flags for arDt1 would thus be

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

The real data extend across multiple months and years, so using the day-of-month number alone is not sufficient (even if it would be for the example above).

I can think of various work-arounds (converting datetime to string and parsing; using ymd() and then compare year, month, day "piecewise"; or forcing all times, at least temporarily, to be the same, e.g. 00:00:00), but it all gets a bit clumsy, esp. when arrays of different lengths are involved, which means ismember() has to be used instead of a direct one-to-one array comparison.

The problem of of processing only the date part of datetime values, regardless of the time part, should be a rather general one, but I can't find any examples or references. Can someone advise a more elegant/efficient way?

clüles
  • 27
  • 4
  • Can you not just convert to a `datenum` then `floor` and use `ismember`? `ismember(floor(datenum(arDt1)), floor(datenum(arDt2)))` – user12339314 Jul 06 '21 at 14:37
  • Yes indeed, thanks! -- I _knew_ there must be something simple. :-) And I _had_ checked `datenum`, hoping for "whole days only" (the doc says it "represents each point in time as the number of days from January 0, 0000."), but then discovering that it also contains fractions of a day, so (prematurely) gave up on it, not thinking of floor(). Besides, I thought `datenum` is no longer recommended anyway (doc says that "the best way to represent points in time is by using the `datetime` data type"). But for this specific purpose it is just right,of course. – clüles Jul 07 '21 at 07:51

2 Answers2

1

You can use the DATESHIFT function to move all of the dates to the start of the day and then do the comparison.

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

  1×10 logical array

   1   0   1   0   1   0   1   0   1   0
Rob
  • 11
  • 1
1

Alternative solution would be to use the properties of datetime directly. Meaning comparing the year, month and day properties. I prefere this approch since it allows me for example also to filter for a given month (neglecting the day).

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
cuda12
  • 460
  • 3
  • 10