Eric Brine wrote: >The binary search found: ... >2013-11-03T03:45:00 UTC >2013-11-03T04:07:30 UTC
You should only examine integral minutes. Truncate to the minute when bisecting, before you pass your bisected time to DateTime. Or, to avoid fractions entirely, extend the search radius to 2048 minutes. Either way, do not burden DateTime with any arithmetical job. Here's an implementation of what I mean: sub start_of_day { my($tgt_date_str, $zone) = @_; $tgt_date_str =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})\z/ or die; my $tgt_date_ut = DateTime->new(year => "$1", month => "$2", day => "$3", time_zone => "UTC"); my($tgt_date_epoch_min) = $tgt_date_ut->epoch / 60; my($tgt_date_rd) = $tgt_date_ut->utc_rd_values; my $left_epoch_min = $tgt_date_epoch_min - 1440; my $right_epoch_min = $tgt_date_epoch_min + 1440; while(($right_epoch_min - $left_epoch_min) > 1) { my $try_epoch_min = ($left_epoch_min + $right_epoch_min) >> 1; my $try_dt = DateTime->from_epoch(epoch => $try_epoch_min*60, time_zone => $zone); (($try_dt->local_rd_values)[0] >= $tgt_date_rd ? $right_epoch_min : $left_epoch_min) = $try_epoch_min; } return DateTime->from_epoch(epoch => $right_epoch_min*60); } Use as in: @ARGV == 2 or die; my($tgt_date_str, $zone_name) = @ARGV; my $zone = DateTime::TimeZone->new(name => $zone_name); print start_of_day($tgt_date_str, $zone), "Z\n"; -zefram