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:
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/Q70Ig.png)
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.
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/tGtqp.png)
Then the inner faces can be deleted to make the holes, and the whole object given Solidify, Bevel (by angle) and Subdivision Surface modifiers..
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/eqHPi.png)
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.
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/VcFix.png)