I don't know if this method will appeal to your precision requirement, but believe that, with care, the accuracy will be as good as that achieved by a boolean, especially if you take into account the topological anomalies that a boolean could introduce.
A (Edge Menu) subdivided fan-filled 6-sided circle automatically gives you a hexagonal grid. It is at this stage you can set the hole-intervals:
You can use the shipped add-on Loop Tools > Circle to make the perimeter circular, and set its radius. At this stage, you could select the whole face-region, and inset it slightly, to protect the perimeter.
All the other vertices can be CtrlShiftB bevelled to a small radius, so the resulting faces are easy to select (ShiftG) by area. They are circular for the most part, but just to be sure, we can use Loop Tools > Circle again on all the selected faces, and set their radius there. Now they can be given a border by using I (Inset) set to Outset.
Then the inner faces can be deleted to make the holes, and the whole object given Solidify, Bevel (by angle) and Subdivision Surface modifiers..
If you wanted more precision than that, you could measure the relative diameters of a hexagon in a similar grid with, and without, 2 levels of Catmull-Clark subdivision, in a larger-scale trial, and compensate accordingly when setting the diameter of the holes with Loop Tools.