Can you do by just subtracting 144 from the block height per day you're looking?
This is wrong approach. Current all-time average block time is somewhere about 9.55 minutes.
If not, I'd still recommend doing that and then looking up the api for a block explorer (like blockchain.com) and trying to programmatically go back (or forward) from there based on how many blocks would have come since. I remember blockchain.com's api indexing blocks based on height and hash (not sure how others do it but it's probably an easy enough place to start and get a json of data, and then checking the time the block was received or generated).
Unfortunately blockchain.com API doesn't have filter to choose block based on date.
Here is another fun way of doing it which is a lot faster and cheaper to do:
If you run a SPV client like Electrum on your computer you already have all the block headers saved up in a ~60 MB file called "blockchain_headers" which is a stream of bytes. All you have to do is to programatically read this file to get the raw bytes which should be a multiple of 80. Each 80 byte is a block header of a block in chronological order (so you have the block height this way too). Then start from the beginning (byte 0) and extract the time from each 80 byte chunk (ie. one header) knowing that 4th item in it is the timestamp.
version[4] + prev_hash[32] + merkle_root[32] + time[4] + target[4] + nonce[4]
Here is a pseudocode
stream = File.Read("blockchain_headers")
while(stream.HasBytesLeft)
stream.Skip(68)
timestamp = stream.Read(4).ConvertToTime_LittleEndian()
resultList.Add(timestamp)
stream.Skip(8)
Now all you have to do is search in the list of timestamps to see when the day in the datetime you converted changes to get the last height of the day. The height is the index of the datetime inside the resultList/array.
Keep in mind that timestamps are in UTC not your local time.
Do you mind checking beginning of file
blockchain_headers with hex editor/viewer? I tried on my device, but mostly it only contain zeroes. I suspect Electrum only request needed block header rather than all block header.