| 
						 | 
						- <?php
 - namespace App\Http\Controllers;
 - 
 - use Laravel\Lumen\Routing\Controller as BaseController;
 - use Illuminate\Http\Request;
 - use DB, Log;
 - use Quartz;
 - use DateTime, DateTimeZone, DateInterval;
 - use App\Jobs\TripComplete;
 - 
 - class LocalTime extends BaseController
 - {
 - 
 -   public function find(Request $request) {
 -     $token = $request->input('token');
 -     if(!$token)
 -       return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json');
 - 
 -     $db = DB::table('databases')->where('read_token','=',$token)->first();
 -     if(!$db)
 -       return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json');
 - 
 -     $qz = new Quartz\DB(env('STORAGE_DIR').$db->name, 'r');
 - 
 -     $timezones = [
 -       '-23:00','-22:00','-21:00','-20:00',
 -       '-19:00','-18:00','-17:00','-16:00','-15:00','-14:00','-13:00','-12:00','-11:00','-10:00',
 -       '-09:00','-08:00','-07:00','-06:00','-05:00','-04:00','-03:00','-02:00','-01:00','+00:00',
 -       '+01:00','+02:00','+03:00','+04:00','+05:00','+06:00','+07:00','+08:00','+09:00','+10:00',
 -       '+11:00','+12:00','+13:00','+14:00','+15:00','+16:00','+17:00','+18:00','+19:00','+20:00',
 -       '+21:00','+22:00','+23:00',
 -     ];
 -     
 -     $date = false;
 -     if($input=$request->input('input')) {
 -       // Strict input format
 -       if(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/', $input)) {
 -         $date = $input;
 -       } else {
 -         // Invalid format
 -       }
 -     }
 -     if(!$date) {
 -       return response(json_encode(['error' => 'invalid date provided']))->header('Content-Type', 'application/json');
 -     }
 - 
 -     $candidates = [];
 -     
 -     foreach($timezones as $tz) {
 -       // Interpret the input date in each timezone
 -       $date = DateTime::createFromFormat('Y-m-d H:i:s', $input, new DateTimeZone($tz));
 - 
 -       // Find the closest record to that absolute timestamp
 -       if($record = $this->_find_closest_record($qz, $date)) {
 -         if($record->data) {
 -           $local = $this->_timezone_for_location($record->data->geometry->coordinates[1], $record->data->geometry->coordinates[0], $record->date->format('c'));
 -           
 -           $diff = strtotime($local->localtime) - strtotime($date->format('c'));
 -   
 -           // Find the record where the localized timezone offset matches the candidate offset
 -           if($tz == $local->date->format('P')) {
 -             $candidates[] = [
 -               'record' => $record->data,
 -               'local' => $local,
 -               'tz' => $tz,
 -               'diff' => $diff
 -             ];
 -           }
 -         }
 -       }
 -     }
 -     
 -     // Choose the candidate with the smallest absolute time difference
 -     usort($candidates, function($a, $b){ 
 -       return abs($a['diff']) < abs($b['diff']) ? -1 : 1;
 -     });
 - 
 -     if(count($candidates)) {
 -       $record = $candidates[0];
 -       
 -       $response = [
 -         'data' => $record['record'],
 -         'timezone' => [
 -           'offset' => $record['local']->offset,
 -           'seconds' => $record['local']->seconds,
 -           'localtime' => $record['local']->localtime,
 -           'name' => $record['local']->name,
 -         ]
 -       ];
 -     } else {
 -       $response = ['data'=>null];
 -     }
 -     
 -     return response(json_encode($response))->header('Content-Type', 'application/json');
 -   }
 -   
 -   private function _timezone_for_location($lat, $lng, $date) {
 -     $tz = \p3k\Timezone::timezone_for_location($lat, $lng, $date);
 -     return new TimezoneResult($tz, $date);
 -   }
 -   
 -   private function _find_closest_record($qz, $date) {
 -     // TODO: move this logic into QuartzDB
 -     
 -     // Load the shard for the given date
 -     $shard = $qz->shardForDate($date);
 -     // If the shard doesn't exist, check one day before
 -     if(!$shard->exists()) {
 -       $date = $date->sub(new DateInterval('PT86400S'));
 -       $shard = $qz->shardForDate($date);
 -     }
 -     // Now if the shard doesn't exist, return an empty result
 -     if(!$shard->exists()) {
 -       return false;
 -     }
 - 
 -     // Start iterating through the shard and look for the last line that is before the given date
 -     $shard->init();
 -     $record = false;
 -     foreach($shard as $r) {
 -       if($r && $r->date > $date)
 -         break;
 -       $record = $r;
 -     }
 -     return $record;
 -   }
 - 
 - }
 - 
 - class TimezoneResult {
 -   public $timezone = null;
 - 
 -   private $_now;
 -   private $_name;
 - 
 -   public function __construct($timezone, $date=false) {
 -     if($date)
 -       $this->_now = new DateTime($date);
 -     else
 -       $this->_now = new DateTime();
 -     $this->_now->setTimeZone(new DateTimeZone($timezone));
 -     $this->_name = $timezone;
 -   }
 - 
 -   public function __get($key) {
 -     switch($key) {
 -       case 'date':
 -         return $this->_now;
 -       case 'offset': 
 -         return $this->_now->format('P');
 -       case 'seconds':
 -         return (int)$this->_now->format('Z');
 -       case 'localtime':
 -         return $this->_now->format('c');
 -       case 'name':
 -         return $this->_name;
 -     }
 -   }
 - 
 -   public function __toString() {
 -     return $this->_name;
 -   }
 - }
 - 
 
 
  |