/**
  *
  */
 public function testGenerate()
 {
     $now = time();
     $fromTs = $now - 90 * 3600 * rand(10, 20);
     $toTs = $now;
     $dayGenerator = CalendarDayGenerator::generate($fromTs, $toTs);
     $days = [];
     foreach ($dayGenerator as $day) {
         $days[] = $day;
     }
     $diff = (new \DateTime(date('Y-m-d', $fromTs)))->diff(new \DateTime(date('Y-m-d', $toTs)));
     $expectedDays = $diff->days + 1;
     $this->assertEquals($expectedDays, count($days));
 }
}
$toDate = date_create_from_format('Ymd', $toDay);
if (!$toDate instanceof \DateTime) {
    appendLog(sprintf('to [%s] not valid', $toDay));
    return;
}
$pdoPool = PdoFactory::makePool($gameVersion);
$installUidProvider = new InstallUidProvider($gameVersion, $pdoPool);
$userDetailProvider = new UserDetailProvider($gameVersion, $pdoPool);
$magicNumber = isset($options['magic']) ? (int) $options['magic'] : 500;
assert($magicNumber > 10);
$indexer = IndexerFactory::make(ELASTIC_SEARCH_HOST, $gameVersion, $magicNumber);
if ($verbose) {
    dump(sprintf('version: %s, from: %s, to: %s, safe: %d, magic: %d', $gameVersion, $fromDay, $toDay, $safeRound, $magicNumber));
}
$calendarDayGenerator = CalendarDayGenerator::generate($fromDate->getTimestamp(), $toDate->getTimestamp());
$totalUser = 0;
$processedRound = 0;
foreach ($calendarDayGenerator as $calendarDay) {
    $markerDate = new DateTimeImmutable($calendarDay);
    if ($calendarMarker->isMarked($markerDate)) {
        appendLog('bypass ' . $markerDate->format('Y-m-d'));
        continue;
    }
    $msg = basename(__FILE__) . ': process for ' . $calendarDay . ' run with ts ' . date('c');
    appendLog($msg);
    $groupedUidList = $installUidProvider->generate($calendarDay, function ($shardId, $userCount, $delta) {
        if ($userCount === 0) {
            return;
        }
        appendLog(sprintf('%s install(%d) cost %s', $shardId, $userCount, PHP_Timer::secondsToTimeString($delta)));