├── .gitignore ├── config.example.php ├── LICENSE ├── README.md └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | config.php 3 | -------------------------------------------------------------------------------- /config.example.php: -------------------------------------------------------------------------------- 1 | 59.4388618469, 5 | 'default_longitude' => 24.7544727325, 6 | 7 | 'google_timezone_api_key' => 'get-your-own-at:', // https://developers.google.com/maps/documentation/timezone/ 8 | ); 9 | // -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Allan Laal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sunrise 2 | Display sunset and sunrise times as all day events from an iCalendar feed in Google Calendar, your phone or elsewhere. 3 | 4 | ## usage 5 | 6 | Example calendar URL: 7 | 8 | http://sun.is.permanent.ee/?latitude=59.4388618469&longitude=24.7544727325&title=sunrise,sunset,length_civil&label_length_civil=☼&label_sunrise=↑&label_sunset=↓&start=-100&end=365&filename=sunrise.ics 9 | 10 | Modify the parameters in the URL according to your needs. You will atleast need to modify latitude and longitude. 11 | 12 | Add the above url into your Google Calendar at Other Calendars -> down arrow box thingie -> Add by URL 13 | 14 | ### latitude 15 | The latitude of your location, in degrees. 16 | 17 | latitude=59.4388618469 18 | 19 | ### longitude 20 | The longitude of your location, in degrees. 21 | 22 | longitude=24.7544727325 23 | 24 | ### title 25 | This sets what the calendar events title will be. You can use any of the below variables in any order: 26 | 27 | variable | description 28 | :--------------- | :--------- 29 | astronomical_twilight_begin | Start of astronomical twilight 30 | nautical_twilight_begin | Start of nautical twilight 31 | civil_twilight_begin | Start of civil twilight 32 | sunrise | Sunrise 33 | transit | Noon 34 | sunset | Sunset 35 | civil_twilight_end | End of civil twilight 36 | nautical_twilight_end | End of nautical twilight 37 | astronomical_twilight_end | End of astronomical twilight 38 | length | Day length from Sunrise until Sunset 39 | length_civil | Day length for civil twilight 40 | length_nautical | Day length for nautical twilight 41 | length_astronomical | Day length for astronomical twilight 42 | 43 | title=sunrise,sunset,length,length_civil 44 | 45 | ### labels 46 | Normally the values of the variables in the calendar event titles are not prefixed with any text to conserve space, but you can change that by adding an URL parameter with the variable name prefixed with 'label_'. 47 | 48 | label_astronomical_twilight_end=End%20of%20twilight 49 | 50 | ### start 51 | What day to start the calendar on from today. 52 | 53 | start=-100 54 | 55 | ### end 56 | What day to end the calendar on from today. 57 | 58 | end=365 59 | 60 | ### filename 61 | This is the filename of the file offered for download when you access the calendar URL directly. This needs to be the last URL parameter, because otherwise Google Calendar will not read anything from this URL and will silently fail. 62 | 63 | filename=sunrise.ics -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 6 | * @example http://sun.is.permanent.ee/?latitude=59.4388618469&longitude=24.7544727325&title=sunrise,sunset,length&label_sunrise=↑&label_sunset=↓&start=-100&end=365 7 | * @link https://github.com/allanlaal/sunrise-calendar-feed 8 | */ 9 | $version = '20150410T000000Z'; // modify this when you make changes in the code! 10 | 11 | // include config: 12 | require_once('./config.php'); 13 | 14 | // get and set timezone: 15 | $latitude = param('latitude', $config['default_latitude']); 16 | $longitude = param('longitude', $config['default_longitude']); 17 | 18 | // get and set timezone by latitude and longitude 19 | $url = "https://maps.googleapis.com/maps/api/timezone/json?location=$latitude,$longitude×tamp=".time()."&key=".$config['google_timezone_api_key']; 20 | $json = file_get_contents($url); 21 | $timezone = json_decode($json); 22 | 23 | if ($timezone->status != 'OK') 24 | { 25 | die("ERROR! Cannot detect a timezone\n"); 26 | } 27 | // else: 28 | 29 | date_default_timezone_set($timezone->timeZoneId); 30 | 31 | 32 | // buffer output so if anything fails, it wont display a partial calendar 33 | $out = "BEGIN:VCALENDAR\r\n"; 34 | $out .= "PRODID:-//Permanent Solutions Ltd//Sunrise Sunset Calendar//EN\r\n"; 35 | $out .= "VERSION:5.1.4\r\n"; 36 | $out .= "CALSCALE:GREGORIAN\r\n"; 37 | $out .= "METHOD:PUBLISH\r\n"; 38 | $out .= "X-WR-TIMEZONE:".$timezone->timeZoneId."\r\n"; 39 | $out .= "URL:https://github.com/allanlaal/sunrise-calendar-feed\r\n"; 40 | $out .= "X-WR-CALNAME:Sunrise-Sunset\r\n"; 41 | $out .= "X-WR-CALDESC:Display sunset and sunrise times as an all day event from a constantly updating vcalendar/ICS calendar in Google Calendar, your phone or elsewhere.\r\n"; 42 | $out .= "X-LOTUS-CHARSET:UTF-8\r\n"; 43 | 44 | //$out .= "X-PUBLISHED-TTL:".(30*24*60*60)."\r\n"; // check back in 1 month 45 | //$out .= "REFRESH-INTERVAL\r\n"; 46 | 47 | 48 | 49 | $now = date('Y-m-d', time()); 50 | for ($day=param('start', 0); $day<=param('end', 365); $day++) 51 | { 52 | $out .= "BEGIN:VEVENT\r\n"; 53 | $out .= "DTSTART;VALUE=DATE:".date('Ymd', strtotime($now.' +'.$day.' days'))."\r\n"; 54 | $out .= "DTEND;VALUE=DATE:".date('Ymd', strtotime($now.' +'.($day+1).' days'))."\r\n"; 55 | $out .= "DTSTAMP:".date('Ymd\THis\Z')."\r\n"; 56 | $out .= "UID:Permanent-Sunrise-".date('Ymd', strtotime($now.' +'.$day.' days'))."-$version\r\n"; 57 | $out .= "CLASS:PUBLIC\r\n"; 58 | $out .= "CREATED:$version\r\n"; 59 | $out .= "GEO:$latitude;$longitude\r\n"; //@see http://tools.ietf.org/html/rfc2445 60 | 61 | $sun_info = date_sun_info(strtotime($now.' +'.$day.' days'), $latitude, $longitude); 62 | 63 | $out .= 'DESCRIPTION:'; 64 | $out .= date('H:i', $sun_info['astronomical_twilight_begin']). ' Start of astronomical twilight\n'; 65 | $out .= date('H:i', $sun_info['nautical_twilight_begin']). ' Start of nautical twilight\n'; 66 | $out .= date('H:i', $sun_info['civil_twilight_begin']). ' Start of civil twilight\n'; 67 | $out .= date('H:i', $sun_info['sunrise']). ' Sunrise\n'; 68 | $out .= date('H:i', $sun_info['transit']). ' Noon\n'; 69 | $out .= date('H:i', $sun_info['sunset']). ' Sunset\n'; 70 | $out .= date('H:i', $sun_info['civil_twilight_end']). ' End of civil twilight\n'; 71 | $out .= date('H:i', $sun_info['nautical_twilight_end']). ' End of nautical twilight\n'; 72 | $out .= date('H:i', $sun_info['astronomical_twilight_end']). ' End of astronomical twilight\n'; 73 | $out .= '\n'; 74 | $out .= calc_day_length($sun_info['sunset'], $sun_info['sunrise']). ' Day length from Sunrise until Sunset\n'; 75 | $out .= calc_day_length($sun_info['civil_twilight_end'], $sun_info['civil_twilight_begin']). ' Day length for civil twilight\n'; 76 | $out .= calc_day_length($sun_info['nautical_twilight_end'], $sun_info['nautical_twilight_begin']). ' Day length for nautical twilight\n'; 77 | $out .= calc_day_length($sun_info['astronomical_twilight_end'], $sun_info['astronomical_twilight_begin']). ' Day length for astronomical twilight\n'; 78 | $out .= "\r\n"; 79 | 80 | $out .= "LAST-MODIFIED:$version\r\n"; 81 | $out .= "SEQUENCE:0\r\n"; 82 | $out .= "STATUS:CONFIRMED\r\n"; 83 | 84 | $out .= "SUMMARY:"; 85 | foreach (explode(',', param('title', 'sunrise,sunset,length')) as $title) 86 | { 87 | if (strpos($title, 'length') !== FALSE) 88 | { 89 | if ($title !== 'length') 90 | { 91 | $type = str_replace('length_', '', $title); 92 | $length = calc_day_length($sun_info[$type.'_twilight_end'], $sun_info[$type.'_twilight_begin']); 93 | } 94 | else 95 | { 96 | $length = calc_day_length($sun_info['sunset'], $sun_info['sunrise']); 97 | } 98 | 99 | $out .= param('label_'.$title, "").$length; 100 | } 101 | else 102 | { 103 | $out .= param('label_'.$title).date('H:i', $sun_info[$title]); 104 | } 105 | $out .= ' '; 106 | } 107 | $out .= "\r\n"; 108 | 109 | $out .= "TRANSP:OPAQUE\r\n"; 110 | $out .= "END:VEVENT\r\n"; 111 | 112 | } 113 | 114 | $out .= 'END:VCALENDAR'; 115 | 116 | 117 | header('Content-type: text/calendar; charset=utf-8'); 118 | header('Content-Disposition: inline; filename='.param('filename')); 119 | echo $out; 120 | 121 | 122 | /** 123 | * @param int $sunset 124 | * @param int $sunrise 125 | * @return string 126 | * @example 14h28 127 | */ 128 | function calc_day_length($sunset, $sunrise) 129 | { 130 | $day_length = $sunset - $sunrise; 131 | $day_length_h = intval($day_length/60/60); 132 | $day_length_min = round(($day_length - $day_length_h*60*60)/60, 0); 133 | $length = "{$day_length_h}h".str_pad($day_length_min, 2, '0', STR_PAD_LEFT); 134 | 135 | return $length; 136 | } 137 | 138 | 139 | /** 140 | * @param string $name 141 | * @param string $default 142 | * @return string 143 | * @desc GET an URL parameter 144 | */ 145 | function param($name, $default='') 146 | { 147 | // echo "&$name=$default"; // builds URL parameters with the default values 148 | 149 | if ( 150 | isset($_GET[$name]) 151 | && 152 | !empty($_GET[$name]) 153 | ) 154 | { 155 | $out = filter_input(INPUT_GET, $name, FILTER_SANITIZE_STRING); 156 | } 157 | else 158 | { 159 | $out = $default; 160 | } 161 | 162 | return $out; 163 | } --------------------------------------------------------------------------------