It depends...
If you want a nested loops with a correlated index seek and you have a suitable index on at least one of the tables with leading columns id,dt then converting into a range seek will be the ideal as in Charlie's answer.
If you want a hash join (perhaps you have no useful indexes) then
a.id = b.a_id and convert(date, a.dt) = convert(date, b.dt)
or
a.id = b.a_id and DATETRUNC(day, b.dt) = DATETRUNC(day, a.dt)
Does at least give you an equality predicate on both conditions meaning that both can be used in the hash key.
DATETRUNC is more able to take advantage of the fact that an index ordered by datetime is also ordered by date and would also allow a merge join with a predicate on id, DATETRUNC(day, dt) without any sort operators if both tables have an index on id, dt - though this will be a "many to many" type with a worktable.
StmtText
|--Merge Join(Inner Join, MANY-TO-MANY MERGE:([a].[id], [Expr1003])=([b].[a_id], [Expr1002]), RESIDUAL:([dbo].[table1].[id] as [a].[id]=[dbo].[table2].[a_id] as [b].[a_id] AND [Expr1002]=[Expr1003]))
|--Compute Scalar(DEFINE:([Expr1003]=datetrunc(day,[dbo].[table1].[dt] as [a].[dt])))
| |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]), ORDERED FORWARD)
|--Compute Scalar(DEFINE:([Expr1002]=datetrunc(day,[dbo].[table2].[dt] as [b].[dt])))
|--Clustered Index Scan(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), ORDERED FORWARD)
The convert(date, a.dt) option would also support an indexed lookup with nested loops and an equality on id and range seek on dt though not as efficiently as constructing the range yourself would as the dynamic seek reads an additional day.
|--Nested Loops(Inner Join, OUTER REFERENCES:([a].[id], [Expr1002]))
|--Compute Scalar(DEFINE:([Expr1002]=CONVERT(date,[dbo].[table1].[dt] as [a].[dt],0)))
| |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]))
|--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1005], [Expr1006], [Expr1004]))
|--Compute Scalar(DEFINE:(([Expr1005],[Expr1006],[Expr1004])=GetRangeThroughConvert([Expr1002],[Expr1002],(62))))
| |--Constant Scan
|--Clustered Index Seek(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), SEEK:([b].[a_id]=[dbo].[table1].[id] as [a].[id] AND [b].[dt] > [Expr1005] AND [b].[dt] < [Expr1006]), WHERE:([Expr1002]=CONVERT(date,[dbo].[table2].[dt] as [b].[dt],0)) ORDERED FORWARD)
The dynamic seek logic does not extend to DATETRUNC so the best that one can do with a nested loops is an equality on the id part and residual on the date.
|--Nested Loops(Inner Join, OUTER REFERENCES:([a].[id], [Expr1003]))
|--Compute Scalar(DEFINE:([Expr1003]=datetrunc(day,[dbo].[table1].[dt] as [a].[dt])))
| |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]))
|--Clustered Index Seek(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), SEEK:([b].[a_id]=[dbo].[table1].[id] as [a].[id]), WHERE:(datetrunc(day,[dbo].[table2].[dt] as [b].[dt])=[Expr1003]) ORDERED FORWARD)